I want to enforce one-line if statements not having braces. For example:
// incorrect
if(foo) {
bar()
}
// correct
if(foo) bar()
But if I have else/else ifs, I still want to keep braces:
// incorrect
if(foo) bar()
else(baz) qux()
// correct
if(foo) {
bar()
} else(baz) {
qux()
}
EDIT: this only applies to if-statements. Other loops and such are exempt.
// correct:
for(foo) {
bar()
}
// incorrect:
while(foo) bar
I was able to create a plugin like this:
module.exports = {
meta: {
type: "layout",
fixable: "whitespace",
messages: {
noSingleLineIfsAsBlock: "Don't use braces with one line if statements",
useBlocksWithElseCases: "Use braces when there are else ifs and/or elses"
}
},
create(context) {
return {
IfStatement(node) {
if(node.alternate === null && node.parent.type !== "IfStatement") {
if(node.consequent.type === "BlockStatement" && node.consequent.body.length > 0) {
// assumes that blank lines are removed by other eslint rules, so at most three lines for a if block with one line inside
if(node.consequent.loc.end.line - node.consequent.loc.start.line + 1 <= 3) {
context.report({
node: node,
messageId: "noSingleLineIfsAsBlock",
fix(fixer) {
const sourceCode = context.getSourceCode();
const openingBrace = sourceCode.getFirstToken(node.consequent);
const closingBrace = sourceCode.getLastToken(node.consequent);
const firstValueToken = sourceCode.getFirstToken(node.consequent.body[0]);
const lastValueToken = sourceCode.getLastToken(node.consequent.body[0]);
return [
fixer.removeRange([openingBrace.range[0], firstValueToken.range[0]]),
fixer.removeRange([lastValueToken.range[1], closingBrace.range[1]])
];
}
})
}
}
} else if(node.alternate || node.parent.type === "IfStatement") {
if(node.consequent.type !== "BlockStatement") {
context.report({
node: node,
messageId: "useBlocksWithElseCases",
fix(fixer) {
// assumes that other eslint rules will fix brace styling
const sourceCode = context.getSourceCode();
const firstValueToken = sourceCode.getFirstToken(node.consequent);
const lastValueToken = sourceCode.getLastToken(node.consequent);
return [
fixer.insertTextBefore(firstValueToken, "{"),
fixer.insertTextAfter(lastValueToken, "}")
];
}
})
}
if(node.alternate && node.alternate.type !== "IfStatement" && node.alternate.type !== "BlockStatement") {
context.report({
node: node,
messageId: "useBlocksWithElseCases",
fix(fixer) {
// assumes that other eslint rules will fix brace styling
const sourceCode = context.getSourceCode();
const firstValueToken = sourceCode.getFirstToken(node.alternate);
const lastValueToken = sourceCode.getLastToken(node.alternate);
return [
fixer.insertTextBefore(firstValueToken, "{"),
fixer.insertTextAfter(lastValueToken, "}")
];
}
})
}
}
}
};
}
};
But I was wondering if there are already existing implementations I could use instead so I wouldn't have to store this in my project.
I browsed npm packages relating to eslint and searched for things like "eslint if statement formatting" but I couldn't find anything. I'm also pretty sure eslint doesn't have a built-in rule for this.
The most related issue I found was this, but it's asking how to avoid the style I'm trying to implement, and I'm not using prettier.
Are there any eslint plugins like this that can solve my problem?
if(foo) bar(); else qux();
, as there is only one statement per block in this case. However, OP wants to use & enforce braces if if-else is both present. See also example fromt he docs:if (foo) foo++; else if (bar) baz() else doSomething();
– Schaffel