9
9
// Requirements
10
10
//------------------------------------------------------------------------------
11
11
12
- const { getVariableByName, isArrowToken, isClosingBraceToken, isClosingParenToken } = require ( "./utils/ast-utils" ) ;
13
-
14
- //------------------------------------------------------------------------------
15
- // Helpers
16
- //------------------------------------------------------------------------------
17
-
18
- const BREAK_OR_CONTINUE = new Set ( [ "BreakStatement" , "ContinueStatement" ] ) ;
19
-
20
- // Declaration types that must contain a string Literal node at the end.
21
- const DECLARATIONS = new Set ( [ "ExportAllDeclaration" , "ExportNamedDeclaration" , "ImportDeclaration" ] ) ;
22
-
23
- const IDENTIFIER_OR_KEYWORD = new Set ( [ "Identifier" , "Keyword" ] ) ;
24
-
25
- // Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types.
26
- const NODE_TYPES_BY_KEYWORD = {
27
- __proto__ : null ,
28
- break : "BreakStatement" ,
29
- continue : "ContinueStatement" ,
30
- debugger : "DebuggerStatement" ,
31
- do : "DoWhileStatement" ,
32
- else : "IfStatement" ,
33
- return : "ReturnStatement" ,
34
- yield : "YieldExpression"
35
- } ;
36
-
37
- /*
38
- * Before an opening parenthesis, postfix `++` and `--` always trigger ASI;
39
- * the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement.
40
- */
41
- const PUNCTUATORS = new Set ( [ ":" , ";" , "{" , "=>" , "++" , "--" ] ) ;
42
-
43
- /*
44
- * Statements that can contain an `ExpressionStatement` after a closing parenthesis.
45
- * DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis.
46
- */
47
- const STATEMENTS = new Set ( [
48
- "DoWhileStatement" ,
49
- "ForInStatement" ,
50
- "ForOfStatement" ,
51
- "ForStatement" ,
52
- "IfStatement" ,
53
- "WhileStatement" ,
54
- "WithStatement"
55
- ] ) ;
56
-
57
- /**
58
- * Tests if a node appears at the beginning of an ancestor ExpressionStatement node.
59
- * @param {ASTNode } node The node to check.
60
- * @returns {boolean } Whether the node appears at the beginning of an ancestor ExpressionStatement node.
61
- */
62
- function isStartOfExpressionStatement ( node ) {
63
- const start = node . range [ 0 ] ;
64
- let ancestor = node ;
65
-
66
- while ( ( ancestor = ancestor . parent ) && ancestor . range [ 0 ] === start ) {
67
- if ( ancestor . type === "ExpressionStatement" ) {
68
- return true ;
69
- }
70
- }
71
- return false ;
72
- }
12
+ const {
13
+ getVariableByName,
14
+ isArrowToken,
15
+ isStartOfExpressionStatement,
16
+ needsPrecedingSemicolon
17
+ } = require ( "./utils/ast-utils" ) ;
73
18
74
19
//------------------------------------------------------------------------------
75
20
// Rule Definition
@@ -120,50 +65,6 @@ module.exports = {
120
65
return false ;
121
66
}
122
67
123
- /**
124
- * Determines whether a parenthesized object literal that replaces a specified node needs to be preceded by a semicolon.
125
- * @param {ASTNode } node The node to be replaced. This node should be at the start of an `ExpressionStatement` or at the start of the body of an `ArrowFunctionExpression`.
126
- * @returns {boolean } Whether a semicolon is required before the parenthesized object literal.
127
- */
128
- function needsSemicolon ( node ) {
129
- const prevToken = sourceCode . getTokenBefore ( node ) ;
130
-
131
- if ( ! prevToken || prevToken . type === "Punctuator" && PUNCTUATORS . has ( prevToken . value ) ) {
132
- return false ;
133
- }
134
-
135
- const prevNode = sourceCode . getNodeByRangeIndex ( prevToken . range [ 0 ] ) ;
136
-
137
- if ( isClosingParenToken ( prevToken ) ) {
138
- return ! STATEMENTS . has ( prevNode . type ) ;
139
- }
140
-
141
- if ( isClosingBraceToken ( prevToken ) ) {
142
- return (
143
- prevNode . type === "BlockStatement" && prevNode . parent . type === "FunctionExpression" ||
144
- prevNode . type === "ClassBody" && prevNode . parent . type === "ClassExpression" ||
145
- prevNode . type === "ObjectExpression"
146
- ) ;
147
- }
148
-
149
- if ( IDENTIFIER_OR_KEYWORD . has ( prevToken . type ) ) {
150
- if ( BREAK_OR_CONTINUE . has ( prevNode . parent . type ) ) {
151
- return false ;
152
- }
153
-
154
- const keyword = prevToken . value ;
155
- const nodeType = NODE_TYPES_BY_KEYWORD [ keyword ] ;
156
-
157
- return prevNode . type !== nodeType ;
158
- }
159
-
160
- if ( prevToken . type === "String" ) {
161
- return ! DECLARATIONS . has ( prevNode . parent . type ) ;
162
- }
163
-
164
- return true ;
165
- }
166
-
167
68
/**
168
69
* Reports on nodes where the `Object` constructor is called without arguments.
169
70
* @param {ASTNode } node The node to evaluate.
@@ -183,7 +84,7 @@ module.exports = {
183
84
184
85
if ( needsParentheses ( node ) ) {
185
86
replacement = "({})" ;
186
- if ( needsSemicolon ( node ) ) {
87
+ if ( needsPrecedingSemicolon ( sourceCode , node ) ) {
187
88
fixText = ";({})" ;
188
89
messageId = "useLiteralAfterSemicolon" ;
189
90
} else {
0 commit comments