eslint 8.2.0 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/lib/linter/code-path-analysis/code-path-analyzer.js +6 -1
- package/lib/linter/code-path-analysis/code-path.js +1 -1
- package/lib/linter/linter.js +1 -1
- package/lib/rules/block-scoped-var.js +2 -0
- package/lib/rules/block-spacing.js +10 -3
- package/lib/rules/brace-style.js +6 -0
- package/lib/rules/class-methods-use-this.js +10 -1
- package/lib/rules/complexity.js +14 -6
- package/lib/rules/indent.js +21 -0
- package/lib/rules/keyword-spacing.js +1 -0
- package/lib/rules/lines-around-comment.js +54 -7
- package/lib/rules/max-depth.js +2 -0
- package/lib/rules/max-statements.js +10 -0
- package/lib/rules/no-eval.js +2 -0
- package/lib/rules/no-extra-semi.js +1 -1
- package/lib/rules/no-inner-declarations.js +26 -4
- package/lib/rules/no-invalid-this.js +4 -0
- package/lib/rules/no-lone-blocks.js +8 -2
- package/lib/rules/no-redeclare.js +2 -0
- package/lib/rules/no-unused-expressions.js +6 -0
- package/lib/rules/no-use-before-define.js +32 -9
- package/lib/rules/one-var.js +5 -1
- package/lib/rules/padded-blocks.js +8 -0
- package/lib/rules/padding-line-between-statements.js +2 -0
- package/lib/rules/prefer-const.js +1 -1
- package/lib/rules/require-atomic-updates.js +14 -2
- package/lib/rules/semi-style.js +8 -2
- package/lib/rules/semi.js +18 -9
- package/lib/rules/utils/ast-utils.js +15 -3
- package/lib/rules/vars-on-top.js +25 -12
- package/package.json +4 -4
package/README.md
CHANGED
@@ -206,6 +206,9 @@ This means:
|
|
206
206
|
These folks keep the project moving and are resources for help.
|
207
207
|
|
208
208
|
<!-- NOTE: This section is autogenerated. Do not manually edit.-->
|
209
|
+
|
210
|
+
|
211
|
+
|
209
212
|
<!--teamstart-->
|
210
213
|
|
211
214
|
### Technical Steering Committee (TSC)
|
@@ -288,6 +291,9 @@ Nitin Kumar
|
|
288
291
|
|
289
292
|
<!--teamend-->
|
290
293
|
|
294
|
+
|
295
|
+
|
296
|
+
|
291
297
|
## <a name="sponsors"></a>Sponsors
|
292
298
|
|
293
299
|
The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://opencollective.com/eslint) to get your logo on our README and website.
|
@@ -461,6 +461,10 @@ function processCodePathToEnter(analyzer, node) {
|
|
461
461
|
startCodePath("function");
|
462
462
|
break;
|
463
463
|
|
464
|
+
case "StaticBlock":
|
465
|
+
startCodePath("class-static-block");
|
466
|
+
break;
|
467
|
+
|
464
468
|
case "ChainExpression":
|
465
469
|
state.pushChainContext();
|
466
470
|
break;
|
@@ -706,7 +710,8 @@ function postprocess(analyzer, node) {
|
|
706
710
|
case "Program":
|
707
711
|
case "FunctionDeclaration":
|
708
712
|
case "FunctionExpression":
|
709
|
-
case "ArrowFunctionExpression":
|
713
|
+
case "ArrowFunctionExpression":
|
714
|
+
case "StaticBlock": {
|
710
715
|
endCodePath();
|
711
716
|
break;
|
712
717
|
}
|
@@ -40,7 +40,7 @@ class CodePath {
|
|
40
40
|
|
41
41
|
/**
|
42
42
|
* The reason that this code path was started. May be "program",
|
43
|
-
* "function",
|
43
|
+
* "function", "class-field-initializer", or "class-static-block".
|
44
44
|
* @type {string}
|
45
45
|
*/
|
46
46
|
this.origin = origin;
|
package/lib/linter/linter.js
CHANGED
@@ -626,7 +626,7 @@ function analyzeScope(ast, parserOptions, visitorKeys) {
|
|
626
626
|
ignoreEval: true,
|
627
627
|
nodejsScope: ecmaFeatures.globalReturn,
|
628
628
|
impliedStrict: ecmaFeatures.impliedStrict,
|
629
|
-
ecmaVersion,
|
629
|
+
ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
|
630
630
|
sourceType: parserOptions.sourceType || "script",
|
631
631
|
childVisitorKeys: visitorKeys || evk.KEYS,
|
632
632
|
fallback: Traverser.getKeys
|
@@ -112,6 +112,8 @@ module.exports = {
|
|
112
112
|
"SwitchStatement:exit": exitScope,
|
113
113
|
CatchClause: enterScope,
|
114
114
|
"CatchClause:exit": exitScope,
|
115
|
+
StaticBlock: enterScope,
|
116
|
+
"StaticBlock:exit": exitScope,
|
115
117
|
|
116
118
|
// Finds and reports references which are outside of valid scope.
|
117
119
|
VariableDeclaration: checkForVariables
|
@@ -40,7 +40,7 @@ module.exports = {
|
|
40
40
|
|
41
41
|
/**
|
42
42
|
* Gets the open brace token from a given node.
|
43
|
-
* @param {ASTNode} node A BlockStatement/SwitchStatement node to get.
|
43
|
+
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to get.
|
44
44
|
* @returns {Token} The token of the open brace.
|
45
45
|
*/
|
46
46
|
function getOpenBrace(node) {
|
@@ -50,6 +50,12 @@ module.exports = {
|
|
50
50
|
}
|
51
51
|
return sourceCode.getLastToken(node, 1);
|
52
52
|
}
|
53
|
+
|
54
|
+
if (node.type === "StaticBlock") {
|
55
|
+
return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
|
56
|
+
}
|
57
|
+
|
58
|
+
// "BlockStatement"
|
53
59
|
return sourceCode.getFirstToken(node);
|
54
60
|
}
|
55
61
|
|
@@ -72,8 +78,8 @@ module.exports = {
|
|
72
78
|
}
|
73
79
|
|
74
80
|
/**
|
75
|
-
*
|
76
|
-
* @param {ASTNode} node A BlockStatement/SwitchStatement node to
|
81
|
+
* Checks and reports invalid spacing style inside braces.
|
82
|
+
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to check.
|
77
83
|
* @returns {void}
|
78
84
|
*/
|
79
85
|
function checkSpacingInsideBraces(node) {
|
@@ -157,6 +163,7 @@ module.exports = {
|
|
157
163
|
|
158
164
|
return {
|
159
165
|
BlockStatement: checkSpacingInsideBraces,
|
166
|
+
StaticBlock: checkSpacingInsideBraces,
|
160
167
|
SwitchStatement: checkSpacingInsideBraces
|
161
168
|
};
|
162
169
|
}
|
package/lib/rules/brace-style.js
CHANGED
@@ -155,6 +155,12 @@ module.exports = {
|
|
155
155
|
validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
|
156
156
|
}
|
157
157
|
},
|
158
|
+
StaticBlock(node) {
|
159
|
+
validateCurlyPair(
|
160
|
+
sourceCode.getFirstToken(node, { skip: 1 }), // skip the `static` token
|
161
|
+
sourceCode.getLastToken(node)
|
162
|
+
);
|
163
|
+
},
|
158
164
|
ClassBody(node) {
|
159
165
|
validateCurlyPair(sourceCode.getFirstToken(node), sourceCode.getLastToken(node));
|
160
166
|
},
|
@@ -161,8 +161,17 @@ module.exports = {
|
|
161
161
|
/*
|
162
162
|
* Class field value are implicit functions.
|
163
163
|
*/
|
164
|
-
"PropertyDefinition:exit": popContext,
|
165
164
|
"PropertyDefinition > *.key:exit": pushContext,
|
165
|
+
"PropertyDefinition:exit": popContext,
|
166
|
+
|
167
|
+
/*
|
168
|
+
* Class static blocks are implicit functions. They aren't required to use `this`,
|
169
|
+
* but we have to push context so that it captures any use of `this` in the static block
|
170
|
+
* separately from enclosing contexts, because static blocks have their own `this` and it
|
171
|
+
* shouldn't count as used `this` in enclosing contexts.
|
172
|
+
*/
|
173
|
+
StaticBlock: pushContext,
|
174
|
+
"StaticBlock:exit": popContext,
|
166
175
|
|
167
176
|
ThisExpression: markThisUsed,
|
168
177
|
Super: markThisUsed,
|
package/lib/rules/complexity.js
CHANGED
@@ -124,20 +124,28 @@ module.exports = {
|
|
124
124
|
|
125
125
|
/*
|
126
126
|
* This rule only evaluates complexity of functions, so "program" is excluded.
|
127
|
-
* Class field initializers are implicit functions. Therefore,
|
128
|
-
* to the enclosing function's complexity, but their
|
127
|
+
* Class field initializers and class static blocks are implicit functions. Therefore,
|
128
|
+
* they shouldn't contribute to the enclosing function's complexity, but their
|
129
|
+
* own complexity should be evaluated.
|
129
130
|
*/
|
130
131
|
if (
|
131
132
|
codePath.origin !== "function" &&
|
132
|
-
codePath.origin !== "class-field-initializer"
|
133
|
+
codePath.origin !== "class-field-initializer" &&
|
134
|
+
codePath.origin !== "class-static-block"
|
133
135
|
) {
|
134
136
|
return;
|
135
137
|
}
|
136
138
|
|
137
139
|
if (complexity > THRESHOLD) {
|
138
|
-
|
139
|
-
|
140
|
-
|
140
|
+
let name;
|
141
|
+
|
142
|
+
if (codePath.origin === "class-field-initializer") {
|
143
|
+
name = "class field initializer";
|
144
|
+
} else if (codePath.origin === "class-static-block") {
|
145
|
+
name = "class static block";
|
146
|
+
} else {
|
147
|
+
name = astUtils.getFunctionNameWithKind(node);
|
148
|
+
}
|
141
149
|
|
142
150
|
context.report({
|
143
151
|
node,
|
package/lib/rules/indent.js
CHANGED
@@ -68,6 +68,7 @@ const KNOWN_NODES = new Set([
|
|
68
68
|
"ReturnStatement",
|
69
69
|
"SequenceExpression",
|
70
70
|
"SpreadElement",
|
71
|
+
"StaticBlock",
|
71
72
|
"Super",
|
72
73
|
"SwitchCase",
|
73
74
|
"SwitchStatement",
|
@@ -583,6 +584,16 @@ module.exports = {
|
|
583
584
|
},
|
584
585
|
additionalProperties: false
|
585
586
|
},
|
587
|
+
StaticBlock: {
|
588
|
+
type: "object",
|
589
|
+
properties: {
|
590
|
+
body: {
|
591
|
+
type: "integer",
|
592
|
+
minimum: 0
|
593
|
+
}
|
594
|
+
},
|
595
|
+
additionalProperties: false
|
596
|
+
},
|
586
597
|
CallExpression: {
|
587
598
|
type: "object",
|
588
599
|
properties: {
|
@@ -646,6 +657,9 @@ module.exports = {
|
|
646
657
|
parameters: DEFAULT_PARAMETER_INDENT,
|
647
658
|
body: DEFAULT_FUNCTION_BODY_INDENT
|
648
659
|
},
|
660
|
+
StaticBlock: {
|
661
|
+
body: DEFAULT_FUNCTION_BODY_INDENT
|
662
|
+
},
|
649
663
|
CallExpression: {
|
650
664
|
arguments: DEFAULT_PARAMETER_INDENT
|
651
665
|
},
|
@@ -1397,6 +1411,13 @@ module.exports = {
|
|
1397
1411
|
}
|
1398
1412
|
},
|
1399
1413
|
|
1414
|
+
StaticBlock(node) {
|
1415
|
+
const openingCurly = sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
|
1416
|
+
const closingCurly = sourceCode.getLastToken(node);
|
1417
|
+
|
1418
|
+
addElementListIndent(node.body, openingCurly, closingCurly, options.StaticBlock.body);
|
1419
|
+
},
|
1420
|
+
|
1400
1421
|
SwitchStatement(node) {
|
1401
1422
|
const openingCurly = sourceCode.getTokenAfter(node.discriminant, astUtils.isOpeningBraceToken);
|
1402
1423
|
const closingCurly = sourceCode.getLastToken(node);
|
@@ -590,6 +590,7 @@ module.exports = {
|
|
590
590
|
ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
|
591
591
|
MethodDefinition: checkSpacingForProperty,
|
592
592
|
PropertyDefinition: checkSpacingForProperty,
|
593
|
+
StaticBlock: checkSpacingAroundFirstToken,
|
593
594
|
Property: checkSpacingForProperty,
|
594
595
|
|
595
596
|
// To avoid conflicts with `space-infix-ops`, e.g. `a > this.b`
|
@@ -185,10 +185,39 @@ module.exports = {
|
|
185
185
|
/**
|
186
186
|
* Returns the parent node that contains the given token.
|
187
187
|
* @param {token} token The token to check.
|
188
|
-
* @returns {ASTNode} The parent node that contains the given token.
|
188
|
+
* @returns {ASTNode|null} The parent node that contains the given token.
|
189
189
|
*/
|
190
190
|
function getParentNodeOfToken(token) {
|
191
|
-
|
191
|
+
const node = sourceCode.getNodeByRangeIndex(token.range[0]);
|
192
|
+
|
193
|
+
/*
|
194
|
+
* For the purpose of this rule, the comment token is in a `StaticBlock` node only
|
195
|
+
* if it's inside the braces of that `StaticBlock` node.
|
196
|
+
*
|
197
|
+
* Example where this function returns `null`:
|
198
|
+
*
|
199
|
+
* static
|
200
|
+
* // comment
|
201
|
+
* {
|
202
|
+
* }
|
203
|
+
*
|
204
|
+
* Example where this function returns `StaticBlock` node:
|
205
|
+
*
|
206
|
+
* static
|
207
|
+
* {
|
208
|
+
* // comment
|
209
|
+
* }
|
210
|
+
*
|
211
|
+
*/
|
212
|
+
if (node && node.type === "StaticBlock") {
|
213
|
+
const openingBrace = sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
|
214
|
+
|
215
|
+
return token.range[0] >= openingBrace.range[0]
|
216
|
+
? node
|
217
|
+
: null;
|
218
|
+
}
|
219
|
+
|
220
|
+
return node;
|
192
221
|
}
|
193
222
|
|
194
223
|
/**
|
@@ -200,8 +229,15 @@ module.exports = {
|
|
200
229
|
function isCommentAtParentStart(token, nodeType) {
|
201
230
|
const parent = getParentNodeOfToken(token);
|
202
231
|
|
203
|
-
|
204
|
-
|
232
|
+
if (parent && isParentNodeType(parent, nodeType)) {
|
233
|
+
const parentStartNodeOrToken = parent.type === "StaticBlock"
|
234
|
+
? sourceCode.getFirstToken(parent, { skip: 1 }) // opening brace of the static block
|
235
|
+
: parent;
|
236
|
+
|
237
|
+
return token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1;
|
238
|
+
}
|
239
|
+
|
240
|
+
return false;
|
205
241
|
}
|
206
242
|
|
207
243
|
/**
|
@@ -213,7 +249,7 @@ module.exports = {
|
|
213
249
|
function isCommentAtParentEnd(token, nodeType) {
|
214
250
|
const parent = getParentNodeOfToken(token);
|
215
251
|
|
216
|
-
return parent && isParentNodeType(parent, nodeType) &&
|
252
|
+
return !!parent && isParentNodeType(parent, nodeType) &&
|
217
253
|
parent.loc.end.line - token.loc.end.line === 1;
|
218
254
|
}
|
219
255
|
|
@@ -223,7 +259,12 @@ module.exports = {
|
|
223
259
|
* @returns {boolean} True if the comment is at block start.
|
224
260
|
*/
|
225
261
|
function isCommentAtBlockStart(token) {
|
226
|
-
return
|
262
|
+
return (
|
263
|
+
isCommentAtParentStart(token, "ClassBody") ||
|
264
|
+
isCommentAtParentStart(token, "BlockStatement") ||
|
265
|
+
isCommentAtParentStart(token, "StaticBlock") ||
|
266
|
+
isCommentAtParentStart(token, "SwitchCase")
|
267
|
+
);
|
227
268
|
}
|
228
269
|
|
229
270
|
/**
|
@@ -232,7 +273,13 @@ module.exports = {
|
|
232
273
|
* @returns {boolean} True if the comment is at block end.
|
233
274
|
*/
|
234
275
|
function isCommentAtBlockEnd(token) {
|
235
|
-
return
|
276
|
+
return (
|
277
|
+
isCommentAtParentEnd(token, "ClassBody") ||
|
278
|
+
isCommentAtParentEnd(token, "BlockStatement") ||
|
279
|
+
isCommentAtParentEnd(token, "StaticBlock") ||
|
280
|
+
isCommentAtParentEnd(token, "SwitchCase") ||
|
281
|
+
isCommentAtParentEnd(token, "SwitchStatement")
|
282
|
+
);
|
236
283
|
}
|
237
284
|
|
238
285
|
/**
|
package/lib/rules/max-depth.js
CHANGED
@@ -118,6 +118,7 @@ module.exports = {
|
|
118
118
|
FunctionDeclaration: startFunction,
|
119
119
|
FunctionExpression: startFunction,
|
120
120
|
ArrowFunctionExpression: startFunction,
|
121
|
+
StaticBlock: startFunction,
|
121
122
|
|
122
123
|
IfStatement(node) {
|
123
124
|
if (node.parent.type !== "IfStatement") {
|
@@ -146,6 +147,7 @@ module.exports = {
|
|
146
147
|
"FunctionDeclaration:exit": endFunction,
|
147
148
|
"FunctionExpression:exit": endFunction,
|
148
149
|
"ArrowFunctionExpression:exit": endFunction,
|
150
|
+
"StaticBlock:exit": endFunction,
|
149
151
|
"Program:exit": endFunction
|
150
152
|
};
|
151
153
|
|
@@ -123,6 +123,14 @@ module.exports = {
|
|
123
123
|
function endFunction(node) {
|
124
124
|
const count = functionStack.pop();
|
125
125
|
|
126
|
+
/*
|
127
|
+
* This rule does not apply to class static blocks, but we have to track them so
|
128
|
+
* that stataments in them do not count as statements in the enclosing function.
|
129
|
+
*/
|
130
|
+
if (node.type === "StaticBlock") {
|
131
|
+
return;
|
132
|
+
}
|
133
|
+
|
126
134
|
if (ignoreTopLevelFunctions && functionStack.length === 0) {
|
127
135
|
topLevelFunctions.push({ node, count });
|
128
136
|
} else {
|
@@ -148,12 +156,14 @@ module.exports = {
|
|
148
156
|
FunctionDeclaration: startFunction,
|
149
157
|
FunctionExpression: startFunction,
|
150
158
|
ArrowFunctionExpression: startFunction,
|
159
|
+
StaticBlock: startFunction,
|
151
160
|
|
152
161
|
BlockStatement: countStatements,
|
153
162
|
|
154
163
|
"FunctionDeclaration:exit": endFunction,
|
155
164
|
"FunctionExpression:exit": endFunction,
|
156
165
|
"ArrowFunctionExpression:exit": endFunction,
|
166
|
+
"StaticBlock:exit": endFunction,
|
157
167
|
|
158
168
|
"Program:exit"() {
|
159
169
|
if (topLevelFunctions.length === 1) {
|
package/lib/rules/no-eval.js
CHANGED
@@ -248,6 +248,8 @@ module.exports = {
|
|
248
248
|
"ArrowFunctionExpression:exit": exitVarScope,
|
249
249
|
"PropertyDefinition > *.value": enterVarScope,
|
250
250
|
"PropertyDefinition > *.value:exit": exitVarScope,
|
251
|
+
StaticBlock: enterVarScope,
|
252
|
+
"StaticBlock:exit": exitVarScope,
|
251
253
|
|
252
254
|
ThisExpression(node) {
|
253
255
|
if (!isMember(node.parent, "eval")) {
|
@@ -116,7 +116,7 @@ module.exports = {
|
|
116
116
|
* @param {Node} node A MethodDefinition node of the start point.
|
117
117
|
* @returns {void}
|
118
118
|
*/
|
119
|
-
"MethodDefinition, PropertyDefinition"(node) {
|
119
|
+
"MethodDefinition, PropertyDefinition, StaticBlock"(node) {
|
120
120
|
checkForPartOfClassBody(sourceCode.getTokenAfter(node));
|
121
121
|
}
|
122
122
|
};
|
@@ -15,9 +15,33 @@ const astUtils = require("./utils/ast-utils");
|
|
15
15
|
// Rule Definition
|
16
16
|
//------------------------------------------------------------------------------
|
17
17
|
|
18
|
-
const validParent = new Set(["Program", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
|
18
|
+
const validParent = new Set(["Program", "StaticBlock", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
|
19
19
|
const validBlockStatementParent = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);
|
20
20
|
|
21
|
+
/**
|
22
|
+
* Finds the nearest enclosing context where this rule allows declarations and returns its description.
|
23
|
+
* @param {ASTNode} node Node to search from.
|
24
|
+
* @returns {string} Description. One of "program", "function body", "class static block body".
|
25
|
+
*/
|
26
|
+
function getAllowedBodyDescription(node) {
|
27
|
+
let { parent } = node;
|
28
|
+
|
29
|
+
while (parent) {
|
30
|
+
|
31
|
+
if (parent.type === "StaticBlock") {
|
32
|
+
return "class static block body";
|
33
|
+
}
|
34
|
+
|
35
|
+
if (astUtils.isFunction(parent)) {
|
36
|
+
return "function body";
|
37
|
+
}
|
38
|
+
|
39
|
+
({ parent } = parent);
|
40
|
+
}
|
41
|
+
|
42
|
+
return "program";
|
43
|
+
}
|
44
|
+
|
21
45
|
module.exports = {
|
22
46
|
meta: {
|
23
47
|
type: "problem",
|
@@ -59,14 +83,12 @@ module.exports = {
|
|
59
83
|
return;
|
60
84
|
}
|
61
85
|
|
62
|
-
const upperFunction = astUtils.getUpperFunction(parent);
|
63
|
-
|
64
86
|
context.report({
|
65
87
|
node,
|
66
88
|
messageId: "moveDeclToRoot",
|
67
89
|
data: {
|
68
90
|
type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
|
69
|
-
body: (
|
91
|
+
body: getAllowedBodyDescription(node)
|
70
92
|
}
|
71
93
|
});
|
72
94
|
}
|
@@ -132,6 +132,10 @@ module.exports = {
|
|
132
132
|
"PropertyDefinition > *.value": enterFunction,
|
133
133
|
"PropertyDefinition > *.value:exit": exitFunction,
|
134
134
|
|
135
|
+
// Class static blocks are implicit functions.
|
136
|
+
StaticBlock: enterFunction,
|
137
|
+
"StaticBlock:exit": exitFunction,
|
138
|
+
|
135
139
|
// Reports if `this` of the current context is invalid.
|
136
140
|
ThisExpression(node) {
|
137
141
|
const current = stack.getCurrent();
|
@@ -39,7 +39,9 @@ module.exports = {
|
|
39
39
|
* @returns {void}
|
40
40
|
*/
|
41
41
|
function report(node) {
|
42
|
-
const messageId = node.parent.type === "BlockStatement"
|
42
|
+
const messageId = node.parent.type === "BlockStatement" || node.parent.type === "StaticBlock"
|
43
|
+
? "redundantNestedBlock"
|
44
|
+
: "redundantBlock";
|
43
45
|
|
44
46
|
context.report({
|
45
47
|
node,
|
@@ -54,6 +56,7 @@ module.exports = {
|
|
54
56
|
*/
|
55
57
|
function isLoneBlock(node) {
|
56
58
|
return node.parent.type === "BlockStatement" ||
|
59
|
+
node.parent.type === "StaticBlock" ||
|
57
60
|
node.parent.type === "Program" ||
|
58
61
|
|
59
62
|
// Don't report blocks in switch cases if the block is the only statement of the case.
|
@@ -99,7 +102,10 @@ module.exports = {
|
|
99
102
|
loneBlocks.pop();
|
100
103
|
report(node);
|
101
104
|
} else if (
|
102
|
-
|
105
|
+
(
|
106
|
+
node.parent.type === "BlockStatement" ||
|
107
|
+
node.parent.type === "StaticBlock"
|
108
|
+
) &&
|
103
109
|
node.parent.body.length === 1
|
104
110
|
) {
|
105
111
|
report(node);
|
@@ -115,6 +115,12 @@ module.exports = {
|
|
115
115
|
const parent = ancestors[ancestors.length - 1],
|
116
116
|
grandparent = ancestors[ancestors.length - 2];
|
117
117
|
|
118
|
+
/**
|
119
|
+
* https://tc39.es/ecma262/#directive-prologue
|
120
|
+
*
|
121
|
+
* Only `FunctionBody`, `ScriptBody` and `ModuleBody` can have directive prologue.
|
122
|
+
* Class static blocks do not have directive prologue.
|
123
|
+
*/
|
118
124
|
return (parent.type === "Program" || parent.type === "BlockStatement" &&
|
119
125
|
(/Function/u.test(grandparent.type))) &&
|
120
126
|
directives(parent).indexOf(node) >= 0;
|
@@ -45,25 +45,37 @@ function isInRange(node, location) {
|
|
45
45
|
|
46
46
|
/**
|
47
47
|
* Checks whether or not a given location is inside of the range of a class static initializer.
|
48
|
+
* Static initializers are static blocks and initializers of static fields.
|
48
49
|
* @param {ASTNode} node `ClassBody` node to check static initializers.
|
49
50
|
* @param {number} location A location to check.
|
50
51
|
* @returns {boolean} `true` if the location is inside of a class static initializer.
|
51
52
|
*/
|
52
53
|
function isInClassStaticInitializerRange(node, location) {
|
53
54
|
return node.body.some(classMember => (
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
(
|
56
|
+
classMember.type === "StaticBlock" &&
|
57
|
+
isInRange(classMember, location)
|
58
|
+
) ||
|
59
|
+
(
|
60
|
+
classMember.type === "PropertyDefinition" &&
|
61
|
+
classMember.static &&
|
62
|
+
classMember.value &&
|
63
|
+
isInRange(classMember.value, location)
|
64
|
+
)
|
58
65
|
));
|
59
66
|
}
|
60
67
|
|
61
68
|
/**
|
62
|
-
* Checks whether a given scope is the scope of a
|
69
|
+
* Checks whether a given scope is the scope of a a class static initializer.
|
70
|
+
* Static initializers are static blocks and initializers of static fields.
|
63
71
|
* @param {eslint-scope.Scope} scope A scope to check.
|
64
72
|
* @returns {boolean} `true` if the scope is a class static initializer scope.
|
65
73
|
*/
|
66
74
|
function isClassStaticInitializerScope(scope) {
|
75
|
+
if (scope.type === "class-static-block") {
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
|
67
79
|
if (scope.type === "class-field-initializer") {
|
68
80
|
|
69
81
|
// `scope.block` is PropertyDefinition#value node
|
@@ -82,7 +94,8 @@ function isClassStaticInitializerScope(scope) {
|
|
82
94
|
* - top-level
|
83
95
|
* - functions
|
84
96
|
* - class field initializers (implicit functions)
|
85
|
-
*
|
97
|
+
* - class static blocks (implicit functions)
|
98
|
+
* Static class field initializers and class static blocks are automatically run during the class definition evaluation,
|
86
99
|
* and therefore we'll consider them as a part of the parent execution context.
|
87
100
|
* Example:
|
88
101
|
*
|
@@ -90,6 +103,7 @@ function isClassStaticInitializerScope(scope) {
|
|
90
103
|
*
|
91
104
|
* x; // returns `false`
|
92
105
|
* () => x; // returns `true`
|
106
|
+
*
|
93
107
|
* class C {
|
94
108
|
* field = x; // returns `true`
|
95
109
|
* static field = x; // returns `false`
|
@@ -97,6 +111,14 @@ function isClassStaticInitializerScope(scope) {
|
|
97
111
|
* method() {
|
98
112
|
* x; // returns `true`
|
99
113
|
* }
|
114
|
+
*
|
115
|
+
* static method() {
|
116
|
+
* x; // returns `true`
|
117
|
+
* }
|
118
|
+
*
|
119
|
+
* static {
|
120
|
+
* x; // returns `false`
|
121
|
+
* }
|
100
122
|
* }
|
101
123
|
* @param {eslint-scope.Reference} reference A reference to check.
|
102
124
|
* @returns {boolean} `true` if the reference is from a separate execution context.
|
@@ -127,8 +149,9 @@ function isFromSeparateExecutionContext(reference) {
|
|
127
149
|
* var {a = a} = obj
|
128
150
|
* for (var a in a) {}
|
129
151
|
* for (var a of a) {}
|
130
|
-
* var C = class { [C]; }
|
131
|
-
* var C = class { static foo = C; }
|
152
|
+
* var C = class { [C]; };
|
153
|
+
* var C = class { static foo = C; };
|
154
|
+
* var C = class { static { foo = C; } };
|
132
155
|
* class C extends C {}
|
133
156
|
* class C extends (class { static foo = C; }) {}
|
134
157
|
* class C { [C]; }
|
@@ -158,7 +181,7 @@ function isEvaluatedDuringInitialization(reference) {
|
|
158
181
|
|
159
182
|
/*
|
160
183
|
* Class binding is initialized before running static initializers.
|
161
|
-
* For example, `class C { static foo = C; }` is valid.
|
184
|
+
* For example, `class C { static foo = C; static { bar = C; } }` is valid.
|
162
185
|
*/
|
163
186
|
!isInClassStaticInitializerRange(classDefinition.body, location)
|
164
187
|
);
|
package/lib/rules/one-var.js
CHANGED
@@ -541,6 +541,8 @@ module.exports = {
|
|
541
541
|
FunctionDeclaration: startFunction,
|
542
542
|
FunctionExpression: startFunction,
|
543
543
|
ArrowFunctionExpression: startFunction,
|
544
|
+
StaticBlock: startFunction, // StaticBlock creates a new scope for `var` variables
|
545
|
+
|
544
546
|
BlockStatement: startBlock,
|
545
547
|
ForStatement: startBlock,
|
546
548
|
ForInStatement: startBlock,
|
@@ -552,10 +554,12 @@ module.exports = {
|
|
552
554
|
"ForInStatement:exit": endBlock,
|
553
555
|
"SwitchStatement:exit": endBlock,
|
554
556
|
"BlockStatement:exit": endBlock,
|
557
|
+
|
555
558
|
"Program:exit": endFunction,
|
556
559
|
"FunctionDeclaration:exit": endFunction,
|
557
560
|
"FunctionExpression:exit": endFunction,
|
558
|
-
"ArrowFunctionExpression:exit": endFunction
|
561
|
+
"ArrowFunctionExpression:exit": endFunction,
|
562
|
+
"StaticBlock:exit": endFunction
|
559
563
|
};
|
560
564
|
|
561
565
|
}
|
@@ -106,6 +106,12 @@ module.exports = {
|
|
106
106
|
if (node.type === "SwitchStatement") {
|
107
107
|
return sourceCode.getTokenBefore(node.cases[0]);
|
108
108
|
}
|
109
|
+
|
110
|
+
if (node.type === "StaticBlock") {
|
111
|
+
return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
|
112
|
+
}
|
113
|
+
|
114
|
+
// `BlockStatement` or `ClassBody`
|
109
115
|
return sourceCode.getFirstToken(node);
|
110
116
|
}
|
111
117
|
|
@@ -172,6 +178,7 @@ module.exports = {
|
|
172
178
|
function requirePaddingFor(node) {
|
173
179
|
switch (node.type) {
|
174
180
|
case "BlockStatement":
|
181
|
+
case "StaticBlock":
|
175
182
|
return options.blocks;
|
176
183
|
case "SwitchStatement":
|
177
184
|
return options.switches;
|
@@ -282,6 +289,7 @@ module.exports = {
|
|
282
289
|
}
|
283
290
|
checkPadding(node);
|
284
291
|
};
|
292
|
+
rule.StaticBlock = rule.BlockStatement;
|
285
293
|
}
|
286
294
|
|
287
295
|
if (Object.prototype.hasOwnProperty.call(options, "classes")) {
|
@@ -618,9 +618,11 @@ module.exports = {
|
|
618
618
|
Program: enterScope,
|
619
619
|
BlockStatement: enterScope,
|
620
620
|
SwitchStatement: enterScope,
|
621
|
+
StaticBlock: enterScope,
|
621
622
|
"Program:exit": exitScope,
|
622
623
|
"BlockStatement:exit": exitScope,
|
623
624
|
"SwitchStatement:exit": exitScope,
|
625
|
+
"StaticBlock:exit": exitScope,
|
624
626
|
|
625
627
|
":statement": verify,
|
626
628
|
|
@@ -17,7 +17,7 @@ const astUtils = require("./utils/ast-utils");
|
|
17
17
|
//------------------------------------------------------------------------------
|
18
18
|
|
19
19
|
const PATTERN_TYPE = /^(?:.+?Pattern|RestElement|SpreadProperty|ExperimentalRestProperty|Property)$/u;
|
20
|
-
const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/u;
|
20
|
+
const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|StaticBlock|SwitchCase)$/u;
|
21
21
|
const DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/u;
|
22
22
|
|
23
23
|
/**
|
@@ -176,7 +176,17 @@ module.exports = {
|
|
176
176
|
},
|
177
177
|
|
178
178
|
fixable: null,
|
179
|
-
|
179
|
+
|
180
|
+
schema: [{
|
181
|
+
type: "object",
|
182
|
+
properties: {
|
183
|
+
allowProperties: {
|
184
|
+
type: "boolean",
|
185
|
+
default: false
|
186
|
+
}
|
187
|
+
},
|
188
|
+
additionalProperties: false
|
189
|
+
}],
|
180
190
|
|
181
191
|
messages: {
|
182
192
|
nonAtomicUpdate: "Possible race condition: `{{value}}` might be reassigned based on an outdated value of `{{value}}`.",
|
@@ -185,6 +195,8 @@ module.exports = {
|
|
185
195
|
},
|
186
196
|
|
187
197
|
create(context) {
|
198
|
+
const allowProperties = !!context.options[0] && context.options[0].allowProperties;
|
199
|
+
|
188
200
|
const sourceCode = context.getSourceCode();
|
189
201
|
const assignmentReferences = new Map();
|
190
202
|
const segmentInfo = new SegmentInfo();
|
@@ -284,7 +296,7 @@ module.exports = {
|
|
284
296
|
value: variable.name
|
285
297
|
}
|
286
298
|
});
|
287
|
-
} else {
|
299
|
+
} else if (!allowProperties) {
|
288
300
|
context.report({
|
289
301
|
node: node.parent,
|
290
302
|
messageId: "nonAtomicObjectUpdate",
|
package/lib/rules/semi-style.js
CHANGED
@@ -25,7 +25,8 @@ const SELECTOR = [
|
|
25
25
|
|
26
26
|
/**
|
27
27
|
* Get the child node list of a given node.
|
28
|
-
* This returns `
|
28
|
+
* This returns `BlockStatement#body`, `StaticBlock#body`, `Program#body`,
|
29
|
+
* `ClassBody#body`, or `SwitchCase#consequent`.
|
29
30
|
* This is used to check whether a node is the first/last child.
|
30
31
|
* @param {Node} node A node to get child node list.
|
31
32
|
* @returns {Node[]|null} The child node list.
|
@@ -33,7 +34,12 @@ const SELECTOR = [
|
|
33
34
|
function getChildren(node) {
|
34
35
|
const t = node.type;
|
35
36
|
|
36
|
-
if (
|
37
|
+
if (
|
38
|
+
t === "BlockStatement" ||
|
39
|
+
t === "StaticBlock" ||
|
40
|
+
t === "Program" ||
|
41
|
+
t === "ClassBody"
|
42
|
+
) {
|
37
43
|
return node.body;
|
38
44
|
}
|
39
45
|
if (t === "SwitchCase") {
|
package/lib/rules/semi.js
CHANGED
@@ -306,22 +306,31 @@ module.exports = {
|
|
306
306
|
}
|
307
307
|
|
308
308
|
/**
|
309
|
-
* Checks a node to see if it's in a one-liner block
|
309
|
+
* Checks a node to see if it's the last item in a one-liner block.
|
310
|
+
* Block is any `BlockStatement` or `StaticBlock` node. Block is a one-liner if its
|
311
|
+
* braces (and consequently everything between them) are on the same line.
|
310
312
|
* @param {ASTNode} node The node to check.
|
311
|
-
* @returns {boolean} whether the node is in a one-liner block
|
313
|
+
* @returns {boolean} whether the node is the last item in a one-liner block.
|
312
314
|
*/
|
313
|
-
function
|
315
|
+
function isLastInOneLinerBlock(node) {
|
314
316
|
const parent = node.parent;
|
315
317
|
const nextToken = sourceCode.getTokenAfter(node);
|
316
318
|
|
317
319
|
if (!nextToken || nextToken.value !== "}") {
|
318
320
|
return false;
|
319
321
|
}
|
320
|
-
|
321
|
-
|
322
|
-
parent.
|
323
|
-
|
324
|
-
|
322
|
+
|
323
|
+
if (parent.type === "BlockStatement") {
|
324
|
+
return parent.loc.start.line === parent.loc.end.line;
|
325
|
+
}
|
326
|
+
|
327
|
+
if (parent.type === "StaticBlock") {
|
328
|
+
const openingBrace = sourceCode.getFirstToken(parent, { skip: 1 }); // skip the `static` token
|
329
|
+
|
330
|
+
return openingBrace.loc.start.line === parent.loc.end.line;
|
331
|
+
}
|
332
|
+
|
333
|
+
return false;
|
325
334
|
}
|
326
335
|
|
327
336
|
/**
|
@@ -343,7 +352,7 @@ module.exports = {
|
|
343
352
|
report(node);
|
344
353
|
}
|
345
354
|
} else {
|
346
|
-
const oneLinerBlock = (exceptOneLine &&
|
355
|
+
const oneLinerBlock = (exceptOneLine && isLastInOneLinerBlock(node));
|
347
356
|
|
348
357
|
if (isSemi && oneLinerBlock) {
|
349
358
|
report(node, true);
|
@@ -35,7 +35,7 @@ const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|g
|
|
35
35
|
const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
|
36
36
|
|
37
37
|
// A set of node types that can contain a list of statements
|
38
|
-
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "SwitchCase"]);
|
38
|
+
const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "StaticBlock", "SwitchCase"]);
|
39
39
|
|
40
40
|
const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
|
41
41
|
|
@@ -937,6 +937,8 @@ module.exports = {
|
|
937
937
|
*
|
938
938
|
* First, this checks the node:
|
939
939
|
*
|
940
|
+
* - The given node is not in `PropertyDefinition#value` position.
|
941
|
+
* - The given node is not `StaticBlock`.
|
940
942
|
* - The function name does not start with uppercase. It's a convention to capitalize the names
|
941
943
|
* of constructor functions. This check is not performed if `capIsConstructor` is set to `false`.
|
942
944
|
* - The function does not have a JSDoc comment that has a @this tag.
|
@@ -951,7 +953,8 @@ module.exports = {
|
|
951
953
|
* - The location is not on an ES2015 class.
|
952
954
|
* - Its `bind`/`call`/`apply` method is not called directly.
|
953
955
|
* - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
|
954
|
-
* @param {ASTNode} node A function node to check.
|
956
|
+
* @param {ASTNode} node A function node to check. It also can be an implicit function, like `StaticBlock`
|
957
|
+
* or any expression that is `PropertyDefinition#value` node.
|
955
958
|
* @param {SourceCode} sourceCode A SourceCode instance to get comments.
|
956
959
|
* @param {boolean} [capIsConstructor = true] `false` disables the assumption that functions which name starts
|
957
960
|
* with an uppercase or are assigned to a variable which name starts with an uppercase are constructors.
|
@@ -964,7 +967,12 @@ module.exports = {
|
|
964
967
|
* Therefore, A expression node at `PropertyDefinition#value` is a function.
|
965
968
|
* In this case, `this` is always not default binding.
|
966
969
|
*/
|
967
|
-
if (node
|
970
|
+
if (node.parent.type === "PropertyDefinition" && node.parent.value === node) {
|
971
|
+
return false;
|
972
|
+
}
|
973
|
+
|
974
|
+
// Class static blocks are implicit functions. In this case, `this` is always not default binding.
|
975
|
+
if (node.type === "StaticBlock") {
|
968
976
|
return false;
|
969
977
|
}
|
970
978
|
|
@@ -1825,6 +1833,10 @@ module.exports = {
|
|
1825
1833
|
return true;
|
1826
1834
|
}
|
1827
1835
|
|
1836
|
+
if (rightToken.type === "PrivateIdentifier") {
|
1837
|
+
return true;
|
1838
|
+
}
|
1839
|
+
|
1828
1840
|
return false;
|
1829
1841
|
},
|
1830
1842
|
|
package/lib/rules/vars-on-top.js
CHANGED
@@ -77,10 +77,12 @@ module.exports = {
|
|
77
77
|
const l = statements.length;
|
78
78
|
let i = 0;
|
79
79
|
|
80
|
-
//
|
81
|
-
|
82
|
-
|
83
|
-
|
80
|
+
// Skip over directives and imports. Static blocks don't have either.
|
81
|
+
if (node.parent.type !== "StaticBlock") {
|
82
|
+
for (; i < l; ++i) {
|
83
|
+
if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
|
84
|
+
break;
|
85
|
+
}
|
84
86
|
}
|
85
87
|
}
|
86
88
|
|
@@ -111,16 +113,27 @@ module.exports = {
|
|
111
113
|
/**
|
112
114
|
* Checks whether variable is on top at functional block scope level
|
113
115
|
* @param {ASTNode} node The node to check
|
114
|
-
* @param {ASTNode} parent Parent of the node
|
115
|
-
* @param {ASTNode} grandParent Parent of the node's parent
|
116
116
|
* @returns {void}
|
117
117
|
*/
|
118
|
-
function blockScopeVarCheck(node
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
118
|
+
function blockScopeVarCheck(node) {
|
119
|
+
const { parent } = node;
|
120
|
+
|
121
|
+
if (
|
122
|
+
parent.type === "BlockStatement" &&
|
123
|
+
/Function/u.test(parent.parent.type) &&
|
124
|
+
isVarOnTop(node, parent.body)
|
125
|
+
) {
|
126
|
+
return;
|
123
127
|
}
|
128
|
+
|
129
|
+
if (
|
130
|
+
parent.type === "StaticBlock" &&
|
131
|
+
isVarOnTop(node, parent.body)
|
132
|
+
) {
|
133
|
+
return;
|
134
|
+
}
|
135
|
+
|
136
|
+
context.report({ node, messageId: "top" });
|
124
137
|
}
|
125
138
|
|
126
139
|
//--------------------------------------------------------------------------
|
@@ -134,7 +147,7 @@ module.exports = {
|
|
134
147
|
} else if (node.parent.type === "Program") {
|
135
148
|
globalVarCheck(node, node.parent);
|
136
149
|
} else {
|
137
|
-
blockScopeVarCheck(node
|
150
|
+
blockScopeVarCheck(node);
|
138
151
|
}
|
139
152
|
}
|
140
153
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.3.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -56,10 +56,10 @@
|
|
56
56
|
"doctrine": "^3.0.0",
|
57
57
|
"enquirer": "^2.3.5",
|
58
58
|
"escape-string-regexp": "^4.0.0",
|
59
|
-
"eslint-scope": "^
|
59
|
+
"eslint-scope": "^7.1.0",
|
60
60
|
"eslint-utils": "^3.0.0",
|
61
|
-
"eslint-visitor-keys": "^3.
|
62
|
-
"espree": "^9.
|
61
|
+
"eslint-visitor-keys": "^3.1.0",
|
62
|
+
"espree": "^9.1.0",
|
63
63
|
"esquery": "^1.4.0",
|
64
64
|
"esutils": "^2.0.2",
|
65
65
|
"fast-deep-equal": "^3.1.3",
|