249 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			249 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @fileoverview Validates spacing before and after semicolon
 | |
|  * @author Mathias Schreck
 | |
|  * @deprecated in ESLint v8.53.0
 | |
|  */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| const astUtils = require("./utils/ast-utils");
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Rule Definition
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| /** @type {import('../shared/types').Rule} */
 | |
| module.exports = {
 | |
|     meta: {
 | |
|         deprecated: true,
 | |
|         replacedBy: [],
 | |
|         type: "layout",
 | |
| 
 | |
|         docs: {
 | |
|             description: "Enforce consistent spacing before and after semicolons",
 | |
|             recommended: false,
 | |
|             url: "https://eslint.org/docs/latest/rules/semi-spacing"
 | |
|         },
 | |
| 
 | |
|         fixable: "whitespace",
 | |
| 
 | |
|         schema: [
 | |
|             {
 | |
|                 type: "object",
 | |
|                 properties: {
 | |
|                     before: {
 | |
|                         type: "boolean",
 | |
|                         default: false
 | |
|                     },
 | |
|                     after: {
 | |
|                         type: "boolean",
 | |
|                         default: true
 | |
|                     }
 | |
|                 },
 | |
|                 additionalProperties: false
 | |
|             }
 | |
|         ],
 | |
| 
 | |
|         messages: {
 | |
|             unexpectedWhitespaceBefore: "Unexpected whitespace before semicolon.",
 | |
|             unexpectedWhitespaceAfter: "Unexpected whitespace after semicolon.",
 | |
|             missingWhitespaceBefore: "Missing whitespace before semicolon.",
 | |
|             missingWhitespaceAfter: "Missing whitespace after semicolon."
 | |
|         }
 | |
|     },
 | |
| 
 | |
|     create(context) {
 | |
| 
 | |
|         const config = context.options[0],
 | |
|             sourceCode = context.sourceCode;
 | |
|         let requireSpaceBefore = false,
 | |
|             requireSpaceAfter = true;
 | |
| 
 | |
|         if (typeof config === "object") {
 | |
|             requireSpaceBefore = config.before;
 | |
|             requireSpaceAfter = config.after;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks if a given token has leading whitespace.
 | |
|          * @param {Object} token The token to check.
 | |
|          * @returns {boolean} True if the given token has leading space, false if not.
 | |
|          */
 | |
|         function hasLeadingSpace(token) {
 | |
|             const tokenBefore = sourceCode.getTokenBefore(token);
 | |
| 
 | |
|             return tokenBefore && astUtils.isTokenOnSameLine(tokenBefore, token) && sourceCode.isSpaceBetweenTokens(tokenBefore, token);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks if a given token has trailing whitespace.
 | |
|          * @param {Object} token The token to check.
 | |
|          * @returns {boolean} True if the given token has trailing space, false if not.
 | |
|          */
 | |
|         function hasTrailingSpace(token) {
 | |
|             const tokenAfter = sourceCode.getTokenAfter(token);
 | |
| 
 | |
|             return tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter) && sourceCode.isSpaceBetweenTokens(token, tokenAfter);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks if the given token is the last token in its line.
 | |
|          * @param {Token} token The token to check.
 | |
|          * @returns {boolean} Whether or not the token is the last in its line.
 | |
|          */
 | |
|         function isLastTokenInCurrentLine(token) {
 | |
|             const tokenAfter = sourceCode.getTokenAfter(token);
 | |
| 
 | |
|             return !(tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter));
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks if the given token is the first token in its line
 | |
|          * @param {Token} token The token to check.
 | |
|          * @returns {boolean} Whether or not the token is the first in its line.
 | |
|          */
 | |
|         function isFirstTokenInCurrentLine(token) {
 | |
|             const tokenBefore = sourceCode.getTokenBefore(token);
 | |
| 
 | |
|             return !(tokenBefore && astUtils.isTokenOnSameLine(token, tokenBefore));
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks if the next token of a given token is a closing parenthesis.
 | |
|          * @param {Token} token The token to check.
 | |
|          * @returns {boolean} Whether or not the next token of a given token is a closing parenthesis.
 | |
|          */
 | |
|         function isBeforeClosingParen(token) {
 | |
|             const nextToken = sourceCode.getTokenAfter(token);
 | |
| 
 | |
|             return (nextToken && astUtils.isClosingBraceToken(nextToken) || astUtils.isClosingParenToken(nextToken));
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Report location example :
 | |
|          *
 | |
|          * for unexpected space `before`
 | |
|          *
 | |
|          * var a = 'b'   ;
 | |
|          *            ^^^
 | |
|          *
 | |
|          * for unexpected space `after`
 | |
|          *
 | |
|          * var a = 'b';  c = 10;
 | |
|          *             ^^
 | |
|          *
 | |
|          * Reports if the given token has invalid spacing.
 | |
|          * @param {Token} token The semicolon token to check.
 | |
|          * @param {ASTNode} node The corresponding node of the token.
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function checkSemicolonSpacing(token, node) {
 | |
|             if (astUtils.isSemicolonToken(token)) {
 | |
|                 if (hasLeadingSpace(token)) {
 | |
|                     if (!requireSpaceBefore) {
 | |
|                         const tokenBefore = sourceCode.getTokenBefore(token);
 | |
|                         const loc = {
 | |
|                             start: tokenBefore.loc.end,
 | |
|                             end: token.loc.start
 | |
|                         };
 | |
| 
 | |
|                         context.report({
 | |
|                             node,
 | |
|                             loc,
 | |
|                             messageId: "unexpectedWhitespaceBefore",
 | |
|                             fix(fixer) {
 | |
| 
 | |
|                                 return fixer.removeRange([tokenBefore.range[1], token.range[0]]);
 | |
|                             }
 | |
|                         });
 | |
|                     }
 | |
|                 } else {
 | |
|                     if (requireSpaceBefore) {
 | |
|                         const loc = token.loc;
 | |
| 
 | |
|                         context.report({
 | |
|                             node,
 | |
|                             loc,
 | |
|                             messageId: "missingWhitespaceBefore",
 | |
|                             fix(fixer) {
 | |
|                                 return fixer.insertTextBefore(token, " ");
 | |
|                             }
 | |
|                         });
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (!isFirstTokenInCurrentLine(token) && !isLastTokenInCurrentLine(token) && !isBeforeClosingParen(token)) {
 | |
|                     if (hasTrailingSpace(token)) {
 | |
|                         if (!requireSpaceAfter) {
 | |
|                             const tokenAfter = sourceCode.getTokenAfter(token);
 | |
|                             const loc = {
 | |
|                                 start: token.loc.end,
 | |
|                                 end: tokenAfter.loc.start
 | |
|                             };
 | |
| 
 | |
|                             context.report({
 | |
|                                 node,
 | |
|                                 loc,
 | |
|                                 messageId: "unexpectedWhitespaceAfter",
 | |
|                                 fix(fixer) {
 | |
| 
 | |
|                                     return fixer.removeRange([token.range[1], tokenAfter.range[0]]);
 | |
|                                 }
 | |
|                             });
 | |
|                         }
 | |
|                     } else {
 | |
|                         if (requireSpaceAfter) {
 | |
|                             const loc = token.loc;
 | |
| 
 | |
|                             context.report({
 | |
|                                 node,
 | |
|                                 loc,
 | |
|                                 messageId: "missingWhitespaceAfter",
 | |
|                                 fix(fixer) {
 | |
|                                     return fixer.insertTextAfter(token, " ");
 | |
|                                 }
 | |
|                             });
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks the spacing of the semicolon with the assumption that the last token is the semicolon.
 | |
|          * @param {ASTNode} node The node to check.
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function checkNode(node) {
 | |
|             const token = sourceCode.getLastToken(node);
 | |
| 
 | |
|             checkSemicolonSpacing(token, node);
 | |
|         }
 | |
| 
 | |
|         return {
 | |
|             VariableDeclaration: checkNode,
 | |
|             ExpressionStatement: checkNode,
 | |
|             BreakStatement: checkNode,
 | |
|             ContinueStatement: checkNode,
 | |
|             DebuggerStatement: checkNode,
 | |
|             DoWhileStatement: checkNode,
 | |
|             ReturnStatement: checkNode,
 | |
|             ThrowStatement: checkNode,
 | |
|             ImportDeclaration: checkNode,
 | |
|             ExportNamedDeclaration: checkNode,
 | |
|             ExportAllDeclaration: checkNode,
 | |
|             ExportDefaultDeclaration: checkNode,
 | |
|             ForStatement(node) {
 | |
|                 if (node.init) {
 | |
|                     checkSemicolonSpacing(sourceCode.getTokenAfter(node.init), node);
 | |
|                 }
 | |
| 
 | |
|                 if (node.test) {
 | |
|                     checkSemicolonSpacing(sourceCode.getTokenAfter(node.test), node);
 | |
|                 }
 | |
|             },
 | |
|             PropertyDefinition: checkNode
 | |
|         };
 | |
|     }
 | |
| };
 |