You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							188 lines
						
					
					
						
							7.7 KiB
						
					
					
				
			
		
		
	
	
							188 lines
						
					
					
						
							7.7 KiB
						
					
					
				/** | 
						|
 * @fileoverview Rule to flag block statements that do not use the one true brace style | 
						|
 * @author Ian Christian Myers | 
						|
 */ | 
						|
 | 
						|
"use strict"; | 
						|
 | 
						|
const astUtils = require("./utils/ast-utils"); | 
						|
 | 
						|
//------------------------------------------------------------------------------ | 
						|
// Rule Definition | 
						|
//------------------------------------------------------------------------------ | 
						|
 | 
						|
module.exports = { | 
						|
    meta: { | 
						|
        type: "layout", | 
						|
 | 
						|
        docs: { | 
						|
            description: "enforce consistent brace style for blocks", | 
						|
            category: "Stylistic Issues", | 
						|
            recommended: false, | 
						|
            url: "https://eslint.org/docs/rules/brace-style" | 
						|
        }, | 
						|
 | 
						|
        schema: [ | 
						|
            { | 
						|
                enum: ["1tbs", "stroustrup", "allman"] | 
						|
            }, | 
						|
            { | 
						|
                type: "object", | 
						|
                properties: { | 
						|
                    allowSingleLine: { | 
						|
                        type: "boolean", | 
						|
                        default: false | 
						|
                    } | 
						|
                }, | 
						|
                additionalProperties: false | 
						|
            } | 
						|
        ], | 
						|
 | 
						|
        fixable: "whitespace", | 
						|
 | 
						|
        messages: { | 
						|
            nextLineOpen: "Opening curly brace does not appear on the same line as controlling statement.", | 
						|
            sameLineOpen: "Opening curly brace appears on the same line as controlling statement.", | 
						|
            blockSameLine: "Statement inside of curly braces should be on next line.", | 
						|
            nextLineClose: "Closing curly brace does not appear on the same line as the subsequent block.", | 
						|
            singleLineClose: "Closing curly brace should be on the same line as opening curly brace or on the line after the previous block.", | 
						|
            sameLineClose: "Closing curly brace appears on the same line as the subsequent block." | 
						|
        } | 
						|
    }, | 
						|
 | 
						|
    create(context) { | 
						|
        const style = context.options[0] || "1tbs", | 
						|
            params = context.options[1] || {}, | 
						|
            sourceCode = context.getSourceCode(); | 
						|
 | 
						|
        //-------------------------------------------------------------------------- | 
						|
        // Helpers | 
						|
        //-------------------------------------------------------------------------- | 
						|
 | 
						|
        /** | 
						|
         * Fixes a place where a newline unexpectedly appears | 
						|
         * @param {Token} firstToken The token before the unexpected newline | 
						|
         * @param {Token} secondToken The token after the unexpected newline | 
						|
         * @returns {Function} A fixer function to remove the newlines between the tokens | 
						|
         */ | 
						|
        function removeNewlineBetween(firstToken, secondToken) { | 
						|
            const textRange = [firstToken.range[1], secondToken.range[0]]; | 
						|
            const textBetween = sourceCode.text.slice(textRange[0], textRange[1]); | 
						|
 | 
						|
            // Don't do a fix if there is a comment between the tokens | 
						|
            if (textBetween.trim()) { | 
						|
                return null; | 
						|
            } | 
						|
            return fixer => fixer.replaceTextRange(textRange, " "); | 
						|
        } | 
						|
 | 
						|
        /** | 
						|
         * Validates a pair of curly brackets based on the user's config | 
						|
         * @param {Token} openingCurly The opening curly bracket | 
						|
         * @param {Token} closingCurly The closing curly bracket | 
						|
         * @returns {void} | 
						|
         */ | 
						|
        function validateCurlyPair(openingCurly, closingCurly) { | 
						|
            const tokenBeforeOpeningCurly = sourceCode.getTokenBefore(openingCurly); | 
						|
            const tokenAfterOpeningCurly = sourceCode.getTokenAfter(openingCurly); | 
						|
            const tokenBeforeClosingCurly = sourceCode.getTokenBefore(closingCurly); | 
						|
            const singleLineException = params.allowSingleLine && astUtils.isTokenOnSameLine(openingCurly, closingCurly); | 
						|
 | 
						|
            if (style !== "allman" && !astUtils.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurly)) { | 
						|
                context.report({ | 
						|
                    node: openingCurly, | 
						|
                    messageId: "nextLineOpen", | 
						|
                    fix: removeNewlineBetween(tokenBeforeOpeningCurly, openingCurly) | 
						|
                }); | 
						|
            } | 
						|
 | 
						|
            if (style === "allman" && astUtils.isTokenOnSameLine(tokenBeforeOpeningCurly, openingCurly) && !singleLineException) { | 
						|
                context.report({ | 
						|
                    node: openingCurly, | 
						|
                    messageId: "sameLineOpen", | 
						|
                    fix: fixer => fixer.insertTextBefore(openingCurly, "\n") | 
						|
                }); | 
						|
            } | 
						|
 | 
						|
            if (astUtils.isTokenOnSameLine(openingCurly, tokenAfterOpeningCurly) && tokenAfterOpeningCurly !== closingCurly && !singleLineException) { | 
						|
                context.report({ | 
						|
                    node: openingCurly, | 
						|
                    messageId: "blockSameLine", | 
						|
                    fix: fixer => fixer.insertTextAfter(openingCurly, "\n") | 
						|
                }); | 
						|
            } | 
						|
 | 
						|
            if (tokenBeforeClosingCurly !== openingCurly && !singleLineException && astUtils.isTokenOnSameLine(tokenBeforeClosingCurly, closingCurly)) { | 
						|
                context.report({ | 
						|
                    node: closingCurly, | 
						|
                    messageId: "singleLineClose", | 
						|
                    fix: fixer => fixer.insertTextBefore(closingCurly, "\n") | 
						|
                }); | 
						|
            } | 
						|
        } | 
						|
 | 
						|
        /** | 
						|
         * Validates the location of a token that appears before a keyword (e.g. a newline before `else`) | 
						|
         * @param {Token} curlyToken The closing curly token. This is assumed to precede a keyword token (such as `else` or `finally`). | 
						|
         * @returns {void} | 
						|
         */ | 
						|
        function validateCurlyBeforeKeyword(curlyToken) { | 
						|
            const keywordToken = sourceCode.getTokenAfter(curlyToken); | 
						|
 | 
						|
            if (style === "1tbs" && !astUtils.isTokenOnSameLine(curlyToken, keywordToken)) { | 
						|
                context.report({ | 
						|
                    node: curlyToken, | 
						|
                    messageId: "nextLineClose", | 
						|
                    fix: removeNewlineBetween(curlyToken, keywordToken) | 
						|
                }); | 
						|
            } | 
						|
 | 
						|
            if (style !== "1tbs" && astUtils.isTokenOnSameLine(curlyToken, keywordToken)) { | 
						|
                context.report({ | 
						|
                    node: curlyToken, | 
						|
                    messageId: "sameLineClose", | 
						|
                    fix: fixer => fixer.insertTextAfter(curlyToken, "\n") | 
						|
                }); | 
						|
            } | 
						|
        } | 
						|
 | 
						|
        //-------------------------------------------------------------------------- | 
						|
        // Public API | 
						|
        //-------------------------------------------------------------------------- | 
						|
 | 
						|
        return { | 
						|
            BlockStatement(node) { | 
						|
                if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) { | 
						|
                    validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node)); | 
						|
                } | 
						|
            }, | 
						|
            ClassBody(node) { | 
						|
                validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node)); | 
						|
            }, | 
						|
            SwitchStatement(node) { | 
						|
                const closingCurly = sourceCode.getLastToken(node); | 
						|
                const openingCurly = sourceCode.getTokenBefore(node.cases.length ? node.cases[0] : closingCurly); | 
						|
 | 
						|
                validateCurlyPair(openingCurly, closingCurly); | 
						|
            }, | 
						|
            IfStatement(node) { | 
						|
                if (node.consequent.type === "BlockStatement" && node.alternate) { | 
						|
 | 
						|
                    // Handle the keyword after the `if` block (before `else`) | 
						|
                    validateCurlyBeforeKeyword(sourceCode.getLastToken(node.consequent)); | 
						|
                } | 
						|
            }, | 
						|
            TryStatement(node) { | 
						|
 | 
						|
                // Handle the keyword after the `try` block (before `catch` or `finally`) | 
						|
                validateCurlyBeforeKeyword(sourceCode.getLastToken(node.block)); | 
						|
 | 
						|
                if (node.handler && node.finalizer) { | 
						|
 | 
						|
                    // Handle the keyword after the `catch` block (before `finally`) | 
						|
                    validateCurlyBeforeKeyword(sourceCode.getLastToken(node.handler.body)); | 
						|
                } | 
						|
            } | 
						|
        }; | 
						|
    } | 
						|
};
 | 
						|
 |