oxlint-plugin-eslint 1.52.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/LICENSE +22 -0
- package/README.md +36 -0
- package/common/ast-utils.cjs +5843 -0
- package/common/chunk.cjs +9 -0
- package/common/eslint-utils.cjs +1633 -0
- package/common/fix-tracker.cjs +89 -0
- package/common/ignore.cjs +123 -0
- package/common/keywords.cjs +15 -0
- package/common/regexpp.cjs +1720 -0
- package/common/regular-expressions.cjs +40 -0
- package/common/string-utils.cjs +39 -0
- package/index.js +7477 -0
- package/package.json +34 -0
- package/rules/accessor-pairs.cjs +233 -0
- package/rules/array-bracket-newline.cjs +172 -0
- package/rules/array-bracket-spacing.cjs +184 -0
- package/rules/array-callback-return.cjs +262 -0
- package/rules/array-element-newline.cjs +178 -0
- package/rules/arrow-body-style.cjs +135 -0
- package/rules/arrow-parens.cjs +130 -0
- package/rules/arrow-spacing.cjs +129 -0
- package/rules/block-scoped-var.cjs +101 -0
- package/rules/block-spacing.cjs +125 -0
- package/rules/brace-style.cjs +141 -0
- package/rules/callback-return.cjs +117 -0
- package/rules/camelcase.cjs +194 -0
- package/rules/capitalized-comments.cjs +168 -0
- package/rules/class-methods-use-this.cjs +155 -0
- package/rules/comma-dangle.cjs +274 -0
- package/rules/comma-spacing.cjs +111 -0
- package/rules/comma-style.cjs +180 -0
- package/rules/complexity.cjs +100 -0
- package/rules/computed-property-spacing.cjs +155 -0
- package/rules/consistent-return.cjs +113 -0
- package/rules/consistent-this.cjs +109 -0
- package/rules/constructor-super.cjs +207 -0
- package/rules/curly.cjs +173 -0
- package/rules/default-case-last.cjs +36 -0
- package/rules/default-case.cjs +50 -0
- package/rules/default-param-last.cjs +61 -0
- package/rules/dot-location.cjs +87 -0
- package/rules/dot-notation.cjs +77 -0
- package/rules/eol-last.cjs +91 -0
- package/rules/eqeqeq.cjs +127 -0
- package/rules/for-direction.cjs +94 -0
- package/rules/func-call-spacing.cjs +127 -0
- package/rules/func-name-matching.cjs +138 -0
- package/rules/func-names.cjs +121 -0
- package/rules/func-style.cjs +103 -0
- package/rules/function-call-argument-newline.cjs +109 -0
- package/rules/function-paren-newline.cjs +173 -0
- package/rules/generator-star-spacing.cjs +174 -0
- package/rules/getter-return.cjs +129 -0
- package/rules/global-require.cjs +84 -0
- package/rules/grouped-accessor-pairs.cjs +146 -0
- package/rules/guard-for-in.cjs +39 -0
- package/rules/handle-callback-err.cjs +86 -0
- package/rules/id-blacklist.cjs +135 -0
- package/rules/id-denylist.cjs +126 -0
- package/rules/id-length.cjs +119 -0
- package/rules/id-match.cjs +139 -0
- package/rules/implicit-arrow-linebreak.cjs +76 -0
- package/rules/indent-legacy.cjs +520 -0
- package/rules/indent.cjs +842 -0
- package/rules/init-declarations.cjs +88 -0
- package/rules/jsx-quotes.cjs +84 -0
- package/rules/key-spacing.cjs +399 -0
- package/rules/keyword-spacing.cjs +464 -0
- package/rules/line-comment-position.cjs +75 -0
- package/rules/linebreak-style.cjs +89 -0
- package/rules/lines-around-comment.cjs +290 -0
- package/rules/lines-around-directive.cjs +129 -0
- package/rules/lines-between-class-members.cjs +212 -0
- package/rules/logical-assignment-operators.cjs +305 -0
- package/rules/max-classes-per-file.cjs +61 -0
- package/rules/max-depth.cjs +117 -0
- package/rules/max-len.cjs +256 -0
- package/rules/max-lines-per-function.cjs +116 -0
- package/rules/max-lines.cjs +109 -0
- package/rules/max-nested-callbacks.cjs +78 -0
- package/rules/max-params.cjs +78 -0
- package/rules/max-statements-per-line.cjs +147 -0
- package/rules/max-statements.cjs +119 -0
- package/rules/multiline-comment-style.cjs +319 -0
- package/rules/multiline-ternary.cjs +106 -0
- package/rules/new-cap.cjs +139 -0
- package/rules/new-parens.cjs +70 -0
- package/rules/newline-after-var.cjs +159 -0
- package/rules/newline-before-return.cjs +128 -0
- package/rules/newline-per-chained-call.cjs +100 -0
- package/rules/no-alert.cjs +84 -0
- package/rules/no-array-constructor.cjs +91 -0
- package/rules/no-async-promise-executor.cjs +33 -0
- package/rules/no-await-in-loop.cjs +75 -0
- package/rules/no-bitwise.cjs +106 -0
- package/rules/no-buffer-constructor.cjs +51 -0
- package/rules/no-caller.cjs +34 -0
- package/rules/no-case-declarations.cjs +56 -0
- package/rules/no-catch-shadow.cjs +57 -0
- package/rules/no-class-assign.cjs +55 -0
- package/rules/no-compare-neg-zero.cjs +52 -0
- package/rules/no-cond-assign.cjs +104 -0
- package/rules/no-confusing-arrow.cjs +87 -0
- package/rules/no-console.cjs +138 -0
- package/rules/no-const-assign.cjs +50 -0
- package/rules/no-constant-binary-expression.cjs +284 -0
- package/rules/no-constant-condition.cjs +119 -0
- package/rules/no-constructor-return.cjs +43 -0
- package/rules/no-continue.cjs +33 -0
- package/rules/no-control-regex.cjs +74 -0
- package/rules/no-debugger.cjs +33 -0
- package/rules/no-delete-var.cjs +32 -0
- package/rules/no-div-regex.cjs +39 -0
- package/rules/no-dupe-args.cjs +61 -0
- package/rules/no-dupe-class-members.cjs +77 -0
- package/rules/no-dupe-else-if.cjs +74 -0
- package/rules/no-dupe-keys.cjs +88 -0
- package/rules/no-duplicate-case.cjs +49 -0
- package/rules/no-duplicate-imports.cjs +166 -0
- package/rules/no-else-return.cjs +182 -0
- package/rules/no-empty-character-class.cjs +47 -0
- package/rules/no-empty-function.cjs +141 -0
- package/rules/no-empty-pattern.cjs +50 -0
- package/rules/no-empty-static-block.cjs +50 -0
- package/rules/no-empty.cjs +78 -0
- package/rules/no-eq-null.cjs +34 -0
- package/rules/no-eval.cjs +165 -0
- package/rules/no-ex-assign.cjs +45 -0
- package/rules/no-extend-native.cjs +103 -0
- package/rules/no-extra-bind.cjs +127 -0
- package/rules/no-extra-boolean-cast.cjs +159 -0
- package/rules/no-extra-label.cjs +116 -0
- package/rules/no-extra-parens.cjs +665 -0
- package/rules/no-extra-semi.cjs +103 -0
- package/rules/no-fallthrough.cjs +136 -0
- package/rules/no-floating-decimal.cjs +66 -0
- package/rules/no-func-assign.cjs +63 -0
- package/rules/no-global-assign.cjs +62 -0
- package/rules/no-implicit-coercion.cjs +219 -0
- package/rules/no-implicit-globals.cjs +77 -0
- package/rules/no-implied-eval.cjs +87 -0
- package/rules/no-import-assign.cjs +123 -0
- package/rules/no-inline-comments.cjs +57 -0
- package/rules/no-inner-declarations.cjs +82 -0
- package/rules/no-invalid-regexp.cjs +130 -0
- package/rules/no-invalid-this.cjs +90 -0
- package/rules/no-irregular-whitespace.cjs +157 -0
- package/rules/no-iterator.cjs +34 -0
- package/rules/no-label-var.cjs +46 -0
- package/rules/no-labels.cjs +106 -0
- package/rules/no-lone-blocks.cjs +75 -0
- package/rules/no-lonely-if.cjs +42 -0
- package/rules/no-loop-func.cjs +143 -0
- package/rules/no-loss-of-precision.cjs +160 -0
- package/rules/no-magic-numbers.cjs +222 -0
- package/rules/no-misleading-character-class.cjs +500 -0
- package/rules/no-mixed-operators.cjs +197 -0
- package/rules/no-mixed-requires.cjs +117 -0
- package/rules/no-mixed-spaces-and-tabs.cjs +87 -0
- package/rules/no-multi-assign.cjs +38 -0
- package/rules/no-multi-spaces.cjs +95 -0
- package/rules/no-multi-str.cjs +44 -0
- package/rules/no-multiple-empty-lines.cjs +112 -0
- package/rules/no-native-reassign.cjs +72 -0
- package/rules/no-negated-condition.cjs +77 -0
- package/rules/no-negated-in-lhs.cjs +43 -0
- package/rules/no-nested-ternary.cjs +33 -0
- package/rules/no-new-func.cjs +50 -0
- package/rules/no-new-native-nonconstructor.cjs +42 -0
- package/rules/no-new-object.cjs +47 -0
- package/rules/no-new-require.cjs +50 -0
- package/rules/no-new-symbol.cjs +48 -0
- package/rules/no-new-wrappers.cjs +44 -0
- package/rules/no-new.cjs +33 -0
- package/rules/no-nonoctal-decimal-escape.cjs +80 -0
- package/rules/no-obj-calls.cjs +64 -0
- package/rules/no-object-constructor.cjs +69 -0
- package/rules/no-octal-escape.cjs +35 -0
- package/rules/no-octal.cjs +32 -0
- package/rules/no-param-reassign.cjs +135 -0
- package/rules/no-path-concat.cjs +52 -0
- package/rules/no-plusplus.cjs +64 -0
- package/rules/no-process-env.cjs +51 -0
- package/rules/no-process-exit.cjs +50 -0
- package/rules/no-promise-executor-return.cjs +131 -0
- package/rules/no-proto.cjs +34 -0
- package/rules/no-prototype-builtins.cjs +85 -0
- package/rules/no-redeclare.cjs +103 -0
- package/rules/no-regex-spaces.cjs +115 -0
- package/rules/no-restricted-exports.cjs +117 -0
- package/rules/no-restricted-globals.cjs +147 -0
- package/rules/no-restricted-imports.cjs +421 -0
- package/rules/no-restricted-modules.cjs +144 -0
- package/rules/no-restricted-properties.cjs +123 -0
- package/rules/no-restricted-syntax.cjs +49 -0
- package/rules/no-return-assign.cjs +45 -0
- package/rules/no-return-await.cjs +88 -0
- package/rules/no-script-url.cjs +49 -0
- package/rules/no-self-assign.cjs +88 -0
- package/rules/no-self-compare.cjs +53 -0
- package/rules/no-sequences.cjs +81 -0
- package/rules/no-setter-return.cjs +110 -0
- package/rules/no-shadow-restricted-names.cjs +60 -0
- package/rules/no-shadow.cjs +302 -0
- package/rules/no-spaced-func.cjs +69 -0
- package/rules/no-sparse-arrays.cjs +40 -0
- package/rules/no-sync.cjs +58 -0
- package/rules/no-tabs.cjs +73 -0
- package/rules/no-template-curly-in-string.cjs +33 -0
- package/rules/no-ternary.cjs +33 -0
- package/rules/no-this-before-super.cjs +177 -0
- package/rules/no-throw-literal.cjs +40 -0
- package/rules/no-trailing-spaces.cjs +123 -0
- package/rules/no-unassigned-vars.cjs +54 -0
- package/rules/no-undef-init.cjs +46 -0
- package/rules/no-undef.cjs +51 -0
- package/rules/no-undefined.cjs +58 -0
- package/rules/no-underscore-dangle.cjs +211 -0
- package/rules/no-unexpected-multiline.cjs +76 -0
- package/rules/no-unmodified-loop-condition.cjs +849 -0
- package/rules/no-unneeded-ternary.cjs +112 -0
- package/rules/no-unreachable-loop.cjs +128 -0
- package/rules/no-unreachable.cjs +195 -0
- package/rules/no-unsafe-finally.cjs +67 -0
- package/rules/no-unsafe-negation.cjs +86 -0
- package/rules/no-unsafe-optional-chaining.cjs +164 -0
- package/rules/no-unused-expressions.cjs +163 -0
- package/rules/no-unused-labels.cjs +97 -0
- package/rules/no-unused-private-class-members.cjs +69 -0
- package/rules/no-unused-vars.cjs +639 -0
- package/rules/no-use-before-define.cjs +245 -0
- package/rules/no-useless-assignment.cjs +250 -0
- package/rules/no-useless-backreference.cjs +137 -0
- package/rules/no-useless-call.cjs +57 -0
- package/rules/no-useless-catch.cjs +38 -0
- package/rules/no-useless-computed-key.cjs +106 -0
- package/rules/no-useless-concat.cjs +78 -0
- package/rules/no-useless-constructor.cjs +152 -0
- package/rules/no-useless-escape.cjs +164 -0
- package/rules/no-useless-rename.cjs +94 -0
- package/rules/no-useless-return.cjs +229 -0
- package/rules/no-var.cjs +235 -0
- package/rules/no-void.cjs +39 -0
- package/rules/no-warning-comments.cjs +112 -0
- package/rules/no-whitespace-before-property.cjs +72 -0
- package/rules/no-with.cjs +32 -0
- package/rules/nonblock-statement-body-position.cjs +107 -0
- package/rules/object-curly-newline.cjs +194 -0
- package/rules/object-curly-spacing.cjs +225 -0
- package/rules/object-property-newline.cjs +81 -0
- package/rules/object-shorthand.cjs +284 -0
- package/rules/one-var-declaration-per-line.cjs +75 -0
- package/rules/one-var.cjs +378 -0
- package/rules/operator-assignment.cjs +146 -0
- package/rules/operator-linebreak.cjs +150 -0
- package/rules/padded-blocks.cjs +192 -0
- package/rules/padding-line-between-statements.cjs +377 -0
- package/rules/prefer-arrow-callback.cjs +185 -0
- package/rules/prefer-const.cjs +240 -0
- package/rules/prefer-destructuring.cjs +188 -0
- package/rules/prefer-exponentiation-operator.cjs +100 -0
- package/rules/prefer-named-capture-group.cjs +111 -0
- package/rules/prefer-numeric-literals.cjs +75 -0
- package/rules/prefer-object-has-own.cjs +54 -0
- package/rules/prefer-object-spread.cjs +170 -0
- package/rules/prefer-promise-reject-errors.cjs +62 -0
- package/rules/prefer-reflect.cjs +100 -0
- package/rules/prefer-regex-literals.cjs +256 -0
- package/rules/prefer-rest-params.cjs +80 -0
- package/rules/prefer-spread.cjs +57 -0
- package/rules/prefer-template.cjs +147 -0
- package/rules/preserve-caught-error.cjs +196 -0
- package/rules/quote-props.cjs +224 -0
- package/rules/quotes.cjs +187 -0
- package/rules/radix.cjs +124 -0
- package/rules/require-atomic-updates.cjs +197 -0
- package/rules/require-await.cjs +90 -0
- package/rules/require-unicode-regexp.cjs +101 -0
- package/rules/require-yield.cjs +56 -0
- package/rules/rest-spread-spacing.cjs +99 -0
- package/rules/semi-spacing.cjs +215 -0
- package/rules/semi-style.cjs +116 -0
- package/rules/semi.cjs +239 -0
- package/rules/sort-imports.cjs +140 -0
- package/rules/sort-keys.cjs +165 -0
- package/rules/sort-vars.cjs +50 -0
- package/rules/space-before-blocks.cjs +132 -0
- package/rules/space-before-function-paren.cjs +126 -0
- package/rules/space-in-parens.cjs +175 -0
- package/rules/space-infix-ops.cjs +133 -0
- package/rules/space-unary-ops.cjs +237 -0
- package/rules/spaced-comment.cjs +233 -0
- package/rules/strict.cjs +206 -0
- package/rules/switch-colon-spacing.cjs +114 -0
- package/rules/symbol-description.cjs +49 -0
- package/rules/template-curly-spacing.cjs +112 -0
- package/rules/template-tag-spacing.cjs +82 -0
- package/rules/unicode-bom.cjs +52 -0
- package/rules/use-isnan.cjs +144 -0
- package/rules/valid-typeof.cjs +104 -0
- package/rules/vars-on-top.cjs +94 -0
- package/rules/wrap-iife.cjs +131 -0
- package/rules/wrap-regex.cjs +57 -0
- package/rules/yield-star-spacing.cjs +115 -0
- package/rules/yoda.cjs +185 -0
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
const require_chunk = require("../common/chunk.cjs"), require_ast_utils$1 = require("../common/ast-utils.cjs");
|
|
2
|
+
//#region ../../node_modules/.pnpm/eslint@9.39.3_jiti@2.6.1/node_modules/eslint/lib/rules/no-unused-vars.js
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Rule to flag declared but unused variables
|
|
5
|
+
* @author Ilya Volodin
|
|
6
|
+
*/
|
|
7
|
+
var require_no_unused_vars = /* @__PURE__ */ require_chunk.t(((exports, module) => {
|
|
8
|
+
let astUtils = require_ast_utils$1.t();
|
|
9
|
+
/**
|
|
10
|
+
* A simple name for the types of variables that this rule supports
|
|
11
|
+
* @typedef {'array-destructure'|'catch-clause'|'parameter'|'variable'} VariableType
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Bag of data used for formatting the `unusedVar` lint message.
|
|
15
|
+
* @typedef {Object} UnusedVarMessageData
|
|
16
|
+
* @property {string} varName The name of the unused var.
|
|
17
|
+
* @property {'defined'|'assigned a value'} action Description of the vars state.
|
|
18
|
+
* @property {string} additional Any additional info to be appended at the end.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Bag of data used for formatting the `usedIgnoredVar` lint message.
|
|
22
|
+
* @typedef {Object} UsedIgnoredVarMessageData
|
|
23
|
+
* @property {string} varName The name of the unused var.
|
|
24
|
+
* @property {string} additional Any additional info to be appended at the end.
|
|
25
|
+
*/
|
|
26
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
27
|
+
module.exports = {
|
|
28
|
+
meta: {
|
|
29
|
+
type: "problem",
|
|
30
|
+
docs: {
|
|
31
|
+
description: "Disallow unused variables",
|
|
32
|
+
recommended: !0,
|
|
33
|
+
url: "https://eslint.org/docs/latest/rules/no-unused-vars"
|
|
34
|
+
},
|
|
35
|
+
hasSuggestions: !0,
|
|
36
|
+
schema: [{ oneOf: [{ enum: ["all", "local"] }, {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
vars: { enum: ["all", "local"] },
|
|
40
|
+
varsIgnorePattern: { type: "string" },
|
|
41
|
+
args: { enum: [
|
|
42
|
+
"all",
|
|
43
|
+
"after-used",
|
|
44
|
+
"none"
|
|
45
|
+
] },
|
|
46
|
+
ignoreRestSiblings: { type: "boolean" },
|
|
47
|
+
argsIgnorePattern: { type: "string" },
|
|
48
|
+
caughtErrors: { enum: ["all", "none"] },
|
|
49
|
+
caughtErrorsIgnorePattern: { type: "string" },
|
|
50
|
+
destructuredArrayIgnorePattern: { type: "string" },
|
|
51
|
+
ignoreClassWithStaticInitBlock: { type: "boolean" },
|
|
52
|
+
ignoreUsingDeclarations: { type: "boolean" },
|
|
53
|
+
reportUsedIgnorePattern: { type: "boolean" }
|
|
54
|
+
},
|
|
55
|
+
additionalProperties: !1
|
|
56
|
+
}] }],
|
|
57
|
+
messages: {
|
|
58
|
+
unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}.",
|
|
59
|
+
usedIgnoredVar: "'{{varName}}' is marked as ignored but is used{{additional}}.",
|
|
60
|
+
removeVar: "Remove unused variable '{{varName}}'."
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
create(context) {
|
|
64
|
+
let sourceCode = context.sourceCode, REST_PROPERTY_TYPE = /^(?:RestElement|(?:Experimental)?RestProperty)$/u, config = {
|
|
65
|
+
vars: "all",
|
|
66
|
+
args: "after-used",
|
|
67
|
+
ignoreRestSiblings: !1,
|
|
68
|
+
caughtErrors: "all",
|
|
69
|
+
ignoreClassWithStaticInitBlock: !1,
|
|
70
|
+
ignoreUsingDeclarations: !1,
|
|
71
|
+
reportUsedIgnorePattern: !1
|
|
72
|
+
}, firstOption = context.options[0];
|
|
73
|
+
firstOption && (typeof firstOption == "string" ? config.vars = firstOption : (config.vars = firstOption.vars || config.vars, config.args = firstOption.args || config.args, config.ignoreRestSiblings = firstOption.ignoreRestSiblings || config.ignoreRestSiblings, config.caughtErrors = firstOption.caughtErrors || config.caughtErrors, config.ignoreClassWithStaticInitBlock = firstOption.ignoreClassWithStaticInitBlock || config.ignoreClassWithStaticInitBlock, config.ignoreUsingDeclarations = firstOption.ignoreUsingDeclarations || config.ignoreUsingDeclarations, config.reportUsedIgnorePattern = firstOption.reportUsedIgnorePattern || config.reportUsedIgnorePattern, firstOption.varsIgnorePattern && (config.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern, "u")), firstOption.argsIgnorePattern && (config.argsIgnorePattern = new RegExp(firstOption.argsIgnorePattern, "u")), firstOption.caughtErrorsIgnorePattern && (config.caughtErrorsIgnorePattern = new RegExp(firstOption.caughtErrorsIgnorePattern, "u")), firstOption.destructuredArrayIgnorePattern && (config.destructuredArrayIgnorePattern = new RegExp(firstOption.destructuredArrayIgnorePattern, "u"))));
|
|
74
|
+
/**
|
|
75
|
+
* Determines what variable type a def is.
|
|
76
|
+
* @param {Object} def the declaration to check
|
|
77
|
+
* @returns {VariableType} a simple name for the types of variables that this rule supports
|
|
78
|
+
*/
|
|
79
|
+
function defToVariableType(def) {
|
|
80
|
+
if (config.destructuredArrayIgnorePattern && def.name.parent.type === "ArrayPattern") return "array-destructure";
|
|
81
|
+
switch (def.type) {
|
|
82
|
+
case "CatchClause": return "catch-clause";
|
|
83
|
+
case "Parameter": return "parameter";
|
|
84
|
+
default: return "variable";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Gets a given variable's description and configured ignore pattern
|
|
89
|
+
* based on the provided variableType
|
|
90
|
+
* @param {VariableType} variableType a simple name for the types of variables that this rule supports
|
|
91
|
+
* @throws {Error} (Unreachable)
|
|
92
|
+
* @returns {[string | undefined, string | undefined]} the given variable's description and
|
|
93
|
+
* ignore pattern
|
|
94
|
+
*/
|
|
95
|
+
function getVariableDescription(variableType) {
|
|
96
|
+
let pattern, variableDescription;
|
|
97
|
+
switch (variableType) {
|
|
98
|
+
case "array-destructure":
|
|
99
|
+
pattern = config.destructuredArrayIgnorePattern, variableDescription = "elements of array destructuring";
|
|
100
|
+
break;
|
|
101
|
+
case "catch-clause":
|
|
102
|
+
pattern = config.caughtErrorsIgnorePattern, variableDescription = "caught errors";
|
|
103
|
+
break;
|
|
104
|
+
case "parameter":
|
|
105
|
+
pattern = config.argsIgnorePattern, variableDescription = "args";
|
|
106
|
+
break;
|
|
107
|
+
case "variable":
|
|
108
|
+
pattern = config.varsIgnorePattern, variableDescription = "vars";
|
|
109
|
+
break;
|
|
110
|
+
default: throw Error(`Unexpected variable type: ${variableType}`);
|
|
111
|
+
}
|
|
112
|
+
return pattern &&= pattern.toString(), [variableDescription, pattern];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Generates the message data about the variable being defined and unused,
|
|
116
|
+
* including the ignore pattern if configured.
|
|
117
|
+
* @param {Variable} unusedVar eslint-scope variable object.
|
|
118
|
+
* @returns {UnusedVarMessageData} The message data to be used with this unused variable.
|
|
119
|
+
*/
|
|
120
|
+
function getDefinedMessageData(unusedVar) {
|
|
121
|
+
let def = unusedVar.defs && unusedVar.defs[0], additionalMessageData = "";
|
|
122
|
+
if (def) {
|
|
123
|
+
let [variableDescription, pattern] = getVariableDescription(defToVariableType(def));
|
|
124
|
+
pattern && variableDescription && (additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`);
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
varName: unusedVar.name,
|
|
128
|
+
action: "defined",
|
|
129
|
+
additional: additionalMessageData
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Generate the warning message about the variable being
|
|
134
|
+
* assigned and unused, including the ignore pattern if configured.
|
|
135
|
+
* @param {Variable} unusedVar eslint-scope variable object.
|
|
136
|
+
* @returns {UnusedVarMessageData} The message data to be used with this unused variable.
|
|
137
|
+
*/
|
|
138
|
+
function getAssignedMessageData(unusedVar) {
|
|
139
|
+
let def = unusedVar.defs && unusedVar.defs[0], additionalMessageData = "";
|
|
140
|
+
if (def) {
|
|
141
|
+
let [variableDescription, pattern] = getVariableDescription(defToVariableType(def));
|
|
142
|
+
pattern && variableDescription && (additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`);
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
varName: unusedVar.name,
|
|
146
|
+
action: "assigned a value",
|
|
147
|
+
additional: additionalMessageData
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Generate the warning message about a variable being used even though
|
|
152
|
+
* it is marked as being ignored.
|
|
153
|
+
* @param {Variable} variable eslint-scope variable object
|
|
154
|
+
* @param {VariableType} variableType a simple name for the types of variables that this rule supports
|
|
155
|
+
* @returns {UsedIgnoredVarMessageData} The message data to be used with
|
|
156
|
+
* this used ignored variable.
|
|
157
|
+
*/
|
|
158
|
+
function getUsedIgnoredMessageData(variable, variableType) {
|
|
159
|
+
let [variableDescription, pattern] = getVariableDescription(variableType), additionalMessageData = "";
|
|
160
|
+
return pattern && variableDescription && (additionalMessageData = `. Used ${variableDescription} must not match ${pattern}`), {
|
|
161
|
+
varName: variable.name,
|
|
162
|
+
additional: additionalMessageData
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
let STATEMENT_TYPE = /(?:Statement|Declaration)$/u;
|
|
166
|
+
/**
|
|
167
|
+
* Determines if a given variable is being exported from a module.
|
|
168
|
+
* @param {Variable} variable eslint-scope variable object.
|
|
169
|
+
* @returns {boolean} True if the variable is exported, false if not.
|
|
170
|
+
* @private
|
|
171
|
+
*/
|
|
172
|
+
function isExported(variable) {
|
|
173
|
+
let definition = variable.defs[0];
|
|
174
|
+
if (definition) {
|
|
175
|
+
let node = definition.node;
|
|
176
|
+
if (node.type === "VariableDeclarator") node = node.parent;
|
|
177
|
+
else if (definition.type === "Parameter") return !1;
|
|
178
|
+
return node.parent.type.indexOf("Export") === 0;
|
|
179
|
+
}
|
|
180
|
+
return !1;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Determines if a given variable uses the explicit resource management protocol.
|
|
184
|
+
* @param {Variable} variable eslint-scope variable object.
|
|
185
|
+
* @returns {boolean} True if the variable is declared with "using" or "await using"
|
|
186
|
+
* @private
|
|
187
|
+
*/
|
|
188
|
+
function usesExplicitResourceManagement(variable) {
|
|
189
|
+
let [definition] = variable.defs;
|
|
190
|
+
return definition?.type === "Variable" && (definition.parent.kind === "using" || definition.parent.kind === "await using");
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Checks whether a node is a sibling of the rest property or not.
|
|
194
|
+
* @param {ASTNode} node a node to check
|
|
195
|
+
* @returns {boolean} True if the node is a sibling of the rest property, otherwise false.
|
|
196
|
+
*/
|
|
197
|
+
function hasRestSibling(node) {
|
|
198
|
+
return node.type === "Property" && node.parent.type === "ObjectPattern" && REST_PROPERTY_TYPE.test(node.parent.properties.at(-1).type);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Determines if a variable has a sibling rest property
|
|
202
|
+
* @param {Variable} variable eslint-scope variable object.
|
|
203
|
+
* @returns {boolean} True if the variable has a sibling rest property, false if not.
|
|
204
|
+
* @private
|
|
205
|
+
*/
|
|
206
|
+
function hasRestSpreadSibling(variable) {
|
|
207
|
+
if (config.ignoreRestSiblings) {
|
|
208
|
+
let hasRestSiblingDefinition = variable.defs.some((def) => hasRestSibling(def.name.parent)), hasRestSiblingReference = variable.references.some((ref) => hasRestSibling(ref.identifier.parent));
|
|
209
|
+
return hasRestSiblingDefinition || hasRestSiblingReference;
|
|
210
|
+
}
|
|
211
|
+
return !1;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Determines if a reference is a read operation.
|
|
215
|
+
* @param {Reference} ref An eslint-scope Reference
|
|
216
|
+
* @returns {boolean} whether the given reference represents a read operation
|
|
217
|
+
* @private
|
|
218
|
+
*/
|
|
219
|
+
function isReadRef(ref) {
|
|
220
|
+
return ref.isRead();
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Determine if an identifier is referencing an enclosing function name.
|
|
224
|
+
* @param {Reference} ref The reference to check.
|
|
225
|
+
* @param {ASTNode[]} nodes The candidate function nodes.
|
|
226
|
+
* @returns {boolean} True if it's a self-reference, false if not.
|
|
227
|
+
* @private
|
|
228
|
+
*/
|
|
229
|
+
function isSelfReference(ref, nodes) {
|
|
230
|
+
let scope = ref.from;
|
|
231
|
+
for (; scope;) {
|
|
232
|
+
if (nodes.includes(scope.block)) return !0;
|
|
233
|
+
scope = scope.upper;
|
|
234
|
+
}
|
|
235
|
+
return !1;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Gets a list of function definitions for a specified variable.
|
|
239
|
+
* @param {Variable} variable eslint-scope variable object.
|
|
240
|
+
* @returns {ASTNode[]} Function nodes.
|
|
241
|
+
* @private
|
|
242
|
+
*/
|
|
243
|
+
function getFunctionDefinitions(variable) {
|
|
244
|
+
let functionDefinitions = [];
|
|
245
|
+
return variable.defs.forEach((def) => {
|
|
246
|
+
let { type, node } = def;
|
|
247
|
+
type === "FunctionName" && functionDefinitions.push(node), type === "Variable" && node.init && (node.init.type === "FunctionExpression" || node.init.type === "ArrowFunctionExpression") && functionDefinitions.push(node.init);
|
|
248
|
+
}), functionDefinitions;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Checks the position of given nodes.
|
|
252
|
+
* @param {ASTNode} inner A node which is expected as inside.
|
|
253
|
+
* @param {ASTNode} outer A node which is expected as outside.
|
|
254
|
+
* @returns {boolean} `true` if the `inner` node exists in the `outer` node.
|
|
255
|
+
* @private
|
|
256
|
+
*/
|
|
257
|
+
function isInside(inner, outer) {
|
|
258
|
+
return inner.range[0] >= outer.range[0] && inner.range[1] <= outer.range[1];
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Checks whether a given node is unused expression or not.
|
|
262
|
+
* @param {ASTNode} node The node itself
|
|
263
|
+
* @returns {boolean} The node is an unused expression.
|
|
264
|
+
* @private
|
|
265
|
+
*/
|
|
266
|
+
function isUnusedExpression(node) {
|
|
267
|
+
let parent = node.parent;
|
|
268
|
+
return parent.type === "ExpressionStatement" ? !0 : parent.type === "SequenceExpression" ? parent.expressions.at(-1) === node ? isUnusedExpression(parent) : !0 : !1;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* If a given reference is left-hand side of an assignment, this gets
|
|
272
|
+
* the right-hand side node of the assignment.
|
|
273
|
+
*
|
|
274
|
+
* In the following cases, this returns null.
|
|
275
|
+
*
|
|
276
|
+
* - The reference is not the LHS of an assignment expression.
|
|
277
|
+
* - The reference is inside of a loop.
|
|
278
|
+
* - The reference is inside of a function scope which is different from
|
|
279
|
+
* the declaration.
|
|
280
|
+
* @param {eslint-scope.Reference} ref A reference to check.
|
|
281
|
+
* @param {ASTNode} prevRhsNode The previous RHS node.
|
|
282
|
+
* @returns {ASTNode|null} The RHS node or null.
|
|
283
|
+
* @private
|
|
284
|
+
*/
|
|
285
|
+
function getRhsNode(ref, prevRhsNode) {
|
|
286
|
+
let id = ref.identifier, parent = id.parent, canBeUsedLater = ref.from.variableScope !== ref.resolved.scope.variableScope || astUtils.isInLoop(id);
|
|
287
|
+
return prevRhsNode && isInside(id, prevRhsNode) ? prevRhsNode : parent.type === "AssignmentExpression" && isUnusedExpression(parent) && id === parent.left && !canBeUsedLater ? parent.right : null;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Checks whether a given function node is stored to somewhere or not.
|
|
291
|
+
* If the function node is stored, the function can be used later.
|
|
292
|
+
* @param {ASTNode} funcNode A function node to check.
|
|
293
|
+
* @param {ASTNode} rhsNode The RHS node of the previous assignment.
|
|
294
|
+
* @returns {boolean} `true` if under the following conditions:
|
|
295
|
+
* - the funcNode is assigned to a variable.
|
|
296
|
+
* - the funcNode is bound as an argument of a function call.
|
|
297
|
+
* - the function is bound to a property and the object satisfies above conditions.
|
|
298
|
+
* @private
|
|
299
|
+
*/
|
|
300
|
+
function isStorableFunction(funcNode, rhsNode) {
|
|
301
|
+
let node = funcNode, parent = funcNode.parent;
|
|
302
|
+
for (; parent && isInside(parent, rhsNode);) {
|
|
303
|
+
switch (parent.type) {
|
|
304
|
+
case "SequenceExpression":
|
|
305
|
+
if (parent.expressions.at(-1) !== node) return !1;
|
|
306
|
+
break;
|
|
307
|
+
case "CallExpression":
|
|
308
|
+
case "NewExpression": return parent.callee !== node;
|
|
309
|
+
case "AssignmentExpression":
|
|
310
|
+
case "TaggedTemplateExpression":
|
|
311
|
+
case "YieldExpression": return !0;
|
|
312
|
+
default: if (STATEMENT_TYPE.test(parent.type)) return !0;
|
|
313
|
+
}
|
|
314
|
+
node = parent, parent = parent.parent;
|
|
315
|
+
}
|
|
316
|
+
return !1;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Checks whether a given Identifier node exists inside of a function node which can be used later.
|
|
320
|
+
*
|
|
321
|
+
* "can be used later" means:
|
|
322
|
+
* - the function is assigned to a variable.
|
|
323
|
+
* - the function is bound to a property and the object can be used later.
|
|
324
|
+
* - the function is bound as an argument of a function call.
|
|
325
|
+
*
|
|
326
|
+
* If a reference exists in a function which can be used later, the reference is read when the function is called.
|
|
327
|
+
* @param {ASTNode} id An Identifier node to check.
|
|
328
|
+
* @param {ASTNode} rhsNode The RHS node of the previous assignment.
|
|
329
|
+
* @returns {boolean} `true` if the `id` node exists inside of a function node which can be used later.
|
|
330
|
+
* @private
|
|
331
|
+
*/
|
|
332
|
+
function isInsideOfStorableFunction(id, rhsNode) {
|
|
333
|
+
let funcNode = astUtils.getUpperFunction(id);
|
|
334
|
+
return funcNode && isInside(funcNode, rhsNode) && isStorableFunction(funcNode, rhsNode);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Checks whether a given reference is a read to update itself or not.
|
|
338
|
+
* @param {eslint-scope.Reference} ref A reference to check.
|
|
339
|
+
* @param {ASTNode} rhsNode The RHS node of the previous assignment.
|
|
340
|
+
* @returns {boolean} The reference is a read to update itself.
|
|
341
|
+
* @private
|
|
342
|
+
*/
|
|
343
|
+
function isReadForItself(ref, rhsNode) {
|
|
344
|
+
let id = ref.identifier, parent = id.parent;
|
|
345
|
+
return ref.isRead() && (parent.type === "AssignmentExpression" && parent.left === id && isUnusedExpression(parent) && !astUtils.isLogicalAssignmentOperator(parent.operator) || parent.type === "UpdateExpression" && isUnusedExpression(parent) || rhsNode && isInside(id, rhsNode) && !isInsideOfStorableFunction(id, rhsNode));
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Determine if an identifier is used either in for-in or for-of loops.
|
|
349
|
+
* @param {Reference} ref The reference to check.
|
|
350
|
+
* @returns {boolean} whether reference is used in the for-in loops
|
|
351
|
+
* @private
|
|
352
|
+
*/
|
|
353
|
+
function isForInOfRef(ref) {
|
|
354
|
+
let target = ref.identifier.parent;
|
|
355
|
+
return target.type === "VariableDeclarator" && (target = target.parent.parent), target.type !== "ForInStatement" && target.type !== "ForOfStatement" || (target = target.body.type === "BlockStatement" ? target.body.body[0] : target.body, !target) ? !1 : target.type === "ReturnStatement";
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Determines if the variable is used.
|
|
359
|
+
* @param {Variable} variable The variable to check.
|
|
360
|
+
* @returns {boolean} True if the variable is used
|
|
361
|
+
* @private
|
|
362
|
+
*/
|
|
363
|
+
function isUsedVariable(variable) {
|
|
364
|
+
if (variable.eslintUsed) return !0;
|
|
365
|
+
let functionNodes = getFunctionDefinitions(variable), isFunctionDefinition = functionNodes.length > 0, rhsNode = null;
|
|
366
|
+
return variable.references.some((ref) => {
|
|
367
|
+
if (isForInOfRef(ref)) return !0;
|
|
368
|
+
let forItself = isReadForItself(ref, rhsNode);
|
|
369
|
+
return rhsNode = getRhsNode(ref, rhsNode), isReadRef(ref) && !forItself && !(isFunctionDefinition && isSelfReference(ref, functionNodes));
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Checks whether the given variable is after the last used parameter.
|
|
374
|
+
* @param {eslint-scope.Variable} variable The variable to check.
|
|
375
|
+
* @returns {boolean} `true` if the variable is defined after the last
|
|
376
|
+
* used parameter.
|
|
377
|
+
*/
|
|
378
|
+
function isAfterLastUsedArg(variable) {
|
|
379
|
+
let def = variable.defs[0], params = sourceCode.getDeclaredVariables(def.node);
|
|
380
|
+
return !params.slice(params.indexOf(variable) + 1).some((v) => v.references.length > 0 || v.eslintUsed);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Gets an array of variables without read references.
|
|
384
|
+
* @param {Scope} scope an eslint-scope Scope object.
|
|
385
|
+
* @param {Variable[]} unusedVars an array that saving result.
|
|
386
|
+
* @returns {Variable[]} unused variables of the scope and descendant scopes.
|
|
387
|
+
* @private
|
|
388
|
+
*/
|
|
389
|
+
function collectUnusedVariables(scope, unusedVars) {
|
|
390
|
+
let variables = scope.variables, childScopes = scope.childScopes, i, l;
|
|
391
|
+
if (scope.type !== "global" || config.vars === "all") for (i = 0, l = variables.length; i < l; ++i) {
|
|
392
|
+
let variable = variables[i];
|
|
393
|
+
if (scope.type === "class" && scope.block.id === variable.identifiers[0] || scope.functionExpressionScope || !config.reportUsedIgnorePattern && variable.eslintUsed || scope.type === "function" && variable.name === "arguments" && variable.identifiers.length === 0) continue;
|
|
394
|
+
let def = variable.defs[0];
|
|
395
|
+
if (def) {
|
|
396
|
+
let type = def.type, refUsedInArrayPatterns = variable.references.some((ref) => ref.identifier.parent.type === "ArrayPattern");
|
|
397
|
+
if ((def.name.parent.type === "ArrayPattern" || refUsedInArrayPatterns) && config.destructuredArrayIgnorePattern && config.destructuredArrayIgnorePattern.test(def.name.name)) {
|
|
398
|
+
config.reportUsedIgnorePattern && isUsedVariable(variable) && context.report({
|
|
399
|
+
node: def.name,
|
|
400
|
+
messageId: "usedIgnoredVar",
|
|
401
|
+
data: getUsedIgnoredMessageData(variable, "array-destructure")
|
|
402
|
+
});
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (type === "ClassName") {
|
|
406
|
+
let hasStaticBlock = def.node.body.body.some((node) => node.type === "StaticBlock");
|
|
407
|
+
if (config.ignoreClassWithStaticInitBlock && hasStaticBlock) continue;
|
|
408
|
+
}
|
|
409
|
+
if (type === "CatchClause") {
|
|
410
|
+
if (config.caughtErrors === "none") continue;
|
|
411
|
+
if (config.caughtErrorsIgnorePattern && config.caughtErrorsIgnorePattern.test(def.name.name)) {
|
|
412
|
+
config.reportUsedIgnorePattern && isUsedVariable(variable) && context.report({
|
|
413
|
+
node: def.name,
|
|
414
|
+
messageId: "usedIgnoredVar",
|
|
415
|
+
data: getUsedIgnoredMessageData(variable, "catch-clause")
|
|
416
|
+
});
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
} else if (type === "Parameter") {
|
|
420
|
+
if ((def.node.parent.type === "Property" || def.node.parent.type === "MethodDefinition") && def.node.parent.kind === "set" || config.args === "none") continue;
|
|
421
|
+
if (config.argsIgnorePattern && config.argsIgnorePattern.test(def.name.name)) {
|
|
422
|
+
config.reportUsedIgnorePattern && isUsedVariable(variable) && context.report({
|
|
423
|
+
node: def.name,
|
|
424
|
+
messageId: "usedIgnoredVar",
|
|
425
|
+
data: getUsedIgnoredMessageData(variable, "parameter")
|
|
426
|
+
});
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (config.args === "after-used" && astUtils.isFunction(def.name.parent) && !isAfterLastUsedArg(variable)) continue;
|
|
430
|
+
} else if (config.varsIgnorePattern && config.varsIgnorePattern.test(def.name.name)) {
|
|
431
|
+
config.reportUsedIgnorePattern && isUsedVariable(variable) && context.report({
|
|
432
|
+
node: def.name,
|
|
433
|
+
messageId: "usedIgnoredVar",
|
|
434
|
+
data: getUsedIgnoredMessageData(variable, "variable")
|
|
435
|
+
});
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
!isUsedVariable(variable) && !isExported(variable) && !(config.ignoreUsingDeclarations && usesExplicitResourceManagement(variable)) && !hasRestSpreadSibling(variable) && unusedVars.push(variable);
|
|
440
|
+
}
|
|
441
|
+
for (i = 0, l = childScopes.length; i < l; ++i) collectUnusedVariables(childScopes[i], unusedVars);
|
|
442
|
+
return unusedVars;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* fixes unused variables
|
|
446
|
+
* @param {Object} fixer fixer object
|
|
447
|
+
* @param {Object} unusedVar unused variable to fix
|
|
448
|
+
* @returns {Object} fixer object
|
|
449
|
+
*/
|
|
450
|
+
function handleFixes(fixer, unusedVar) {
|
|
451
|
+
let id = unusedVar.identifiers[0], parent = id.parent, parentType = parent.type, tokenBefore = sourceCode.getTokenBefore(id), tokenAfter = sourceCode.getTokenAfter(id), isFunction = astUtils.isFunction, isLoop = astUtils.isLoop, allWriteReferences = unusedVar.references.filter((ref) => ref.isWrite());
|
|
452
|
+
/**
|
|
453
|
+
* get range from token before of a given node
|
|
454
|
+
* @param {ASTNode} node node of identifier
|
|
455
|
+
* @param {number} skips number of token to skip
|
|
456
|
+
* @returns {number} start range of token before the identifier
|
|
457
|
+
*/
|
|
458
|
+
function getPreviousTokenStart(node, skips) {
|
|
459
|
+
return sourceCode.getTokenBefore(node, skips).range[0];
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* get range to token after of a given node
|
|
463
|
+
* @param {ASTNode} node node of identifier
|
|
464
|
+
* @param {number} skips number of token to skip
|
|
465
|
+
* @returns {number} end range of token after the identifier
|
|
466
|
+
*/
|
|
467
|
+
function getNextTokenEnd(node, skips) {
|
|
468
|
+
return sourceCode.getTokenAfter(node, skips).range[1];
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* get the value of token before of a given node
|
|
472
|
+
* @param {ASTNode} node node of identifier
|
|
473
|
+
* @returns {string} value of token before the identifier
|
|
474
|
+
*/
|
|
475
|
+
function getTokenBeforeValue(node) {
|
|
476
|
+
return sourceCode.getTokenBefore(node).value;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* get the value of token after of a given node
|
|
480
|
+
* @param {ASTNode} node node of identifier
|
|
481
|
+
* @returns {string} value of token after the identifier
|
|
482
|
+
*/
|
|
483
|
+
function getTokenAfterValue(node) {
|
|
484
|
+
return sourceCode.getTokenAfter(node).value;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Check if an array has a single element with null as other element.
|
|
488
|
+
* @param {ASTNode} node ArrayPattern node
|
|
489
|
+
* @returns {boolean} true if array has single element with other null elements
|
|
490
|
+
*/
|
|
491
|
+
function hasSingleElement(node) {
|
|
492
|
+
return node.elements.filter((e) => e !== null).length === 1;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* check whether import specifier has an import of particular type
|
|
496
|
+
* @param {ASTNode} node ImportDeclaration node
|
|
497
|
+
* @param {string} type type of import to check
|
|
498
|
+
* @returns {boolean} true if import specifier has import of specified type
|
|
499
|
+
*/
|
|
500
|
+
function hasImportOfCertainType(node, type) {
|
|
501
|
+
return node.specifiers.some((e) => e.type === type);
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Check whether declaration is safe to remove or not
|
|
505
|
+
* @param {ASTNode} nextToken next token of unused variable
|
|
506
|
+
* @param {ASTNode} prevToken previous token of unused variable
|
|
507
|
+
* @returns {boolean} true if declaration is not safe to remove
|
|
508
|
+
*/
|
|
509
|
+
function isDeclarationNotSafeToRemove(nextToken, prevToken) {
|
|
510
|
+
return nextToken.type === "String" || prevToken && !astUtils.isSemicolonToken(prevToken) && !astUtils.isOpeningBraceToken(prevToken);
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* give fixes for unused variables in function parameters
|
|
514
|
+
* @param {ASTNode} node node to check
|
|
515
|
+
* @returns {Object} fixer object
|
|
516
|
+
*/
|
|
517
|
+
function fixFunctionParameters(node) {
|
|
518
|
+
let parentNode = node.parent;
|
|
519
|
+
return isFunction(parentNode) ? parentNode.params.length === 1 ? fixer.removeRange(node.range) : getTokenBeforeValue(node) === "(" && getTokenAfterValue(node) === "," ? fixer.removeRange([node.range[0], getNextTokenEnd(node)]) : fixer.removeRange([getPreviousTokenStart(node), node.range[1]]) : null;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* fix unused variable declarations and function parameters
|
|
523
|
+
* @param {ASTNode} node parent node to identifier
|
|
524
|
+
* @returns {Object} fixer object
|
|
525
|
+
*/
|
|
526
|
+
function fixVariables(node) {
|
|
527
|
+
let parentNode = node.parent;
|
|
528
|
+
if (parentNode.type === "VariableDeclarator") {
|
|
529
|
+
if (isLoop(parentNode.parent.parent)) return null;
|
|
530
|
+
if (parentNode.parent.declarations.length === 1) {
|
|
531
|
+
let nextToken = sourceCode.getTokenAfter(parentNode.parent), prevToken = sourceCode.getTokenBefore(parentNode.parent);
|
|
532
|
+
return nextToken && isDeclarationNotSafeToRemove(nextToken, prevToken) ? null : fixer.removeRange(parentNode.parent.range);
|
|
533
|
+
}
|
|
534
|
+
return getTokenBeforeValue(parentNode) === "," ? fixer.removeRange([getPreviousTokenStart(parentNode), parentNode.range[1]]) : fixer.removeRange([parentNode.range[0], getNextTokenEnd(parentNode)]);
|
|
535
|
+
}
|
|
536
|
+
return getTokenBeforeValue(node) === ":" && parentNode.parent.type === "ObjectPattern" ? fixObjectWithValueSeparator(node) : fixFunctionParameters(node);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* fix nested object like { a: { b } }
|
|
540
|
+
* @param {ASTNode} node parent node to check
|
|
541
|
+
* @returns {Object} fixer object
|
|
542
|
+
*/
|
|
543
|
+
function fixNestedObjectVariable(node) {
|
|
544
|
+
let parentNode = node.parent;
|
|
545
|
+
return parentNode.parent.parent.parent.type === "ObjectPattern" && parentNode.parent.properties.length === 1 ? fixNestedObjectVariable(parentNode.parent) : parentNode.parent.type === "ObjectPattern" ? parentNode.parent.properties.length === 1 ? fixVariables(parentNode.parent) : getTokenBeforeValue(parentNode) === "{" ? fixer.removeRange([parentNode.range[0], getNextTokenEnd(parentNode)]) : fixer.removeRange([getPreviousTokenStart(parentNode), parentNode.range[1]]) : null;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* fix unused variables in array and nested array
|
|
549
|
+
* @param {ASTNode} node parent node to check
|
|
550
|
+
* @returns {Object} fixer object
|
|
551
|
+
*/
|
|
552
|
+
function fixNestedArrayVariable(node) {
|
|
553
|
+
let parentNode = node.parent;
|
|
554
|
+
return parentNode.parent.type === "ArrayPattern" && hasSingleElement(parentNode) ? fixNestedArrayVariable(parentNode) : hasSingleElement(parentNode) ? getTokenBeforeValue(parentNode) === ":" ? fixVariables(parentNode) : parentNode.parent.type === "RestElement" ? fixRestInPattern(parentNode.parent) : fixVariables(parentNode) : getTokenBeforeValue(node) === "," && getTokenAfterValue(node) === "]" ? fixer.removeRange([getPreviousTokenStart(node), node.range[1]]) : fixer.removeRange(node.range);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* fix cases like {a: {k}} or {a: [k]}
|
|
558
|
+
* @param {ASTNode} node parent node to check
|
|
559
|
+
* @returns {Object} fixer object
|
|
560
|
+
*/
|
|
561
|
+
function fixObjectWithValueSeparator(node) {
|
|
562
|
+
let parentNode = node.parent.parent;
|
|
563
|
+
return parentNode.parent.type === "ArrayPattern" && parentNode.properties.length === 1 ? fixNestedArrayVariable(parentNode) : fixNestedObjectVariable(node);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* fix ...[[a]] or ...[{a}] like patterns
|
|
567
|
+
* @param {ASTNode} node parent node to check
|
|
568
|
+
* @returns {Object} fixer object
|
|
569
|
+
*/
|
|
570
|
+
function fixRestInPattern(node) {
|
|
571
|
+
let parentNode = node.parent;
|
|
572
|
+
return isFunction(parentNode) ? parentNode.params.length === 1 ? fixer.removeRange(node.range) : fixer.removeRange([getPreviousTokenStart(node), node.range[1]]) : parentNode.type === "ArrayPattern" ? hasSingleElement(parentNode) ? parentNode.parent.type === "ArrayPattern" ? fixNestedArrayVariable(parentNode) : fixVariables(parentNode) : fixer.removeRange([getPreviousTokenStart(node), node.range[1]]) : null;
|
|
573
|
+
}
|
|
574
|
+
if (allWriteReferences.some((ref) => ref.identifier.range[0] !== id.range[0])) return null;
|
|
575
|
+
if (parentType === "VariableDeclarator") {
|
|
576
|
+
if (parent.parent.declarations.length === 1) {
|
|
577
|
+
if (isLoop(parent.parent.parent) && parent.parent.parent.body !== parent.parent) return null;
|
|
578
|
+
if (parent.parent.parent.type === "IfStatement" || isLoop(parent.parent.parent) || parent.parent.parent.type === "WithStatement" && parent.parent.parent.body === parent.parent) return fixer.replaceText(parent.parent, ";");
|
|
579
|
+
let nextToken = sourceCode.getTokenAfter(parent.parent), prevToken = sourceCode.getTokenBefore(parent.parent);
|
|
580
|
+
return nextToken && isDeclarationNotSafeToRemove(nextToken, prevToken) ? null : fixer.removeRange(parent.parent.range);
|
|
581
|
+
}
|
|
582
|
+
return tokenBefore.value === "," ? fixer.removeRange([tokenBefore.range[0], parent.range[1]]) : fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]);
|
|
583
|
+
}
|
|
584
|
+
if (parent.parent.type === "ObjectPattern") {
|
|
585
|
+
if (parent.parent.properties.length === 1) return parent.parent.parent.type === "RestElement" ? fixRestInPattern(parent.parent.parent) : parent.parent.parent.type === "ArrayPattern" ? fixNestedArrayVariable(parent.parent) : fixVariables(parent.parent);
|
|
586
|
+
if (tokenBefore.value === ":") return getTokenBeforeValue(parent) === "{" && getTokenAfterValue(parent) === "," ? fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]) : fixer.removeRange([getPreviousTokenStart(parent), id.range[1]]);
|
|
587
|
+
}
|
|
588
|
+
if (parentType === "ArrayPattern") {
|
|
589
|
+
if (hasSingleElement(parent)) return parent.parent.type === "RestElement" ? fixRestInPattern(parent.parent) : parent.parent.type === "ArrayPattern" ? fixNestedArrayVariable(parent) : fixVariables(parent);
|
|
590
|
+
if (tokenBefore.value === "," && tokenAfter.value === ",") return fixer.removeRange(id.range);
|
|
591
|
+
}
|
|
592
|
+
if (parentType === "RestElement") {
|
|
593
|
+
if (parent.parent.type === "ArrayPattern") return hasSingleElement(parent.parent) ? parent.parent.parent.type === "ArrayPattern" ? fixNestedArrayVariable(parent.parent) : fixVariables(parent.parent) : fixer.removeRange([getPreviousTokenStart(id, 1), id.range[1]]);
|
|
594
|
+
if (parent.parent.type === "ObjectPattern") return parent.parent.properties.length === 1 ? fixVariables(parent.parent) : fixer.removeRange([getPreviousTokenStart(id, 1), id.range[1]]);
|
|
595
|
+
if (isFunction(parent.parent)) return parent.parent.params.length === 1 ? fixer.removeRange(parent.range) : fixer.removeRange([getPreviousTokenStart(parent), parent.range[1]]);
|
|
596
|
+
}
|
|
597
|
+
if (parentType === "AssignmentPattern") {
|
|
598
|
+
if (parent.parent.type === "ArrayPattern") return fixNestedArrayVariable(parent);
|
|
599
|
+
if (parent.parent.parent.type === "ObjectPattern") return parent.parent.parent.properties.length === 1 ? parent.parent.parent.parent.type === "ArrayPattern" ? fixNestedArrayVariable(parent.parent.parent) : fixVariables(parent.parent.parent) : getTokenBeforeValue(parent.parent) === "{" && getTokenAfterValue(parent.parent) === "," ? fixer.removeRange([parent.parent.range[0], getNextTokenEnd(parent.parent)]) : fixer.removeRange([getPreviousTokenStart(parent.parent), parent.parent.range[1]]);
|
|
600
|
+
if (isFunction(parent.parent)) return fixFunctionParameters(parent);
|
|
601
|
+
}
|
|
602
|
+
return parentType === "FunctionDeclaration" && parent.id === id ? fixer.removeRange(parent.range) : parentType === "ImportDefaultSpecifier" ? !hasImportOfCertainType(parent.parent, "ImportSpecifier") && !hasImportOfCertainType(parent.parent, "ImportNamespaceSpecifier") ? fixer.removeRange([parent.range[0], parent.parent.source.range[0]]) : fixer.removeRange([id.range[0], tokenAfter.range[1]]) : parentType === "ImportSpecifier" ? parent.parent.specifiers.filter((e) => e.type === "ImportSpecifier").length === 1 ? hasImportOfCertainType(parent.parent, "ImportDefaultSpecifier") ? fixer.removeRange([getPreviousTokenStart(parent, 1), tokenAfter.range[1]]) : fixer.removeRange(parent.parent.range) : getTokenBeforeValue(parent) === "{" ? fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]) : fixer.removeRange([getPreviousTokenStart(parent), parent.range[1]]) : parentType === "ImportNamespaceSpecifier" ? hasImportOfCertainType(parent.parent, "ImportDefaultSpecifier") ? fixer.removeRange([getPreviousTokenStart(parent), parent.range[1]]) : fixer.removeRange([parent.range[0], parent.parent.source.range[0]]) : parentType === "CatchClause" ? null : parentType === "ClassDeclaration" ? fixer.removeRange(parent.range) : tokenBefore?.value === "," ? fixer.removeRange([tokenBefore.range[0], id.range[1]]) : tokenAfter.value === "," && (tokenBefore.value === "(" || tokenBefore.value === "{") ? fixer.removeRange([id.range[0], tokenAfter.range[1]]) : parentType === "ArrowFunctionExpression" && parent.params.length === 1 && tokenAfter?.value !== ")" ? fixer.replaceText(id, "()") : fixer.removeRange(id.range);
|
|
603
|
+
}
|
|
604
|
+
return { "Program:exit"(programNode) {
|
|
605
|
+
let unusedVars = collectUnusedVariables(sourceCode.getScope(programNode), []);
|
|
606
|
+
for (let i = 0, l = unusedVars.length; i < l; ++i) {
|
|
607
|
+
let unusedVar = unusedVars[i];
|
|
608
|
+
if (unusedVar.defs.length > 0) {
|
|
609
|
+
let writeReferences = unusedVar.references.filter((ref) => ref.isWrite() && ref.from.variableScope === unusedVar.scope.variableScope), referenceToReport;
|
|
610
|
+
writeReferences.length > 0 && (referenceToReport = writeReferences.at(-1)), context.report({
|
|
611
|
+
node: referenceToReport ? referenceToReport.identifier : unusedVar.identifiers[0],
|
|
612
|
+
messageId: "unusedVar",
|
|
613
|
+
data: unusedVar.references.some((ref) => ref.isWrite()) ? getAssignedMessageData(unusedVar) : getDefinedMessageData(unusedVar),
|
|
614
|
+
suggest: [{
|
|
615
|
+
messageId: "removeVar",
|
|
616
|
+
data: { varName: unusedVar.name },
|
|
617
|
+
fix(fixer) {
|
|
618
|
+
return handleFixes(fixer, unusedVar);
|
|
619
|
+
}
|
|
620
|
+
}]
|
|
621
|
+
});
|
|
622
|
+
} else if (unusedVar.eslintExplicitGlobalComments) {
|
|
623
|
+
let directiveComment = unusedVar.eslintExplicitGlobalComments[0];
|
|
624
|
+
context.report({
|
|
625
|
+
node: programNode,
|
|
626
|
+
loc: astUtils.getNameLocationInGlobalDirectiveComment(sourceCode, directiveComment, unusedVar.name),
|
|
627
|
+
messageId: "unusedVar",
|
|
628
|
+
data: getDefinedMessageData(unusedVar)
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
} };
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
}));
|
|
636
|
+
//#endregion
|
|
637
|
+
//#region src-js/generated/plugin-eslint/rules/no-unused-vars.cjs
|
|
638
|
+
module.exports = require_no_unused_vars().create;
|
|
639
|
+
//#endregion
|