4

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()
}

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?

dr1zzled_d1ce
  • 41
  • 1
  • 4

0 Answers0