eslint 8.0.1 → 8.4.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 +8 -12
- package/conf/globals.js +144 -0
- package/lib/cli-engine/cli-engine.js +10 -21
- package/lib/cli.js +1 -1
- package/lib/config/default-config.js +11 -2
- package/lib/config/flat-config-array.js +2 -2
- package/lib/config/flat-config-helpers.js +67 -0
- package/lib/config/flat-config-schema.js +13 -8
- package/lib/config/rule-validator.js +28 -27
- package/lib/eslint/eslint.js +13 -18
- 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 +457 -45
- package/lib/linter/node-event-generator.js +7 -0
- package/lib/options.js +6 -6
- package/lib/rule-tester/rule-tester.js +5 -2
- package/lib/rules/accessor-pairs.js +1 -0
- package/lib/rules/array-bracket-newline.js +1 -0
- package/lib/rules/array-bracket-spacing.js +1 -0
- package/lib/rules/array-callback-return.js +1 -0
- package/lib/rules/array-element-newline.js +1 -0
- package/lib/rules/arrow-body-style.js +1 -0
- package/lib/rules/arrow-parens.js +1 -0
- package/lib/rules/arrow-spacing.js +1 -0
- package/lib/rules/block-scoped-var.js +3 -0
- package/lib/rules/block-spacing.js +11 -3
- package/lib/rules/brace-style.js +7 -0
- package/lib/rules/callback-return.js +1 -0
- package/lib/rules/camelcase.js +1 -0
- package/lib/rules/capitalized-comments.js +1 -0
- package/lib/rules/class-methods-use-this.js +11 -1
- package/lib/rules/comma-dangle.js +1 -0
- package/lib/rules/comma-spacing.js +1 -0
- package/lib/rules/comma-style.js +1 -0
- package/lib/rules/complexity.js +15 -6
- package/lib/rules/computed-property-spacing.js +1 -0
- package/lib/rules/consistent-return.js +1 -0
- package/lib/rules/consistent-this.js +1 -0
- package/lib/rules/constructor-super.js +1 -0
- package/lib/rules/curly.js +1 -0
- package/lib/rules/default-case-last.js +1 -0
- package/lib/rules/default-case.js +1 -0
- package/lib/rules/default-param-last.js +1 -0
- package/lib/rules/dot-location.js +1 -0
- package/lib/rules/dot-notation.js +1 -0
- package/lib/rules/eol-last.js +1 -0
- package/lib/rules/eqeqeq.js +1 -0
- package/lib/rules/for-direction.js +1 -0
- package/lib/rules/func-call-spacing.js +1 -0
- package/lib/rules/func-name-matching.js +1 -0
- package/lib/rules/func-names.js +1 -0
- package/lib/rules/func-style.js +1 -0
- package/lib/rules/function-call-argument-newline.js +1 -0
- package/lib/rules/function-paren-newline.js +1 -0
- package/lib/rules/generator-star-spacing.js +1 -0
- package/lib/rules/getter-return.js +1 -0
- package/lib/rules/global-require.js +1 -0
- package/lib/rules/grouped-accessor-pairs.js +1 -0
- package/lib/rules/guard-for-in.js +1 -0
- package/lib/rules/handle-callback-err.js +1 -0
- package/lib/rules/id-blacklist.js +1 -0
- package/lib/rules/id-denylist.js +1 -0
- package/lib/rules/id-length.js +1 -0
- package/lib/rules/id-match.js +1 -0
- package/lib/rules/implicit-arrow-linebreak.js +1 -0
- package/lib/rules/indent-legacy.js +1 -0
- package/lib/rules/indent.js +22 -0
- package/lib/rules/index.js +1 -0
- package/lib/rules/init-declarations.js +1 -0
- package/lib/rules/jsx-quotes.js +1 -0
- package/lib/rules/key-spacing.js +15 -13
- package/lib/rules/keyword-spacing.js +16 -1
- package/lib/rules/line-comment-position.js +1 -0
- package/lib/rules/linebreak-style.js +1 -0
- package/lib/rules/lines-around-comment.js +55 -7
- package/lib/rules/lines-around-directive.js +1 -0
- package/lib/rules/lines-between-class-members.js +1 -0
- package/lib/rules/max-classes-per-file.js +1 -0
- package/lib/rules/max-depth.js +3 -0
- package/lib/rules/max-len.js +1 -0
- package/lib/rules/max-lines-per-function.js +21 -2
- package/lib/rules/max-lines.js +1 -0
- package/lib/rules/max-nested-callbacks.js +1 -0
- package/lib/rules/max-params.js +1 -0
- package/lib/rules/max-statements-per-line.js +1 -0
- package/lib/rules/max-statements.js +11 -0
- package/lib/rules/multiline-comment-style.js +1 -0
- package/lib/rules/multiline-ternary.js +1 -0
- package/lib/rules/new-cap.js +1 -0
- package/lib/rules/new-parens.js +1 -0
- package/lib/rules/newline-after-var.js +1 -0
- package/lib/rules/newline-before-return.js +1 -0
- package/lib/rules/newline-per-chained-call.js +1 -0
- package/lib/rules/no-alert.js +1 -0
- package/lib/rules/no-array-constructor.js +1 -0
- package/lib/rules/no-async-promise-executor.js +1 -0
- package/lib/rules/no-await-in-loop.js +1 -0
- package/lib/rules/no-bitwise.js +1 -0
- package/lib/rules/no-buffer-constructor.js +1 -0
- package/lib/rules/no-caller.js +1 -0
- package/lib/rules/no-case-declarations.js +1 -0
- package/lib/rules/no-catch-shadow.js +1 -0
- package/lib/rules/no-class-assign.js +1 -0
- package/lib/rules/no-compare-neg-zero.js +1 -0
- package/lib/rules/no-cond-assign.js +1 -0
- package/lib/rules/no-confusing-arrow.js +1 -0
- package/lib/rules/no-console.js +1 -0
- package/lib/rules/no-const-assign.js +1 -0
- package/lib/rules/no-constant-condition.js +4 -1
- package/lib/rules/no-constructor-return.js +1 -0
- package/lib/rules/no-continue.js +1 -0
- package/lib/rules/no-control-regex.js +1 -0
- package/lib/rules/no-debugger.js +1 -0
- package/lib/rules/no-delete-var.js +1 -0
- package/lib/rules/no-div-regex.js +1 -0
- package/lib/rules/no-dupe-args.js +1 -0
- package/lib/rules/no-dupe-class-members.js +1 -0
- package/lib/rules/no-dupe-else-if.js +1 -0
- package/lib/rules/no-dupe-keys.js +1 -0
- package/lib/rules/no-duplicate-case.js +1 -0
- package/lib/rules/no-duplicate-imports.js +1 -0
- package/lib/rules/no-else-return.js +1 -0
- package/lib/rules/no-empty-character-class.js +1 -0
- package/lib/rules/no-empty-function.js +1 -0
- package/lib/rules/no-empty-pattern.js +1 -0
- package/lib/rules/no-empty.js +1 -0
- package/lib/rules/no-eq-null.js +1 -0
- package/lib/rules/no-eval.js +3 -0
- package/lib/rules/no-ex-assign.js +1 -0
- package/lib/rules/no-extend-native.js +1 -0
- package/lib/rules/no-extra-bind.js +1 -0
- package/lib/rules/no-extra-boolean-cast.js +1 -0
- package/lib/rules/no-extra-label.js +1 -0
- package/lib/rules/no-extra-parens.js +1 -0
- package/lib/rules/no-extra-semi.js +2 -1
- package/lib/rules/no-fallthrough.js +1 -0
- package/lib/rules/no-floating-decimal.js +1 -0
- package/lib/rules/no-func-assign.js +1 -0
- package/lib/rules/no-global-assign.js +1 -0
- package/lib/rules/no-implicit-coercion.js +1 -0
- package/lib/rules/no-implicit-globals.js +1 -0
- package/lib/rules/no-implied-eval.js +1 -0
- package/lib/rules/no-import-assign.js +1 -0
- package/lib/rules/no-inline-comments.js +1 -0
- package/lib/rules/no-inner-declarations.js +27 -4
- package/lib/rules/no-invalid-regexp.js +1 -0
- package/lib/rules/no-invalid-this.js +5 -0
- package/lib/rules/no-irregular-whitespace.js +1 -0
- package/lib/rules/no-iterator.js +1 -0
- package/lib/rules/no-label-var.js +1 -0
- package/lib/rules/no-labels.js +1 -0
- package/lib/rules/no-lone-blocks.js +9 -2
- package/lib/rules/no-lonely-if.js +1 -0
- package/lib/rules/no-loop-func.js +1 -0
- package/lib/rules/no-loss-of-precision.js +1 -0
- package/lib/rules/no-magic-numbers.js +1 -0
- package/lib/rules/no-misleading-character-class.js +1 -0
- package/lib/rules/no-mixed-operators.js +1 -0
- package/lib/rules/no-mixed-requires.js +1 -0
- package/lib/rules/no-mixed-spaces-and-tabs.js +1 -0
- package/lib/rules/no-multi-assign.js +1 -0
- package/lib/rules/no-multi-spaces.js +1 -0
- package/lib/rules/no-multi-str.js +1 -0
- package/lib/rules/no-multiple-empty-lines.js +1 -0
- package/lib/rules/no-native-reassign.js +1 -0
- package/lib/rules/no-negated-condition.js +1 -0
- package/lib/rules/no-negated-in-lhs.js +1 -0
- package/lib/rules/no-nested-ternary.js +1 -0
- package/lib/rules/no-new-func.js +1 -0
- package/lib/rules/no-new-object.js +1 -0
- package/lib/rules/no-new-require.js +1 -0
- package/lib/rules/no-new-symbol.js +1 -0
- package/lib/rules/no-new-wrappers.js +1 -0
- package/lib/rules/no-new.js +1 -0
- package/lib/rules/no-nonoctal-decimal-escape.js +1 -0
- package/lib/rules/no-obj-calls.js +1 -0
- package/lib/rules/no-octal-escape.js +1 -0
- package/lib/rules/no-octal.js +1 -0
- package/lib/rules/no-param-reassign.js +1 -0
- package/lib/rules/no-path-concat.js +1 -0
- package/lib/rules/no-plusplus.js +1 -0
- package/lib/rules/no-process-env.js +1 -0
- package/lib/rules/no-process-exit.js +1 -0
- package/lib/rules/no-promise-executor-return.js +1 -0
- package/lib/rules/no-proto.js +1 -0
- package/lib/rules/no-prototype-builtins.js +1 -0
- package/lib/rules/no-redeclare.js +3 -0
- package/lib/rules/no-regex-spaces.js +1 -0
- package/lib/rules/no-restricted-exports.js +1 -0
- package/lib/rules/no-restricted-globals.js +1 -0
- package/lib/rules/no-restricted-imports.js +1 -0
- package/lib/rules/no-restricted-modules.js +1 -0
- package/lib/rules/no-restricted-properties.js +1 -0
- package/lib/rules/no-restricted-syntax.js +1 -0
- package/lib/rules/no-return-assign.js +1 -0
- package/lib/rules/no-return-await.js +1 -0
- package/lib/rules/no-script-url.js +1 -0
- package/lib/rules/no-self-assign.js +1 -0
- package/lib/rules/no-self-compare.js +1 -0
- package/lib/rules/no-sequences.js +1 -0
- package/lib/rules/no-setter-return.js +1 -0
- package/lib/rules/no-shadow-restricted-names.js +1 -0
- package/lib/rules/no-shadow.js +1 -0
- package/lib/rules/no-spaced-func.js +1 -0
- package/lib/rules/no-sparse-arrays.js +1 -0
- package/lib/rules/no-sync.js +1 -0
- package/lib/rules/no-tabs.js +1 -0
- package/lib/rules/no-template-curly-in-string.js +1 -0
- package/lib/rules/no-ternary.js +1 -0
- package/lib/rules/no-this-before-super.js +1 -0
- package/lib/rules/no-throw-literal.js +1 -0
- package/lib/rules/no-trailing-spaces.js +1 -0
- package/lib/rules/no-undef-init.js +1 -0
- package/lib/rules/no-undef.js +1 -0
- package/lib/rules/no-undefined.js +1 -0
- package/lib/rules/no-underscore-dangle.js +1 -0
- package/lib/rules/no-unexpected-multiline.js +1 -0
- package/lib/rules/no-unmodified-loop-condition.js +1 -0
- package/lib/rules/no-unneeded-ternary.js +1 -0
- package/lib/rules/no-unreachable-loop.js +1 -0
- package/lib/rules/no-unreachable.js +1 -0
- package/lib/rules/no-unsafe-finally.js +1 -0
- package/lib/rules/no-unsafe-negation.js +1 -0
- package/lib/rules/no-unsafe-optional-chaining.js +1 -0
- package/lib/rules/no-unused-expressions.js +7 -0
- package/lib/rules/no-unused-labels.js +1 -0
- package/lib/rules/no-unused-private-class-members.js +195 -0
- package/lib/rules/no-unused-vars.js +1 -0
- package/lib/rules/no-use-before-define.js +176 -74
- package/lib/rules/no-useless-backreference.js +1 -0
- package/lib/rules/no-useless-call.js +1 -0
- package/lib/rules/no-useless-catch.js +1 -0
- package/lib/rules/no-useless-computed-key.js +1 -0
- package/lib/rules/no-useless-concat.js +1 -0
- package/lib/rules/no-useless-constructor.js +1 -0
- package/lib/rules/no-useless-escape.js +1 -0
- package/lib/rules/no-useless-rename.js +1 -0
- package/lib/rules/no-useless-return.js +1 -0
- package/lib/rules/no-var.js +1 -0
- package/lib/rules/no-void.js +1 -0
- package/lib/rules/no-warning-comments.js +1 -0
- package/lib/rules/no-whitespace-before-property.js +1 -0
- package/lib/rules/no-with.js +1 -0
- package/lib/rules/nonblock-statement-body-position.js +1 -0
- package/lib/rules/object-curly-newline.js +1 -0
- package/lib/rules/object-curly-spacing.js +1 -0
- package/lib/rules/object-property-newline.js +1 -0
- package/lib/rules/object-shorthand.js +1 -0
- package/lib/rules/one-var-declaration-per-line.js +1 -0
- package/lib/rules/one-var.js +6 -1
- package/lib/rules/operator-assignment.js +1 -0
- package/lib/rules/operator-linebreak.js +1 -0
- package/lib/rules/padded-blocks.js +9 -0
- package/lib/rules/padding-line-between-statements.js +3 -0
- package/lib/rules/prefer-arrow-callback.js +1 -0
- package/lib/rules/prefer-const.js +2 -1
- package/lib/rules/prefer-destructuring.js +1 -0
- package/lib/rules/prefer-exponentiation-operator.js +1 -0
- package/lib/rules/prefer-named-capture-group.js +1 -0
- package/lib/rules/prefer-numeric-literals.js +1 -0
- package/lib/rules/prefer-object-spread.js +1 -0
- package/lib/rules/prefer-promise-reject-errors.js +1 -0
- package/lib/rules/prefer-reflect.js +1 -0
- package/lib/rules/prefer-regex-literals.js +1 -0
- package/lib/rules/prefer-rest-params.js +1 -0
- package/lib/rules/prefer-spread.js +1 -0
- package/lib/rules/prefer-template.js +1 -0
- package/lib/rules/quote-props.js +1 -0
- package/lib/rules/quotes.js +1 -0
- package/lib/rules/radix.js +1 -0
- package/lib/rules/require-atomic-updates.js +15 -2
- package/lib/rules/require-await.js +1 -0
- package/lib/rules/require-jsdoc.js +1 -0
- package/lib/rules/require-unicode-regexp.js +1 -0
- package/lib/rules/require-yield.js +1 -0
- package/lib/rules/rest-spread-spacing.js +1 -0
- package/lib/rules/semi-spacing.js +1 -0
- package/lib/rules/semi-style.js +9 -2
- package/lib/rules/semi.js +19 -9
- package/lib/rules/sort-imports.js +1 -0
- package/lib/rules/sort-keys.js +1 -0
- package/lib/rules/sort-vars.js +1 -0
- package/lib/rules/space-before-blocks.js +1 -0
- package/lib/rules/space-before-function-paren.js +1 -0
- package/lib/rules/space-in-parens.js +1 -0
- package/lib/rules/space-infix-ops.js +1 -0
- package/lib/rules/space-unary-ops.js +1 -0
- package/lib/rules/spaced-comment.js +1 -0
- package/lib/rules/strict.js +1 -0
- package/lib/rules/switch-colon-spacing.js +1 -0
- package/lib/rules/symbol-description.js +1 -0
- package/lib/rules/template-curly-spacing.js +1 -0
- package/lib/rules/template-tag-spacing.js +1 -0
- package/lib/rules/unicode-bom.js +1 -0
- package/lib/rules/use-isnan.js +1 -0
- package/lib/rules/utils/ast-utils.js +15 -3
- package/lib/rules/valid-jsdoc.js +1 -0
- package/lib/rules/valid-typeof.js +1 -0
- package/lib/rules/vars-on-top.js +26 -12
- package/lib/rules/wrap-iife.js +1 -0
- package/lib/rules/wrap-regex.js +1 -0
- package/lib/rules/yield-star-spacing.js +1 -0
- package/lib/rules/yoda.js +1 -0
- package/lib/shared/types.js +10 -0
- package/package.json +12 -12
@@ -24,6 +24,7 @@ function alwaysFalse() {
|
|
24
24
|
return false;
|
25
25
|
}
|
26
26
|
|
27
|
+
/** @type {import('../shared/types').Rule} */
|
27
28
|
module.exports = {
|
28
29
|
meta: {
|
29
30
|
type: "suggestion",
|
@@ -115,6 +116,12 @@ module.exports = {
|
|
115
116
|
const parent = ancestors[ancestors.length - 1],
|
116
117
|
grandparent = ancestors[ancestors.length - 2];
|
117
118
|
|
119
|
+
/**
|
120
|
+
* https://tc39.es/ecma262/#directive-prologue
|
121
|
+
*
|
122
|
+
* Only `FunctionBody`, `ScriptBody` and `ModuleBody` can have directive prologue.
|
123
|
+
* Class static blocks do not have directive prologue.
|
124
|
+
*/
|
118
125
|
return (parent.type === "Program" || parent.type === "BlockStatement" &&
|
119
126
|
(/Function/u.test(grandparent.type))) &&
|
120
127
|
directives(parent).indexOf(node) >= 0;
|
@@ -0,0 +1,195 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Rule to flag declared but unused private class members
|
3
|
+
* @author Tim van der Lippe
|
4
|
+
*/
|
5
|
+
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Rule Definition
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
/** @type {import('../shared/types').Rule} */
|
13
|
+
module.exports = {
|
14
|
+
meta: {
|
15
|
+
type: "problem",
|
16
|
+
|
17
|
+
docs: {
|
18
|
+
description: "disallow unused private class members",
|
19
|
+
recommended: false,
|
20
|
+
url: "https://eslint.org/docs/rules/no-unused-private-class-members"
|
21
|
+
},
|
22
|
+
|
23
|
+
schema: [],
|
24
|
+
|
25
|
+
messages: {
|
26
|
+
unusedPrivateClassMember: "'{{classMemberName}}' is defined but never used."
|
27
|
+
}
|
28
|
+
},
|
29
|
+
|
30
|
+
create(context) {
|
31
|
+
const trackedClasses = [];
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Check whether the current node is in a write only assignment.
|
35
|
+
* @param {ASTNode} privateIdentifierNode Node referring to a private identifier
|
36
|
+
* @returns {boolean} Whether the node is in a write only assignment
|
37
|
+
* @private
|
38
|
+
*/
|
39
|
+
function isWriteOnlyAssignment(privateIdentifierNode) {
|
40
|
+
const parentStatement = privateIdentifierNode.parent.parent;
|
41
|
+
const isAssignmentExpression = parentStatement.type === "AssignmentExpression";
|
42
|
+
|
43
|
+
if (!isAssignmentExpression &&
|
44
|
+
parentStatement.type !== "ForInStatement" &&
|
45
|
+
parentStatement.type !== "ForOfStatement" &&
|
46
|
+
parentStatement.type !== "AssignmentPattern") {
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
|
50
|
+
// It is a write-only usage, since we still allow usages on the right for reads
|
51
|
+
if (parentStatement.left !== privateIdentifierNode.parent) {
|
52
|
+
return false;
|
53
|
+
}
|
54
|
+
|
55
|
+
// For any other operator (such as '+=') we still consider it a read operation
|
56
|
+
if (isAssignmentExpression && parentStatement.operator !== "=") {
|
57
|
+
|
58
|
+
/*
|
59
|
+
* However, if the read operation is "discarded" in an empty statement, then
|
60
|
+
* we consider it write only.
|
61
|
+
*/
|
62
|
+
return parentStatement.parent.type === "ExpressionStatement";
|
63
|
+
}
|
64
|
+
|
65
|
+
return true;
|
66
|
+
}
|
67
|
+
|
68
|
+
//--------------------------------------------------------------------------
|
69
|
+
// Public
|
70
|
+
//--------------------------------------------------------------------------
|
71
|
+
|
72
|
+
return {
|
73
|
+
|
74
|
+
// Collect all declared members up front and assume they are all unused
|
75
|
+
ClassBody(classBodyNode) {
|
76
|
+
const privateMembers = new Map();
|
77
|
+
|
78
|
+
trackedClasses.unshift(privateMembers);
|
79
|
+
for (const bodyMember of classBodyNode.body) {
|
80
|
+
if (bodyMember.type === "PropertyDefinition" || bodyMember.type === "MethodDefinition") {
|
81
|
+
if (bodyMember.key.type === "PrivateIdentifier") {
|
82
|
+
privateMembers.set(bodyMember.key.name, {
|
83
|
+
declaredNode: bodyMember,
|
84
|
+
isAccessor: bodyMember.type === "MethodDefinition" &&
|
85
|
+
(bodyMember.kind === "set" || bodyMember.kind === "get")
|
86
|
+
});
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
},
|
91
|
+
|
92
|
+
/*
|
93
|
+
* Process all usages of the private identifier and remove a member from
|
94
|
+
* `declaredAndUnusedPrivateMembers` if we deem it used.
|
95
|
+
*/
|
96
|
+
PrivateIdentifier(privateIdentifierNode) {
|
97
|
+
const classBody = trackedClasses.find(classProperties => classProperties.has(privateIdentifierNode.name));
|
98
|
+
|
99
|
+
// Can't happen, as it is a parser to have a missing class body, but let's code defensively here.
|
100
|
+
if (!classBody) {
|
101
|
+
return;
|
102
|
+
}
|
103
|
+
|
104
|
+
// In case any other usage was already detected, we can short circuit the logic here.
|
105
|
+
const memberDefinition = classBody.get(privateIdentifierNode.name);
|
106
|
+
|
107
|
+
if (memberDefinition.isUsed) {
|
108
|
+
return;
|
109
|
+
}
|
110
|
+
|
111
|
+
// The definition of the class member itself
|
112
|
+
if (privateIdentifierNode.parent.type === "PropertyDefinition" ||
|
113
|
+
privateIdentifierNode.parent.type === "MethodDefinition") {
|
114
|
+
return;
|
115
|
+
}
|
116
|
+
|
117
|
+
/*
|
118
|
+
* Any usage of an accessor is considered a read, as the getter/setter can have
|
119
|
+
* side-effects in its definition.
|
120
|
+
*/
|
121
|
+
if (memberDefinition.isAccessor) {
|
122
|
+
memberDefinition.isUsed = true;
|
123
|
+
return;
|
124
|
+
}
|
125
|
+
|
126
|
+
// Any assignments to this member, except for assignments that also read
|
127
|
+
if (isWriteOnlyAssignment(privateIdentifierNode)) {
|
128
|
+
return;
|
129
|
+
}
|
130
|
+
|
131
|
+
const wrappingExpressionType = privateIdentifierNode.parent.parent.type;
|
132
|
+
const parentOfWrappingExpressionType = privateIdentifierNode.parent.parent.parent.type;
|
133
|
+
|
134
|
+
// A statement which only increments (`this.#x++;`)
|
135
|
+
if (wrappingExpressionType === "UpdateExpression" &&
|
136
|
+
parentOfWrappingExpressionType === "ExpressionStatement") {
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
|
140
|
+
/*
|
141
|
+
* ({ x: this.#usedInDestructuring } = bar);
|
142
|
+
*
|
143
|
+
* But should treat the following as a read:
|
144
|
+
* ({ [this.#x]: a } = foo);
|
145
|
+
*/
|
146
|
+
if (wrappingExpressionType === "Property" &&
|
147
|
+
parentOfWrappingExpressionType === "ObjectPattern" &&
|
148
|
+
privateIdentifierNode.parent.parent.value === privateIdentifierNode.parent) {
|
149
|
+
return;
|
150
|
+
}
|
151
|
+
|
152
|
+
// [...this.#unusedInRestPattern] = bar;
|
153
|
+
if (wrappingExpressionType === "RestElement") {
|
154
|
+
return;
|
155
|
+
}
|
156
|
+
|
157
|
+
// [this.#unusedInAssignmentPattern] = bar;
|
158
|
+
if (wrappingExpressionType === "ArrayPattern") {
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
|
162
|
+
/*
|
163
|
+
* We can't delete the memberDefinition, as we need to keep track of which member we are marking as used.
|
164
|
+
* In the case of nested classes, we only mark the first member we encounter as used. If you were to delete
|
165
|
+
* the member, then any subsequent usage could incorrectly mark the member of an encapsulating parent class
|
166
|
+
* as used, which is incorrect.
|
167
|
+
*/
|
168
|
+
memberDefinition.isUsed = true;
|
169
|
+
},
|
170
|
+
|
171
|
+
/*
|
172
|
+
* Post-process the class members and report any remaining members.
|
173
|
+
* Since private members can only be accessed in the current class context,
|
174
|
+
* we can safely assume that all usages are within the current class body.
|
175
|
+
*/
|
176
|
+
"ClassBody:exit"() {
|
177
|
+
const unusedPrivateMembers = trackedClasses.shift();
|
178
|
+
|
179
|
+
for (const [classMemberName, { declaredNode, isUsed }] of unusedPrivateMembers.entries()) {
|
180
|
+
if (isUsed) {
|
181
|
+
continue;
|
182
|
+
}
|
183
|
+
context.report({
|
184
|
+
node: declaredNode,
|
185
|
+
loc: declaredNode.key.loc,
|
186
|
+
messageId: "unusedPrivateClassMember",
|
187
|
+
data: {
|
188
|
+
classMemberName: `#${classMemberName}`
|
189
|
+
}
|
190
|
+
});
|
191
|
+
}
|
192
|
+
}
|
193
|
+
};
|
194
|
+
}
|
195
|
+
};
|
@@ -34,52 +34,113 @@ function parseOptions(options) {
|
|
34
34
|
}
|
35
35
|
|
36
36
|
/**
|
37
|
-
* Checks whether or not a given
|
38
|
-
* @param {
|
39
|
-
* @
|
37
|
+
* Checks whether or not a given location is inside of the range of a given node.
|
38
|
+
* @param {ASTNode} node An node to check.
|
39
|
+
* @param {number} location A location to check.
|
40
|
+
* @returns {boolean} `true` if the location is inside of the range of the node.
|
40
41
|
*/
|
41
|
-
function
|
42
|
-
return
|
42
|
+
function isInRange(node, location) {
|
43
|
+
return node && node.range[0] <= location && location <= node.range[1];
|
43
44
|
}
|
44
45
|
|
45
46
|
/**
|
46
|
-
* Checks whether or not a given
|
47
|
-
*
|
48
|
-
* @param {
|
49
|
-
* @
|
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.
|
49
|
+
* @param {ASTNode} node `ClassBody` node to check static initializers.
|
50
|
+
* @param {number} location A location to check.
|
51
|
+
* @returns {boolean} `true` if the location is inside of a class static initializer.
|
50
52
|
*/
|
51
|
-
function
|
52
|
-
return (
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
function isInClassStaticInitializerRange(node, location) {
|
54
|
+
return node.body.some(classMember => (
|
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
|
+
)
|
65
|
+
));
|
56
66
|
}
|
57
67
|
|
58
68
|
/**
|
59
|
-
* Checks whether
|
60
|
-
*
|
61
|
-
* @param {eslint-scope.
|
62
|
-
* @returns {boolean} `true` if the
|
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.
|
71
|
+
* @param {eslint-scope.Scope} scope A scope to check.
|
72
|
+
* @returns {boolean} `true` if the scope is a class static initializer scope.
|
63
73
|
*/
|
64
|
-
function
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
74
|
+
function isClassStaticInitializerScope(scope) {
|
75
|
+
if (scope.type === "class-static-block") {
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
|
79
|
+
if (scope.type === "class-field-initializer") {
|
80
|
+
|
81
|
+
// `scope.block` is PropertyDefinition#value node
|
82
|
+
const propertyDefinition = scope.block.parent;
|
83
|
+
|
84
|
+
return propertyDefinition.static;
|
85
|
+
}
|
86
|
+
|
87
|
+
return false;
|
69
88
|
}
|
70
89
|
|
71
90
|
/**
|
72
|
-
* Checks whether
|
73
|
-
*
|
74
|
-
*
|
75
|
-
*
|
91
|
+
* Checks whether a given reference is evaluated in an execution context
|
92
|
+
* that isn't the one where the variable it refers to is defined.
|
93
|
+
* Execution contexts are:
|
94
|
+
* - top-level
|
95
|
+
* - functions
|
96
|
+
* - class field initializers (implicit functions)
|
97
|
+
* - class static blocks (implicit functions)
|
98
|
+
* Static class field initializers and class static blocks are automatically run during the class definition evaluation,
|
99
|
+
* and therefore we'll consider them as a part of the parent execution context.
|
100
|
+
* Example:
|
101
|
+
*
|
102
|
+
* const x = 1;
|
103
|
+
*
|
104
|
+
* x; // returns `false`
|
105
|
+
* () => x; // returns `true`
|
106
|
+
*
|
107
|
+
* class C {
|
108
|
+
* field = x; // returns `true`
|
109
|
+
* static field = x; // returns `false`
|
110
|
+
*
|
111
|
+
* method() {
|
112
|
+
* x; // returns `true`
|
113
|
+
* }
|
114
|
+
*
|
115
|
+
* static method() {
|
116
|
+
* x; // returns `true`
|
117
|
+
* }
|
118
|
+
*
|
119
|
+
* static {
|
120
|
+
* x; // returns `false`
|
121
|
+
* }
|
122
|
+
* }
|
123
|
+
* @param {eslint-scope.Reference} reference A reference to check.
|
124
|
+
* @returns {boolean} `true` if the reference is from a separate execution context.
|
76
125
|
*/
|
77
|
-
function
|
78
|
-
|
126
|
+
function isFromSeparateExecutionContext(reference) {
|
127
|
+
const variable = reference.resolved;
|
128
|
+
let scope = reference.from;
|
129
|
+
|
130
|
+
// Scope#variableScope represents execution context
|
131
|
+
while (variable.scope.variableScope !== scope.variableScope) {
|
132
|
+
if (isClassStaticInitializerScope(scope.variableScope)) {
|
133
|
+
scope = scope.variableScope.upper;
|
134
|
+
} else {
|
135
|
+
return true;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
return false;
|
79
140
|
}
|
80
141
|
|
81
142
|
/**
|
82
|
-
* Checks whether or not a given reference is
|
143
|
+
* Checks whether or not a given reference is evaluated during the initialization of its variable.
|
83
144
|
*
|
84
145
|
* This returns `true` in the following cases:
|
85
146
|
*
|
@@ -88,17 +149,45 @@ function isInRange(node, location) {
|
|
88
149
|
* var {a = a} = obj
|
89
150
|
* for (var a in a) {}
|
90
151
|
* for (var a of a) {}
|
91
|
-
*
|
152
|
+
* var C = class { [C]; };
|
153
|
+
* var C = class { static foo = C; };
|
154
|
+
* var C = class { static { foo = C; } };
|
155
|
+
* class C extends C {}
|
156
|
+
* class C extends (class { static foo = C; }) {}
|
157
|
+
* class C { [C]; }
|
92
158
|
* @param {Reference} reference A reference to check.
|
93
|
-
* @returns {boolean} `true` if the reference is
|
159
|
+
* @returns {boolean} `true` if the reference is evaluated during the initialization.
|
94
160
|
*/
|
95
|
-
function
|
96
|
-
if (
|
161
|
+
function isEvaluatedDuringInitialization(reference) {
|
162
|
+
if (isFromSeparateExecutionContext(reference)) {
|
163
|
+
|
164
|
+
/*
|
165
|
+
* Even if the reference appears in the initializer, it isn't evaluated during the initialization.
|
166
|
+
* For example, `const x = () => x;` is valid.
|
167
|
+
*/
|
97
168
|
return false;
|
98
169
|
}
|
99
170
|
|
100
|
-
let node = variable.identifiers[0].parent;
|
101
171
|
const location = reference.identifier.range[1];
|
172
|
+
const definition = reference.resolved.defs[0];
|
173
|
+
|
174
|
+
if (definition.type === "ClassName") {
|
175
|
+
|
176
|
+
// `ClassDeclaration` or `ClassExpression`
|
177
|
+
const classDefinition = definition.node;
|
178
|
+
|
179
|
+
return (
|
180
|
+
isInRange(classDefinition, location) &&
|
181
|
+
|
182
|
+
/*
|
183
|
+
* Class binding is initialized before running static initializers.
|
184
|
+
* For example, `class C { static foo = C; static { bar = C; } }` is valid.
|
185
|
+
*/
|
186
|
+
!isInClassStaticInitializerRange(classDefinition.body, location)
|
187
|
+
);
|
188
|
+
}
|
189
|
+
|
190
|
+
let node = definition.name.parent;
|
102
191
|
|
103
192
|
while (node) {
|
104
193
|
if (node.type === "VariableDeclarator") {
|
@@ -129,6 +218,7 @@ function isInInitializer(variable, reference) {
|
|
129
218
|
// Rule Definition
|
130
219
|
//------------------------------------------------------------------------------
|
131
220
|
|
221
|
+
/** @type {import('../shared/types').Rule} */
|
132
222
|
module.exports = {
|
133
223
|
meta: {
|
134
224
|
type: "problem",
|
@@ -167,65 +257,77 @@ module.exports = {
|
|
167
257
|
const options = parseOptions(context.options[0]);
|
168
258
|
|
169
259
|
/**
|
170
|
-
* Determines whether a given
|
171
|
-
*
|
172
|
-
*
|
173
|
-
*
|
260
|
+
* Determines whether a given reference should be checked.
|
261
|
+
*
|
262
|
+
* Returns `false` if the reference is:
|
263
|
+
* - initialization's (e.g., `let a = 1`).
|
264
|
+
* - referring to an undefined variable (i.e., if it's an unresolved reference).
|
265
|
+
* - referring to a variable that is defined, but not in the given source code
|
266
|
+
* (e.g., global environment variable or `arguments` in functions).
|
267
|
+
* - allowed by options.
|
268
|
+
* @param {eslint-scope.Reference} reference The reference
|
269
|
+
* @returns {boolean} `true` if the reference should be checked
|
174
270
|
*/
|
175
|
-
function
|
176
|
-
if (
|
177
|
-
return
|
271
|
+
function shouldCheck(reference) {
|
272
|
+
if (reference.init) {
|
273
|
+
return false;
|
178
274
|
}
|
179
|
-
|
180
|
-
|
275
|
+
|
276
|
+
const variable = reference.resolved;
|
277
|
+
|
278
|
+
if (!variable || variable.defs.length === 0) {
|
279
|
+
return false;
|
181
280
|
}
|
182
|
-
|
183
|
-
|
281
|
+
|
282
|
+
const definitionType = variable.defs[0].type;
|
283
|
+
|
284
|
+
if (!options.functions && definitionType === "FunctionName") {
|
285
|
+
return false;
|
184
286
|
}
|
287
|
+
|
288
|
+
if (
|
289
|
+
(
|
290
|
+
!options.variables && definitionType === "Variable" ||
|
291
|
+
!options.classes && definitionType === "ClassName"
|
292
|
+
) &&
|
293
|
+
|
294
|
+
// don't skip checking the reference if it's in the same execution context, because of TDZ
|
295
|
+
isFromSeparateExecutionContext(reference)
|
296
|
+
) {
|
297
|
+
return false;
|
298
|
+
}
|
299
|
+
|
185
300
|
return true;
|
186
301
|
}
|
187
302
|
|
188
303
|
/**
|
189
|
-
* Finds and validates all
|
190
|
-
* @param {Scope} scope The scope object.
|
304
|
+
* Finds and validates all references in a given scope and its child scopes.
|
305
|
+
* @param {eslint-scope.Scope} scope The scope object.
|
191
306
|
* @returns {void}
|
192
|
-
* @private
|
193
307
|
*/
|
194
|
-
function
|
195
|
-
scope.references.forEach(reference => {
|
308
|
+
function checkReferencesInScope(scope) {
|
309
|
+
scope.references.filter(shouldCheck).forEach(reference => {
|
196
310
|
const variable = reference.resolved;
|
311
|
+
const definitionIdentifier = variable.defs[0].name;
|
197
312
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
* - referring to an undefined variable.
|
202
|
-
* - referring to a global environment variable (there're no identifiers).
|
203
|
-
* - located preceded by the variable (except in initializers).
|
204
|
-
* - allowed by options.
|
205
|
-
*/
|
206
|
-
if (reference.init ||
|
207
|
-
!variable ||
|
208
|
-
variable.identifiers.length === 0 ||
|
209
|
-
(variable.identifiers[0].range[1] < reference.identifier.range[1] && !isInInitializer(variable, reference)) ||
|
210
|
-
!isForbidden(variable, reference)
|
313
|
+
if (
|
314
|
+
reference.identifier.range[1] < definitionIdentifier.range[1] ||
|
315
|
+
isEvaluatedDuringInitialization(reference)
|
211
316
|
) {
|
212
|
-
|
317
|
+
context.report({
|
318
|
+
node: reference.identifier,
|
319
|
+
messageId: "usedBeforeDefined",
|
320
|
+
data: reference.identifier
|
321
|
+
});
|
213
322
|
}
|
214
|
-
|
215
|
-
// Reports.
|
216
|
-
context.report({
|
217
|
-
node: reference.identifier,
|
218
|
-
messageId: "usedBeforeDefined",
|
219
|
-
data: reference.identifier
|
220
|
-
});
|
221
323
|
});
|
222
324
|
|
223
|
-
scope.childScopes.forEach(
|
325
|
+
scope.childScopes.forEach(checkReferencesInScope);
|
224
326
|
}
|
225
327
|
|
226
328
|
return {
|
227
329
|
Program() {
|
228
|
-
|
330
|
+
checkReferencesInScope(context.getScope());
|
229
331
|
}
|
230
332
|
};
|
231
333
|
}
|
@@ -49,6 +49,7 @@ function isValidThisArg(expectedThis, thisArg, sourceCode) {
|
|
49
49
|
// Rule Definition
|
50
50
|
//------------------------------------------------------------------------------
|
51
51
|
|
52
|
+
/** @type {import('../shared/types').Rule} */
|
52
53
|
module.exports = {
|
53
54
|
meta: {
|
54
55
|
type: "suggestion",
|
@@ -132,6 +132,7 @@ function isRedundantSuperCall(body, ctorParams) {
|
|
132
132
|
// Rule Definition
|
133
133
|
//------------------------------------------------------------------------------
|
134
134
|
|
135
|
+
/** @type {import('../shared/types').Rule} */
|
135
136
|
module.exports = {
|
136
137
|
meta: {
|
137
138
|
type: "suggestion",
|
package/lib/rules/no-var.js
CHANGED
@@ -179,6 +179,7 @@ function hasNameDisallowedForLetDeclarations(variable) {
|
|
179
179
|
// Rule Definition
|
180
180
|
//------------------------------------------------------------------------------
|
181
181
|
|
182
|
+
/** @type {import('../shared/types').Rule} */
|
182
183
|
module.exports = {
|
183
184
|
meta: {
|
184
185
|
type: "suggestion",
|
package/lib/rules/no-void.js
CHANGED