2 * @fileoverview Validates spacing before and after semicolon
3 * @author Mathias Schreck
8 const astUtils
= require("./utils/ast-utils");
10 //------------------------------------------------------------------------------
12 //------------------------------------------------------------------------------
19 description
: "enforce consistent spacing before and after semicolons",
21 url
: "https://eslint.org/docs/rules/semi-spacing"
24 fixable
: "whitespace",
39 additionalProperties
: false
44 unexpectedWhitespaceBefore
: "Unexpected whitespace before semicolon.",
45 unexpectedWhitespaceAfter
: "Unexpected whitespace after semicolon.",
46 missingWhitespaceBefore
: "Missing whitespace before semicolon.",
47 missingWhitespaceAfter
: "Missing whitespace after semicolon."
53 const config
= context
.options
[0],
54 sourceCode
= context
.getSourceCode();
55 let requireSpaceBefore
= false,
56 requireSpaceAfter
= true;
58 if (typeof config
=== "object") {
59 requireSpaceBefore
= config
.before
;
60 requireSpaceAfter
= config
.after
;
64 * Checks if a given token has leading whitespace.
65 * @param {Object} token The token to check.
66 * @returns {boolean} True if the given token has leading space, false if not.
68 function hasLeadingSpace(token
) {
69 const tokenBefore
= sourceCode
.getTokenBefore(token
);
71 return tokenBefore
&& astUtils
.isTokenOnSameLine(tokenBefore
, token
) && sourceCode
.isSpaceBetweenTokens(tokenBefore
, token
);
75 * Checks if a given token has trailing whitespace.
76 * @param {Object} token The token to check.
77 * @returns {boolean} True if the given token has trailing space, false if not.
79 function hasTrailingSpace(token
) {
80 const tokenAfter
= sourceCode
.getTokenAfter(token
);
82 return tokenAfter
&& astUtils
.isTokenOnSameLine(token
, tokenAfter
) && sourceCode
.isSpaceBetweenTokens(token
, tokenAfter
);
86 * Checks if the given token is the last token in its line.
87 * @param {Token} token The token to check.
88 * @returns {boolean} Whether or not the token is the last in its line.
90 function isLastTokenInCurrentLine(token
) {
91 const tokenAfter
= sourceCode
.getTokenAfter(token
);
93 return !(tokenAfter
&& astUtils
.isTokenOnSameLine(token
, tokenAfter
));
97 * Checks if the given token is the first token in its line
98 * @param {Token} token The token to check.
99 * @returns {boolean} Whether or not the token is the first in its line.
101 function isFirstTokenInCurrentLine(token
) {
102 const tokenBefore
= sourceCode
.getTokenBefore(token
);
104 return !(tokenBefore
&& astUtils
.isTokenOnSameLine(token
, tokenBefore
));
108 * Checks if the next token of a given token is a closing parenthesis.
109 * @param {Token} token The token to check.
110 * @returns {boolean} Whether or not the next token of a given token is a closing parenthesis.
112 function isBeforeClosingParen(token
) {
113 const nextToken
= sourceCode
.getTokenAfter(token
);
115 return (nextToken
&& astUtils
.isClosingBraceToken(nextToken
) || astUtils
.isClosingParenToken(nextToken
));
119 * Report location example :
121 * for unexpected space `before`
126 * for unexpected space `after`
128 * var a = 'b'; c = 10;
131 * Reports if the given token has invalid spacing.
132 * @param {Token} token The semicolon token to check.
133 * @param {ASTNode} node The corresponding node of the token.
136 function checkSemicolonSpacing(token
, node
) {
137 if (astUtils
.isSemicolonToken(token
)) {
138 if (hasLeadingSpace(token
)) {
139 if (!requireSpaceBefore
) {
140 const tokenBefore
= sourceCode
.getTokenBefore(token
);
142 start
: tokenBefore
.loc
.end
,
149 messageId
: "unexpectedWhitespaceBefore",
152 return fixer
.removeRange([tokenBefore
.range
[1], token
.range
[0]]);
157 if (requireSpaceBefore
) {
158 const loc
= token
.loc
;
163 messageId
: "missingWhitespaceBefore",
165 return fixer
.insertTextBefore(token
, " ");
171 if (!isFirstTokenInCurrentLine(token
) && !isLastTokenInCurrentLine(token
) && !isBeforeClosingParen(token
)) {
172 if (hasTrailingSpace(token
)) {
173 if (!requireSpaceAfter
) {
174 const tokenAfter
= sourceCode
.getTokenAfter(token
);
176 start
: token
.loc
.end
,
177 end
: tokenAfter
.loc
.start
183 messageId
: "unexpectedWhitespaceAfter",
186 return fixer
.removeRange([token
.range
[1], tokenAfter
.range
[0]]);
191 if (requireSpaceAfter
) {
192 const loc
= token
.loc
;
197 messageId
: "missingWhitespaceAfter",
199 return fixer
.insertTextAfter(token
, " ");
209 * Checks the spacing of the semicolon with the assumption that the last token is the semicolon.
210 * @param {ASTNode} node The node to check.
213 function checkNode(node
) {
214 const token
= sourceCode
.getLastToken(node
);
216 checkSemicolonSpacing(token
, node
);
220 VariableDeclaration
: checkNode
,
221 ExpressionStatement
: checkNode
,
222 BreakStatement
: checkNode
,
223 ContinueStatement
: checkNode
,
224 DebuggerStatement
: checkNode
,
225 DoWhileStatement
: checkNode
,
226 ReturnStatement
: checkNode
,
227 ThrowStatement
: checkNode
,
228 ImportDeclaration
: checkNode
,
229 ExportNamedDeclaration
: checkNode
,
230 ExportAllDeclaration
: checkNode
,
231 ExportDefaultDeclaration
: checkNode
,
234 checkSemicolonSpacing(sourceCode
.getTokenAfter(node
.init
), node
);
238 checkSemicolonSpacing(sourceCode
.getTokenAfter(node
.test
), node
);
241 PropertyDefinition
: checkNode