eslint 9.27.0 → 9.29.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 +1 -1
- package/conf/ecma-version.js +1 -1
- package/conf/globals.js +10 -0
- package/lib/cli.js +20 -23
- package/lib/config/config-loader.js +32 -21
- package/lib/config/config.js +34 -11
- package/lib/eslint/eslint.js +18 -21
- package/lib/languages/js/source-code/source-code.js +104 -27
- package/lib/linter/apply-disable-directives.js +2 -4
- package/lib/linter/code-path-analysis/code-path-analyzer.js +8 -9
- package/lib/linter/linter.js +30 -61
- package/lib/linter/source-code-traverser.js +327 -0
- package/lib/linter/source-code-visitor.js +81 -0
- package/lib/options.js +7 -0
- package/lib/rules/class-methods-use-this.js +7 -0
- package/lib/rules/func-style.js +57 -7
- package/lib/rules/no-implicit-globals.js +31 -15
- package/lib/rules/no-magic-numbers.js +98 -5
- package/lib/rules/no-promise-executor-return.js +4 -35
- package/lib/rules/no-restricted-globals.js +35 -2
- package/lib/rules/no-restricted-properties.js +24 -10
- package/lib/rules/no-setter-return.js +13 -48
- package/lib/rules/no-shadow.js +262 -6
- package/lib/rules/no-unassigned-vars.js +14 -6
- package/lib/rules/no-use-before-define.js +99 -1
- package/lib/rules/no-var.js +14 -2
- package/lib/rules/prefer-arrow-callback.js +9 -0
- package/lib/rules/prefer-regex-literals.js +1 -18
- package/lib/services/suppressions-service.js +8 -0
- package/lib/services/warning-service.js +85 -0
- package/lib/shared/naming.js +109 -0
- package/lib/shared/relative-module-resolver.js +28 -0
- package/lib/types/index.d.ts +18 -7
- package/lib/types/rules.d.ts +52 -2
- package/package.json +12 -10
- package/lib/linter/node-event-generator.js +0 -256
- package/lib/linter/safe-emitter.js +0 -52
@@ -10,33 +10,16 @@
|
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
12
|
const astUtils = require("./utils/ast-utils");
|
13
|
-
const { findVariable } = require("@eslint-community/eslint-utils");
|
14
13
|
|
15
14
|
//------------------------------------------------------------------------------
|
16
15
|
// Helpers
|
17
16
|
//------------------------------------------------------------------------------
|
18
17
|
|
19
|
-
/**
|
20
|
-
* Determines whether the given identifier node is a reference to a global variable.
|
21
|
-
* @param {ASTNode} node `Identifier` node to check.
|
22
|
-
* @param {Scope} scope Scope to which the node belongs.
|
23
|
-
* @returns {boolean} True if the identifier is a reference to a global variable.
|
24
|
-
*/
|
25
|
-
function isGlobalReference(node, scope) {
|
26
|
-
const variable = findVariable(scope, node);
|
27
|
-
|
28
|
-
return (
|
29
|
-
variable !== null &&
|
30
|
-
variable.scope.type === "global" &&
|
31
|
-
variable.defs.length === 0
|
32
|
-
);
|
33
|
-
}
|
34
|
-
|
35
18
|
/**
|
36
19
|
* Determines whether the given node is an argument of the specified global method call, at the given `index` position.
|
37
20
|
* E.g., for given `index === 1`, this function checks for `objectName.methodName(foo, node)`, where objectName is a global variable.
|
38
21
|
* @param {ASTNode} node The node to check.
|
39
|
-
* @param {
|
22
|
+
* @param {SourceCode} sourceCode Source code to which the node belongs.
|
40
23
|
* @param {string} objectName Name of the global object.
|
41
24
|
* @param {string} methodName Name of the method.
|
42
25
|
* @param {number} index The given position.
|
@@ -44,7 +27,7 @@ function isGlobalReference(node, scope) {
|
|
44
27
|
*/
|
45
28
|
function isArgumentOfGlobalMethodCall(
|
46
29
|
node,
|
47
|
-
|
30
|
+
sourceCode,
|
48
31
|
objectName,
|
49
32
|
methodName,
|
50
33
|
index,
|
@@ -59,9 +42,8 @@ function isArgumentOfGlobalMethodCall(
|
|
59
42
|
objectName,
|
60
43
|
methodName,
|
61
44
|
) &&
|
62
|
-
isGlobalReference(
|
45
|
+
sourceCode.isGlobalReference(
|
63
46
|
astUtils.skipChainExpression(callNode.callee).object,
|
64
|
-
scope,
|
65
47
|
)
|
66
48
|
);
|
67
49
|
}
|
@@ -69,21 +51,21 @@ function isArgumentOfGlobalMethodCall(
|
|
69
51
|
/**
|
70
52
|
* Determines whether the given node is used as a property descriptor.
|
71
53
|
* @param {ASTNode} node The node to check.
|
72
|
-
* @param {
|
54
|
+
* @param {SourceCode} sourceCode Source code to which the node belongs.
|
73
55
|
* @returns {boolean} `true` if the node is a property descriptor.
|
74
56
|
*/
|
75
|
-
function isPropertyDescriptor(node,
|
57
|
+
function isPropertyDescriptor(node, sourceCode) {
|
76
58
|
if (
|
77
59
|
isArgumentOfGlobalMethodCall(
|
78
60
|
node,
|
79
|
-
|
61
|
+
sourceCode,
|
80
62
|
"Object",
|
81
63
|
"defineProperty",
|
82
64
|
2,
|
83
65
|
) ||
|
84
66
|
isArgumentOfGlobalMethodCall(
|
85
67
|
node,
|
86
|
-
|
68
|
+
sourceCode,
|
87
69
|
"Reflect",
|
88
70
|
"defineProperty",
|
89
71
|
2,
|
@@ -101,14 +83,14 @@ function isPropertyDescriptor(node, scope) {
|
|
101
83
|
grandparent.type === "ObjectExpression" &&
|
102
84
|
(isArgumentOfGlobalMethodCall(
|
103
85
|
grandparent,
|
104
|
-
|
86
|
+
sourceCode,
|
105
87
|
"Object",
|
106
88
|
"create",
|
107
89
|
1,
|
108
90
|
) ||
|
109
91
|
isArgumentOfGlobalMethodCall(
|
110
92
|
grandparent,
|
111
|
-
|
93
|
+
sourceCode,
|
112
94
|
"Object",
|
113
95
|
"defineProperties",
|
114
96
|
1,
|
@@ -124,10 +106,10 @@ function isPropertyDescriptor(node, scope) {
|
|
124
106
|
/**
|
125
107
|
* Determines whether the given function node is used as a setter function.
|
126
108
|
* @param {ASTNode} node The node to check.
|
127
|
-
* @param {
|
109
|
+
* @param {SourceCode} sourceCode Source code to which the node belongs.
|
128
110
|
* @returns {boolean} `true` if the node is a setter.
|
129
111
|
*/
|
130
|
-
function isSetter(node,
|
112
|
+
function isSetter(node, sourceCode) {
|
131
113
|
const parent = node.parent;
|
132
114
|
|
133
115
|
if (
|
@@ -144,7 +126,7 @@ function isSetter(node, scope) {
|
|
144
126
|
parent.value === node &&
|
145
127
|
astUtils.getStaticPropertyName(parent) === "set" &&
|
146
128
|
parent.parent.type === "ObjectExpression" &&
|
147
|
-
isPropertyDescriptor(parent.parent,
|
129
|
+
isPropertyDescriptor(parent.parent, sourceCode)
|
148
130
|
) {
|
149
131
|
// Setter in a property descriptor
|
150
132
|
return true;
|
@@ -153,21 +135,6 @@ function isSetter(node, scope) {
|
|
153
135
|
return false;
|
154
136
|
}
|
155
137
|
|
156
|
-
/**
|
157
|
-
* Finds function's outer scope.
|
158
|
-
* @param {Scope} scope Function's own scope.
|
159
|
-
* @returns {Scope} Function's outer scope.
|
160
|
-
*/
|
161
|
-
function getOuterScope(scope) {
|
162
|
-
const upper = scope.upper;
|
163
|
-
|
164
|
-
if (upper.type === "function-expression-name") {
|
165
|
-
return upper.upper;
|
166
|
-
}
|
167
|
-
|
168
|
-
return upper;
|
169
|
-
}
|
170
|
-
|
171
138
|
//------------------------------------------------------------------------------
|
172
139
|
// Rule Definition
|
173
140
|
//------------------------------------------------------------------------------
|
@@ -200,11 +167,9 @@ module.exports = {
|
|
200
167
|
* @returns {void}
|
201
168
|
*/
|
202
169
|
function enterFunction(node) {
|
203
|
-
const outerScope = getOuterScope(sourceCode.getScope(node));
|
204
|
-
|
205
170
|
funcInfo = {
|
206
171
|
upper: funcInfo,
|
207
|
-
isSetter: isSetter(node,
|
172
|
+
isSetter: isSetter(node, sourceCode),
|
208
173
|
};
|
209
174
|
}
|
210
175
|
|
package/lib/rules/no-shadow.js
CHANGED
@@ -24,6 +24,23 @@ const FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/u;
|
|
24
24
|
const SENTINEL_TYPE =
|
25
25
|
/^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/u;
|
26
26
|
|
27
|
+
// TS-specific node types
|
28
|
+
const TYPES_HOISTED_NODES = new Set([
|
29
|
+
"TSInterfaceDeclaration",
|
30
|
+
"TSTypeAliasDeclaration",
|
31
|
+
]);
|
32
|
+
|
33
|
+
// TS-specific function variable def types
|
34
|
+
const ALLOWED_FUNCTION_VARIABLE_DEF_TYPES = new Set([
|
35
|
+
"TSCallSignatureDeclaration",
|
36
|
+
"TSFunctionType",
|
37
|
+
"TSMethodSignature",
|
38
|
+
"TSEmptyBodyFunctionExpression",
|
39
|
+
"TSDeclareFunction",
|
40
|
+
"TSConstructSignatureDeclaration",
|
41
|
+
"TSConstructorType",
|
42
|
+
]);
|
43
|
+
|
27
44
|
//------------------------------------------------------------------------------
|
28
45
|
// Rule Definition
|
29
46
|
//------------------------------------------------------------------------------
|
@@ -32,6 +49,8 @@ const SENTINEL_TYPE =
|
|
32
49
|
module.exports = {
|
33
50
|
meta: {
|
34
51
|
type: "suggestion",
|
52
|
+
dialects: ["typescript", "javascript"],
|
53
|
+
language: "javascript",
|
35
54
|
|
36
55
|
defaultOptions: [
|
37
56
|
{
|
@@ -39,6 +58,8 @@ module.exports = {
|
|
39
58
|
builtinGlobals: false,
|
40
59
|
hoist: "functions",
|
41
60
|
ignoreOnInitialization: false,
|
61
|
+
ignoreTypeValueShadow: true,
|
62
|
+
ignoreFunctionTypeParameterNameValueShadow: true,
|
42
63
|
},
|
43
64
|
],
|
44
65
|
|
@@ -54,7 +75,15 @@ module.exports = {
|
|
54
75
|
type: "object",
|
55
76
|
properties: {
|
56
77
|
builtinGlobals: { type: "boolean" },
|
57
|
-
hoist: {
|
78
|
+
hoist: {
|
79
|
+
enum: [
|
80
|
+
"all",
|
81
|
+
"functions",
|
82
|
+
"never",
|
83
|
+
"types",
|
84
|
+
"functions-and-types",
|
85
|
+
],
|
86
|
+
},
|
58
87
|
allow: {
|
59
88
|
type: "array",
|
60
89
|
items: {
|
@@ -62,6 +91,10 @@ module.exports = {
|
|
62
91
|
},
|
63
92
|
},
|
64
93
|
ignoreOnInitialization: { type: "boolean" },
|
94
|
+
ignoreTypeValueShadow: { type: "boolean" },
|
95
|
+
ignoreFunctionTypeParameterNameValueShadow: {
|
96
|
+
type: "boolean",
|
97
|
+
},
|
65
98
|
},
|
66
99
|
additionalProperties: false,
|
67
100
|
},
|
@@ -75,10 +108,112 @@ module.exports = {
|
|
75
108
|
},
|
76
109
|
|
77
110
|
create(context) {
|
78
|
-
const [
|
79
|
-
|
111
|
+
const [
|
112
|
+
{
|
113
|
+
builtinGlobals,
|
114
|
+
hoist,
|
115
|
+
allow,
|
116
|
+
ignoreOnInitialization,
|
117
|
+
ignoreTypeValueShadow,
|
118
|
+
ignoreFunctionTypeParameterNameValueShadow,
|
119
|
+
},
|
120
|
+
] = context.options;
|
80
121
|
const sourceCode = context.sourceCode;
|
81
122
|
|
123
|
+
/**
|
124
|
+
* Check if a scope is a TypeScript module augmenting the global namespace.
|
125
|
+
* @param {Scope} scope The scope to check
|
126
|
+
* @returns {boolean} Whether the scope is a global augmentation
|
127
|
+
*/
|
128
|
+
function isGlobalAugmentation(scope) {
|
129
|
+
return (
|
130
|
+
scope.block.kind === "global" ||
|
131
|
+
(!!scope.upper && isGlobalAugmentation(scope.upper))
|
132
|
+
);
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Check if variable is a `this` parameter.
|
137
|
+
* @param {Object} variable The variable to check
|
138
|
+
* @returns {boolean} Whether the variable is a this parameter
|
139
|
+
*/
|
140
|
+
function isThisParam(variable) {
|
141
|
+
return variable.name === "this";
|
142
|
+
}
|
143
|
+
|
144
|
+
/**
|
145
|
+
* Checks if type and value shadows each other
|
146
|
+
* @param {Object} variable The variable to check
|
147
|
+
* @param {Object} shadowedVariable The shadowed variable
|
148
|
+
* @returns {boolean} Whether it's a type/value shadow case to ignore
|
149
|
+
*/
|
150
|
+
function isTypeValueShadow(variable, shadowedVariable) {
|
151
|
+
if (ignoreTypeValueShadow !== true) {
|
152
|
+
return false;
|
153
|
+
}
|
154
|
+
|
155
|
+
if (!("isValueVariable" in variable)) {
|
156
|
+
return false;
|
157
|
+
}
|
158
|
+
|
159
|
+
const firstDefinition = shadowedVariable.defs[0];
|
160
|
+
|
161
|
+
// Check if shadowedVariable is a type import
|
162
|
+
const isTypeImport =
|
163
|
+
firstDefinition &&
|
164
|
+
firstDefinition.parent?.type === "ImportDeclaration" &&
|
165
|
+
(firstDefinition.parent.importKind === "type" ||
|
166
|
+
firstDefinition.parent.specifiers.some(
|
167
|
+
s => s.importKind === "type",
|
168
|
+
));
|
169
|
+
|
170
|
+
const isShadowedValue =
|
171
|
+
!firstDefinition ||
|
172
|
+
(isTypeImport ? false : shadowedVariable.isValueVariable);
|
173
|
+
|
174
|
+
return variable.isValueVariable !== isShadowedValue;
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Checks if it's a function type parameter shadow
|
179
|
+
* @param {Object} variable The variable to check
|
180
|
+
* @returns {boolean} Whether it's a function type parameter shadow case to ignore
|
181
|
+
*/
|
182
|
+
function isFunctionTypeParameterNameValueShadow(variable) {
|
183
|
+
if (ignoreFunctionTypeParameterNameValueShadow !== true) {
|
184
|
+
return false;
|
185
|
+
}
|
186
|
+
|
187
|
+
return variable.defs.some(def =>
|
188
|
+
ALLOWED_FUNCTION_VARIABLE_DEF_TYPES.has(def.node.type),
|
189
|
+
);
|
190
|
+
}
|
191
|
+
|
192
|
+
/**
|
193
|
+
* Checks if the variable is a generic of a static method
|
194
|
+
* @param {Object} variable The variable to check
|
195
|
+
* @returns {boolean} Whether the variable is a generic of a static method
|
196
|
+
*/
|
197
|
+
function isTypeParameterOfStaticMethod(variable) {
|
198
|
+
const typeParameter = variable.identifiers[0].parent;
|
199
|
+
const typeParameterDecl = typeParameter.parent;
|
200
|
+
if (typeParameterDecl.type !== "TSTypeParameterDeclaration") {
|
201
|
+
return false;
|
202
|
+
}
|
203
|
+
const functionExpr = typeParameterDecl.parent;
|
204
|
+
const methodDefinition = functionExpr.parent;
|
205
|
+
return methodDefinition.static;
|
206
|
+
}
|
207
|
+
|
208
|
+
/**
|
209
|
+
* Checks for static method generic shadowing class generic
|
210
|
+
* @param {Object} variable The variable to check
|
211
|
+
* @returns {boolean} Whether it's a static method generic shadowing class generic
|
212
|
+
*/
|
213
|
+
function isGenericOfAStaticMethodShadow(variable) {
|
214
|
+
return isTypeParameterOfStaticMethod(variable);
|
215
|
+
}
|
216
|
+
|
82
217
|
/**
|
83
218
|
* Checks whether or not a given location is inside of the range of a given node.
|
84
219
|
* @param {ASTNode} node An node to check.
|
@@ -114,7 +249,7 @@ module.exports = {
|
|
114
249
|
function getOuterScope(scope) {
|
115
250
|
const upper = scope.upper;
|
116
251
|
|
117
|
-
if (upper.type === "function-expression-name") {
|
252
|
+
if (upper && upper.type === "function-expression-name") {
|
118
253
|
return upper.upper;
|
119
254
|
}
|
120
255
|
return upper;
|
@@ -284,6 +419,21 @@ module.exports = {
|
|
284
419
|
const inner = getNameRange(variable);
|
285
420
|
const outer = getNameRange(scopeVar);
|
286
421
|
|
422
|
+
if (!outer || inner[1] >= outer[0]) {
|
423
|
+
return false;
|
424
|
+
}
|
425
|
+
|
426
|
+
if (hoist === "types") {
|
427
|
+
return !TYPES_HOISTED_NODES.has(outerDef.node.type);
|
428
|
+
}
|
429
|
+
|
430
|
+
if (hoist === "functions-and-types") {
|
431
|
+
return (
|
432
|
+
outerDef.node.type !== "FunctionDeclaration" &&
|
433
|
+
!TYPES_HOISTED_NODES.has(outerDef.node.type)
|
434
|
+
);
|
435
|
+
}
|
436
|
+
|
287
437
|
return (
|
288
438
|
inner &&
|
289
439
|
outer &&
|
@@ -295,12 +445,111 @@ module.exports = {
|
|
295
445
|
);
|
296
446
|
}
|
297
447
|
|
448
|
+
/**
|
449
|
+
* Checks if the initialization of a variable has the declare modifier in a
|
450
|
+
* definition file.
|
451
|
+
* @param {Object} variable The variable to check
|
452
|
+
* @returns {boolean} Whether the variable is declared in a definition file
|
453
|
+
*/
|
454
|
+
function isDeclareInDTSFile(variable) {
|
455
|
+
const fileName = context.filename;
|
456
|
+
if (
|
457
|
+
!fileName.endsWith(".d.ts") &&
|
458
|
+
!fileName.endsWith(".d.cts") &&
|
459
|
+
!fileName.endsWith(".d.mts")
|
460
|
+
) {
|
461
|
+
return false;
|
462
|
+
}
|
463
|
+
return variable.defs.some(
|
464
|
+
def =>
|
465
|
+
(def.type === "Variable" && def.parent.declare) ||
|
466
|
+
(def.type === "ClassName" && def.node.declare) ||
|
467
|
+
(def.type === "TSEnumName" && def.node.declare) ||
|
468
|
+
(def.type === "TSModuleName" && def.node.declare),
|
469
|
+
);
|
470
|
+
}
|
471
|
+
|
472
|
+
/**
|
473
|
+
* Checks if a variable is a duplicate of an enum name in the enum scope
|
474
|
+
* @param {Object} variable The variable to check
|
475
|
+
* @returns {boolean} Whether it's a duplicate enum name variable
|
476
|
+
*/
|
477
|
+
function isDuplicatedEnumNameVariable(variable) {
|
478
|
+
const block = variable.scope.block;
|
479
|
+
|
480
|
+
return (
|
481
|
+
block.type === "TSEnumDeclaration" &&
|
482
|
+
block.id === variable.identifiers[0]
|
483
|
+
);
|
484
|
+
}
|
485
|
+
|
486
|
+
/**
|
487
|
+
* Check if this is an external module declaration merging with a type import
|
488
|
+
* @param {Scope} scope Current scope
|
489
|
+
* @param {Object} variable Current variable
|
490
|
+
* @param {Object} shadowedVariable Shadowed variable
|
491
|
+
* @returns {boolean} Whether it's an external declaration merging
|
492
|
+
*/
|
493
|
+
function isExternalDeclarationMerging(
|
494
|
+
scope,
|
495
|
+
variable,
|
496
|
+
shadowedVariable,
|
497
|
+
) {
|
498
|
+
const firstDefinition = shadowedVariable.defs[0];
|
499
|
+
|
500
|
+
if (!firstDefinition || !firstDefinition.parent) {
|
501
|
+
return false;
|
502
|
+
}
|
503
|
+
|
504
|
+
// Check if the shadowed variable is a type import
|
505
|
+
const isTypeImport =
|
506
|
+
firstDefinition.parent.type === "ImportDeclaration" &&
|
507
|
+
(firstDefinition.parent.importKind === "type" ||
|
508
|
+
firstDefinition.parent.specifiers?.some(
|
509
|
+
s =>
|
510
|
+
s.type === "ImportSpecifier" &&
|
511
|
+
s.importKind === "type" &&
|
512
|
+
s.local.name === shadowedVariable.name,
|
513
|
+
));
|
514
|
+
|
515
|
+
if (!isTypeImport) {
|
516
|
+
return false;
|
517
|
+
}
|
518
|
+
|
519
|
+
// Check if the current variable is within a module declaration
|
520
|
+
const moduleDecl = findSelfOrAncestor(
|
521
|
+
variable.identifiers[0]?.parent,
|
522
|
+
node => node.type === "TSModuleDeclaration",
|
523
|
+
);
|
524
|
+
|
525
|
+
if (!moduleDecl) {
|
526
|
+
return false;
|
527
|
+
}
|
528
|
+
|
529
|
+
/*
|
530
|
+
* Module declaration merging should only happen within the same module
|
531
|
+
* Check if the module name matches the import source
|
532
|
+
*/
|
533
|
+
const importSource = firstDefinition.parent.source.value;
|
534
|
+
const moduleName =
|
535
|
+
moduleDecl.id.type === "Literal"
|
536
|
+
? moduleDecl.id.value
|
537
|
+
: moduleDecl.id.name;
|
538
|
+
|
539
|
+
return importSource === moduleName;
|
540
|
+
}
|
541
|
+
|
298
542
|
/**
|
299
543
|
* Checks the current context for shadowed variables.
|
300
544
|
* @param {Scope} scope Fixme
|
301
545
|
* @returns {void}
|
302
546
|
*/
|
303
547
|
function checkForShadows(scope) {
|
548
|
+
// ignore global augmentation
|
549
|
+
if (isGlobalAugmentation(scope)) {
|
550
|
+
return;
|
551
|
+
}
|
552
|
+
|
304
553
|
const variables = scope.variables;
|
305
554
|
|
306
555
|
for (let i = 0; i < variables.length; ++i) {
|
@@ -310,7 +559,10 @@ module.exports = {
|
|
310
559
|
if (
|
311
560
|
variable.identifiers.length === 0 ||
|
312
561
|
isDuplicatedClassNameVariable(variable) ||
|
313
|
-
|
562
|
+
isDuplicatedEnumNameVariable(variable) ||
|
563
|
+
isAllowed(variable) ||
|
564
|
+
isDeclareInDTSFile(variable) ||
|
565
|
+
isThisParam(variable)
|
314
566
|
) {
|
315
567
|
continue;
|
316
568
|
}
|
@@ -330,7 +582,11 @@ module.exports = {
|
|
330
582
|
ignoreOnInitialization &&
|
331
583
|
isInitPatternNode(variable, shadowed)
|
332
584
|
) &&
|
333
|
-
!(hoist !== "all" && isInTdz(variable, shadowed))
|
585
|
+
!(hoist !== "all" && isInTdz(variable, shadowed)) &&
|
586
|
+
!isTypeValueShadow(variable, shadowed) &&
|
587
|
+
!isFunctionTypeParameterNameValueShadow(variable) &&
|
588
|
+
!isGenericOfAStaticMethodShadow(variable, shadowed) &&
|
589
|
+
!isExternalDeclarationMerging(scope, variable, shadowed)
|
334
590
|
) {
|
335
591
|
const location = getDeclaredLocation(shadowed);
|
336
592
|
const messageId = location.global
|
@@ -31,17 +31,25 @@ module.exports = {
|
|
31
31
|
|
32
32
|
create(context) {
|
33
33
|
const sourceCode = context.sourceCode;
|
34
|
+
let insideDeclareModule = false;
|
34
35
|
|
35
36
|
return {
|
37
|
+
"TSModuleDeclaration[declare=true]"() {
|
38
|
+
insideDeclareModule = true;
|
39
|
+
},
|
40
|
+
"TSModuleDeclaration[declare=true]:exit"() {
|
41
|
+
insideDeclareModule = false;
|
42
|
+
},
|
36
43
|
VariableDeclarator(node) {
|
37
44
|
/** @type {import('estree').VariableDeclaration} */
|
38
45
|
const declaration = node.parent;
|
39
|
-
const
|
40
|
-
|
41
|
-
node.id.type
|
42
|
-
declaration.kind
|
43
|
-
|
44
|
-
|
46
|
+
const shouldSkip =
|
47
|
+
node.init ||
|
48
|
+
node.id.type !== "Identifier" ||
|
49
|
+
declaration.kind === "const" ||
|
50
|
+
declaration.declare ||
|
51
|
+
insideDeclareModule;
|
52
|
+
if (shouldSkip) {
|
45
53
|
return;
|
46
54
|
}
|
47
55
|
const [variable] = sourceCode.getDeclaredVariables(node);
|
@@ -30,6 +30,9 @@ function parseOptions(options) {
|
|
30
30
|
classes: true,
|
31
31
|
variables: true,
|
32
32
|
allowNamedExports: false,
|
33
|
+
enums: true,
|
34
|
+
typedefs: true,
|
35
|
+
ignoreTypeReferences: true,
|
33
36
|
};
|
34
37
|
}
|
35
38
|
|
@@ -208,6 +211,57 @@ function isEvaluatedDuringInitialization(reference) {
|
|
208
211
|
return false;
|
209
212
|
}
|
210
213
|
|
214
|
+
/**
|
215
|
+
* check whether the reference contains a type query.
|
216
|
+
* @param {ASTNode} node Identifier node to check.
|
217
|
+
* @returns {boolean} true if reference contains type query.
|
218
|
+
*/
|
219
|
+
function referenceContainsTypeQuery(node) {
|
220
|
+
switch (node.type) {
|
221
|
+
case "TSTypeQuery":
|
222
|
+
return true;
|
223
|
+
|
224
|
+
case "TSQualifiedName":
|
225
|
+
case "Identifier":
|
226
|
+
return referenceContainsTypeQuery(node.parent);
|
227
|
+
|
228
|
+
default:
|
229
|
+
// if we find a different node, there's no chance that we're in a TSTypeQuery
|
230
|
+
return false;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
/**
|
235
|
+
* Decorators are transpiled such that the decorator is placed after the class declaration
|
236
|
+
* So it is considered safe
|
237
|
+
* @param {Variable} variable The variable to check.
|
238
|
+
* @param {Reference} reference The reference to check.
|
239
|
+
* @returns {boolean} `true` if the reference is in a class decorator.
|
240
|
+
*/
|
241
|
+
function isClassRefInClassDecorator(variable, reference) {
|
242
|
+
if (variable.defs[0].type !== "ClassName") {
|
243
|
+
return false;
|
244
|
+
}
|
245
|
+
|
246
|
+
if (
|
247
|
+
!variable.defs[0].node.decorators ||
|
248
|
+
variable.defs[0].node.decorators.length === 0
|
249
|
+
) {
|
250
|
+
return false;
|
251
|
+
}
|
252
|
+
|
253
|
+
for (const deco of variable.defs[0].node.decorators) {
|
254
|
+
if (
|
255
|
+
reference.identifier.range[0] >= deco.range[0] &&
|
256
|
+
reference.identifier.range[1] <= deco.range[1]
|
257
|
+
) {
|
258
|
+
return true;
|
259
|
+
}
|
260
|
+
}
|
261
|
+
|
262
|
+
return false;
|
263
|
+
}
|
264
|
+
|
211
265
|
//------------------------------------------------------------------------------
|
212
266
|
// Rule Definition
|
213
267
|
//------------------------------------------------------------------------------
|
@@ -215,6 +269,8 @@ function isEvaluatedDuringInitialization(reference) {
|
|
215
269
|
/** @type {import('../types').Rule.RuleModule} */
|
216
270
|
module.exports = {
|
217
271
|
meta: {
|
272
|
+
dialects: ["javascript", "typescript"],
|
273
|
+
language: "javascript",
|
218
274
|
type: "problem",
|
219
275
|
|
220
276
|
docs: {
|
@@ -237,6 +293,9 @@ module.exports = {
|
|
237
293
|
classes: { type: "boolean" },
|
238
294
|
variables: { type: "boolean" },
|
239
295
|
allowNamedExports: { type: "boolean" },
|
296
|
+
enums: { type: "boolean" },
|
297
|
+
typedefs: { type: "boolean" },
|
298
|
+
ignoreTypeReferences: { type: "boolean" },
|
240
299
|
},
|
241
300
|
additionalProperties: false,
|
242
301
|
},
|
@@ -250,6 +309,9 @@ module.exports = {
|
|
250
309
|
functions: true,
|
251
310
|
variables: true,
|
252
311
|
allowNamedExports: false,
|
312
|
+
enums: true,
|
313
|
+
typedefs: true,
|
314
|
+
ignoreTypeReferences: true,
|
253
315
|
},
|
254
316
|
],
|
255
317
|
|
@@ -310,6 +372,41 @@ module.exports = {
|
|
310
372
|
return false;
|
311
373
|
}
|
312
374
|
|
375
|
+
if (!options.enums && definitionType === "TSEnumName") {
|
376
|
+
return false;
|
377
|
+
}
|
378
|
+
|
379
|
+
if (!options.typedefs && definitionType === "Type") {
|
380
|
+
return false;
|
381
|
+
}
|
382
|
+
|
383
|
+
if (
|
384
|
+
options.ignoreTypeReferences &&
|
385
|
+
(referenceContainsTypeQuery(identifier) ||
|
386
|
+
identifier.parent.type === "TSTypeReference")
|
387
|
+
) {
|
388
|
+
return false;
|
389
|
+
}
|
390
|
+
|
391
|
+
// skip nested namespace aliases as variable references
|
392
|
+
if (identifier.parent.type === "TSQualifiedName") {
|
393
|
+
let currentNode = identifier.parent;
|
394
|
+
|
395
|
+
while (currentNode.type === "TSQualifiedName") {
|
396
|
+
currentNode = currentNode.left;
|
397
|
+
}
|
398
|
+
|
399
|
+
if (currentNode === identifier) {
|
400
|
+
return true;
|
401
|
+
}
|
402
|
+
|
403
|
+
return false;
|
404
|
+
}
|
405
|
+
|
406
|
+
if (isClassRefInClassDecorator(variable, reference)) {
|
407
|
+
return false;
|
408
|
+
}
|
409
|
+
|
313
410
|
return true;
|
314
411
|
}
|
315
412
|
|
@@ -326,7 +423,8 @@ module.exports = {
|
|
326
423
|
if (
|
327
424
|
reference.identifier.range[1] <
|
328
425
|
definitionIdentifier.range[1] ||
|
329
|
-
isEvaluatedDuringInitialization(reference)
|
426
|
+
(isEvaluatedDuringInitialization(reference) &&
|
427
|
+
reference.identifier.parent.type !== "TSTypeReference")
|
330
428
|
) {
|
331
429
|
context.report({
|
332
430
|
node: reference.identifier,
|
package/lib/rules/no-var.js
CHANGED
@@ -199,6 +199,8 @@ function hasNameDisallowedForLetDeclarations(variable) {
|
|
199
199
|
module.exports = {
|
200
200
|
meta: {
|
201
201
|
type: "suggestion",
|
202
|
+
dialects: ["typescript", "javascript"],
|
203
|
+
language: "javascript",
|
202
204
|
|
203
205
|
docs: {
|
204
206
|
description: "Require `let` or `const` instead of `var`",
|
@@ -346,9 +348,19 @@ module.exports = {
|
|
346
348
|
|
347
349
|
return {
|
348
350
|
"VariableDeclaration:exit"(node) {
|
349
|
-
if (node.kind
|
350
|
-
|
351
|
+
if (node.kind !== "var") {
|
352
|
+
return;
|
351
353
|
}
|
354
|
+
|
355
|
+
if (
|
356
|
+
node.parent.type === "TSModuleBlock" &&
|
357
|
+
node.parent.parent.type === "TSModuleDeclaration" &&
|
358
|
+
node.parent.parent.global
|
359
|
+
) {
|
360
|
+
return;
|
361
|
+
}
|
362
|
+
|
363
|
+
report(node);
|
352
364
|
},
|
353
365
|
};
|
354
366
|
},
|