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,245 @@
|
|
|
1
|
+
//#region ../../node_modules/.pnpm/eslint@9.39.3_jiti@2.6.1/node_modules/eslint/lib/rules/no-use-before-define.js
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Rule to flag use of variables before they are defined
|
|
4
|
+
* @author Ilya Volodin
|
|
5
|
+
*/
|
|
6
|
+
var require_no_use_before_define = /* @__PURE__ */ require("../common/chunk.cjs").t(((exports, module) => {
|
|
7
|
+
let SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/u, FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/u;
|
|
8
|
+
/**
|
|
9
|
+
* Parses a given value as options.
|
|
10
|
+
* @param {any} options A value to parse.
|
|
11
|
+
* @returns {Object} The parsed options.
|
|
12
|
+
*/
|
|
13
|
+
function parseOptions(options) {
|
|
14
|
+
return typeof options == "object" && options ? options : {
|
|
15
|
+
functions: typeof options == "string" ? options !== "nofunc" : !0,
|
|
16
|
+
classes: !0,
|
|
17
|
+
variables: !0,
|
|
18
|
+
allowNamedExports: !1,
|
|
19
|
+
enums: !0,
|
|
20
|
+
typedefs: !0,
|
|
21
|
+
ignoreTypeReferences: !0
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Checks whether or not a given location is inside of the range of a given node.
|
|
26
|
+
* @param {ASTNode} node An node to check.
|
|
27
|
+
* @param {number} location A location to check.
|
|
28
|
+
* @returns {boolean} `true` if the location is inside of the range of the node.
|
|
29
|
+
*/
|
|
30
|
+
function isInRange(node, location) {
|
|
31
|
+
return node && node.range[0] <= location && location <= node.range[1];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Checks whether or not a given location is inside of the range of a class static initializer.
|
|
35
|
+
* Static initializers are static blocks and initializers of static fields.
|
|
36
|
+
* @param {ASTNode} node `ClassBody` node to check static initializers.
|
|
37
|
+
* @param {number} location A location to check.
|
|
38
|
+
* @returns {boolean} `true` if the location is inside of a class static initializer.
|
|
39
|
+
*/
|
|
40
|
+
function isInClassStaticInitializerRange(node, location) {
|
|
41
|
+
return node.body.some((classMember) => classMember.type === "StaticBlock" && isInRange(classMember, location) || classMember.type === "PropertyDefinition" && classMember.static && classMember.value && isInRange(classMember.value, location));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Checks whether a given scope is the scope of a class static initializer.
|
|
45
|
+
* Static initializers are static blocks and initializers of static fields.
|
|
46
|
+
* @param {eslint-scope.Scope} scope A scope to check.
|
|
47
|
+
* @returns {boolean} `true` if the scope is a class static initializer scope.
|
|
48
|
+
*/
|
|
49
|
+
function isClassStaticInitializerScope(scope) {
|
|
50
|
+
return scope.type === "class-static-block" ? !0 : scope.type === "class-field-initializer" ? scope.block.parent.static : !1;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Checks whether a given reference is evaluated in an execution context
|
|
54
|
+
* that isn't the one where the variable it refers to is defined.
|
|
55
|
+
* Execution contexts are:
|
|
56
|
+
* - top-level
|
|
57
|
+
* - functions
|
|
58
|
+
* - class field initializers (implicit functions)
|
|
59
|
+
* - class static blocks (implicit functions)
|
|
60
|
+
* Static class field initializers and class static blocks are automatically run during the class definition evaluation,
|
|
61
|
+
* and therefore we'll consider them as a part of the parent execution context.
|
|
62
|
+
* Example:
|
|
63
|
+
*
|
|
64
|
+
* const x = 1;
|
|
65
|
+
*
|
|
66
|
+
* x; // returns `false`
|
|
67
|
+
* () => x; // returns `true`
|
|
68
|
+
*
|
|
69
|
+
* class C {
|
|
70
|
+
* field = x; // returns `true`
|
|
71
|
+
* static field = x; // returns `false`
|
|
72
|
+
*
|
|
73
|
+
* method() {
|
|
74
|
+
* x; // returns `true`
|
|
75
|
+
* }
|
|
76
|
+
*
|
|
77
|
+
* static method() {
|
|
78
|
+
* x; // returns `true`
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* static {
|
|
82
|
+
* x; // returns `false`
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* @param {eslint-scope.Reference} reference A reference to check.
|
|
86
|
+
* @returns {boolean} `true` if the reference is from a separate execution context.
|
|
87
|
+
*/
|
|
88
|
+
function isFromSeparateExecutionContext(reference) {
|
|
89
|
+
let variable = reference.resolved, scope = reference.from;
|
|
90
|
+
for (; variable.scope.variableScope !== scope.variableScope;) if (isClassStaticInitializerScope(scope.variableScope)) scope = scope.variableScope.upper;
|
|
91
|
+
else return !0;
|
|
92
|
+
return !1;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Checks whether or not a given reference is evaluated during the initialization of its variable.
|
|
96
|
+
*
|
|
97
|
+
* This returns `true` in the following cases:
|
|
98
|
+
*
|
|
99
|
+
* var a = a
|
|
100
|
+
* var [a = a] = list
|
|
101
|
+
* var {a = a} = obj
|
|
102
|
+
* for (var a in a) {}
|
|
103
|
+
* for (var a of a) {}
|
|
104
|
+
* var C = class { [C]; };
|
|
105
|
+
* var C = class { static foo = C; };
|
|
106
|
+
* var C = class { static { foo = C; } };
|
|
107
|
+
* class C extends C {}
|
|
108
|
+
* class C extends (class { static foo = C; }) {}
|
|
109
|
+
* class C { [C]; }
|
|
110
|
+
* @param {Reference} reference A reference to check.
|
|
111
|
+
* @returns {boolean} `true` if the reference is evaluated during the initialization.
|
|
112
|
+
*/
|
|
113
|
+
function isEvaluatedDuringInitialization(reference) {
|
|
114
|
+
if (isFromSeparateExecutionContext(reference)) return !1;
|
|
115
|
+
let location = reference.identifier.range[1], definition = reference.resolved.defs[0];
|
|
116
|
+
if (definition.type === "ClassName") {
|
|
117
|
+
let classDefinition = definition.node;
|
|
118
|
+
return isInRange(classDefinition, location) && !isInClassStaticInitializerRange(classDefinition.body, location);
|
|
119
|
+
}
|
|
120
|
+
let node = definition.name.parent;
|
|
121
|
+
for (; node;) {
|
|
122
|
+
if (node.type === "VariableDeclarator") {
|
|
123
|
+
if (isInRange(node.init, location) || FOR_IN_OF_TYPE.test(node.parent.parent.type) && isInRange(node.parent.parent.right, location)) return !0;
|
|
124
|
+
break;
|
|
125
|
+
} else if (node.type === "AssignmentPattern") {
|
|
126
|
+
if (isInRange(node.right, location)) return !0;
|
|
127
|
+
} else if (SENTINEL_TYPE.test(node.type)) break;
|
|
128
|
+
node = node.parent;
|
|
129
|
+
}
|
|
130
|
+
return !1;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* check whether the reference contains a type query.
|
|
134
|
+
* @param {ASTNode} node Identifier node to check.
|
|
135
|
+
* @returns {boolean} true if reference contains type query.
|
|
136
|
+
*/
|
|
137
|
+
function referenceContainsTypeQuery(node) {
|
|
138
|
+
switch (node.type) {
|
|
139
|
+
case "TSTypeQuery": return !0;
|
|
140
|
+
case "TSQualifiedName":
|
|
141
|
+
case "Identifier": return referenceContainsTypeQuery(node.parent);
|
|
142
|
+
default: return !1;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Decorators are transpiled such that the decorator is placed after the class declaration
|
|
147
|
+
* So it is considered safe
|
|
148
|
+
* @param {Variable} variable The variable to check.
|
|
149
|
+
* @param {Reference} reference The reference to check.
|
|
150
|
+
* @returns {boolean} `true` if the reference is in a class decorator.
|
|
151
|
+
*/
|
|
152
|
+
function isClassRefInClassDecorator(variable, reference) {
|
|
153
|
+
if (variable.defs[0].type !== "ClassName" || !variable.defs[0].node.decorators || variable.defs[0].node.decorators.length === 0) return !1;
|
|
154
|
+
for (let deco of variable.defs[0].node.decorators) if (reference.identifier.range[0] >= deco.range[0] && reference.identifier.range[1] <= deco.range[1]) return !0;
|
|
155
|
+
return !1;
|
|
156
|
+
}
|
|
157
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
158
|
+
module.exports = {
|
|
159
|
+
meta: {
|
|
160
|
+
dialects: ["javascript", "typescript"],
|
|
161
|
+
language: "javascript",
|
|
162
|
+
type: "problem",
|
|
163
|
+
docs: {
|
|
164
|
+
description: "Disallow the use of variables before they are defined",
|
|
165
|
+
recommended: !1,
|
|
166
|
+
url: "https://eslint.org/docs/latest/rules/no-use-before-define"
|
|
167
|
+
},
|
|
168
|
+
schema: [{ oneOf: [{ enum: ["nofunc"] }, {
|
|
169
|
+
type: "object",
|
|
170
|
+
properties: {
|
|
171
|
+
functions: { type: "boolean" },
|
|
172
|
+
classes: { type: "boolean" },
|
|
173
|
+
variables: { type: "boolean" },
|
|
174
|
+
allowNamedExports: { type: "boolean" },
|
|
175
|
+
enums: { type: "boolean" },
|
|
176
|
+
typedefs: { type: "boolean" },
|
|
177
|
+
ignoreTypeReferences: { type: "boolean" }
|
|
178
|
+
},
|
|
179
|
+
additionalProperties: !1
|
|
180
|
+
}] }],
|
|
181
|
+
defaultOptions: [{
|
|
182
|
+
classes: !0,
|
|
183
|
+
functions: !0,
|
|
184
|
+
variables: !0,
|
|
185
|
+
allowNamedExports: !1,
|
|
186
|
+
enums: !0,
|
|
187
|
+
typedefs: !0,
|
|
188
|
+
ignoreTypeReferences: !0
|
|
189
|
+
}],
|
|
190
|
+
messages: { usedBeforeDefined: "'{{name}}' was used before it was defined." }
|
|
191
|
+
},
|
|
192
|
+
create(context) {
|
|
193
|
+
let options = parseOptions(context.options[0]), sourceCode = context.sourceCode;
|
|
194
|
+
/**
|
|
195
|
+
* Determines whether a given reference should be checked.
|
|
196
|
+
*
|
|
197
|
+
* Returns `false` if the reference is:
|
|
198
|
+
* - initialization's (e.g., `let a = 1`).
|
|
199
|
+
* - referring to an undefined variable (i.e., if it's an unresolved reference).
|
|
200
|
+
* - referring to a variable that is defined, but not in the given source code
|
|
201
|
+
* (e.g., global environment variable or `arguments` in functions).
|
|
202
|
+
* - allowed by options.
|
|
203
|
+
* @param {eslint-scope.Reference} reference The reference
|
|
204
|
+
* @returns {boolean} `true` if the reference should be checked
|
|
205
|
+
*/
|
|
206
|
+
function shouldCheck(reference) {
|
|
207
|
+
if (reference.init) return !1;
|
|
208
|
+
let { identifier } = reference;
|
|
209
|
+
if (options.allowNamedExports && identifier.parent.type === "ExportSpecifier" && identifier.parent.local === identifier) return !1;
|
|
210
|
+
let variable = reference.resolved;
|
|
211
|
+
if (!variable || variable.defs.length === 0) return !1;
|
|
212
|
+
let definitionType = variable.defs[0].type;
|
|
213
|
+
if (!options.functions && definitionType === "FunctionName" || (!options.variables && definitionType === "Variable" || !options.classes && definitionType === "ClassName") && isFromSeparateExecutionContext(reference) || !options.enums && definitionType === "TSEnumName" || !options.typedefs && definitionType === "Type" || options.ignoreTypeReferences && (referenceContainsTypeQuery(identifier) || identifier.parent.type === "TSTypeReference")) return !1;
|
|
214
|
+
if (identifier.parent.type === "TSQualifiedName") {
|
|
215
|
+
let currentNode = identifier.parent;
|
|
216
|
+
for (; currentNode.type === "TSQualifiedName";) currentNode = currentNode.left;
|
|
217
|
+
return currentNode === identifier;
|
|
218
|
+
}
|
|
219
|
+
return !isClassRefInClassDecorator(variable, reference);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Finds and validates all references in a given scope and its child scopes.
|
|
223
|
+
* @param {eslint-scope.Scope} scope The scope object.
|
|
224
|
+
* @returns {void}
|
|
225
|
+
*/
|
|
226
|
+
function checkReferencesInScope(scope) {
|
|
227
|
+
scope.references.filter(shouldCheck).forEach((reference) => {
|
|
228
|
+
let definitionIdentifier = reference.resolved.defs[0].name;
|
|
229
|
+
(reference.identifier.range[1] < definitionIdentifier.range[1] || isEvaluatedDuringInitialization(reference) && reference.identifier.parent.type !== "TSTypeReference") && context.report({
|
|
230
|
+
node: reference.identifier,
|
|
231
|
+
messageId: "usedBeforeDefined",
|
|
232
|
+
data: reference.identifier
|
|
233
|
+
});
|
|
234
|
+
}), scope.childScopes.forEach(checkReferencesInScope);
|
|
235
|
+
}
|
|
236
|
+
return { Program(node) {
|
|
237
|
+
checkReferencesInScope(sourceCode.getScope(node));
|
|
238
|
+
} };
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
}));
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src-js/generated/plugin-eslint/rules/no-use-before-define.cjs
|
|
244
|
+
module.exports = require_no_use_before_define().create;
|
|
245
|
+
//#endregion
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
const require_chunk = require("../common/chunk.cjs"), require_eslint_utils$1 = require("../common/eslint-utils.cjs");
|
|
2
|
+
//#region ../../node_modules/.pnpm/eslint@9.39.3_jiti@2.6.1/node_modules/eslint/lib/rules/no-useless-assignment.js
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview A rule to disallow unnecessary assignments`.
|
|
5
|
+
* @author Yosuke Ota
|
|
6
|
+
*/
|
|
7
|
+
var require_no_useless_assignment = /* @__PURE__ */ require_chunk.t(((exports, module) => {
|
|
8
|
+
let { findVariable } = require_eslint_utils$1.t();
|
|
9
|
+
/** @typedef {import("estree").Node} ASTNode */
|
|
10
|
+
/** @typedef {import("estree").Pattern} Pattern */
|
|
11
|
+
/** @typedef {import("estree").Identifier} Identifier */
|
|
12
|
+
/** @typedef {import("estree").VariableDeclarator} VariableDeclarator */
|
|
13
|
+
/** @typedef {import("estree").AssignmentExpression} AssignmentExpression */
|
|
14
|
+
/** @typedef {import("estree").UpdateExpression} UpdateExpression */
|
|
15
|
+
/** @typedef {import("estree").Expression} Expression */
|
|
16
|
+
/** @typedef {import("eslint-scope").Scope} Scope */
|
|
17
|
+
/** @typedef {import("eslint-scope").Variable} Variable */
|
|
18
|
+
/** @typedef {import("../linter/code-path-analysis/code-path")} CodePath */
|
|
19
|
+
/** @typedef {import("../linter/code-path-analysis/code-path-segment")} CodePathSegment */
|
|
20
|
+
/**
|
|
21
|
+
* Extract identifier from the given pattern node used on the left-hand side of the assignment.
|
|
22
|
+
* @param {Pattern} pattern The pattern node to extract identifier
|
|
23
|
+
* @returns {Iterable<Identifier>} The extracted identifier
|
|
24
|
+
*/
|
|
25
|
+
function* extractIdentifiersFromPattern(pattern) {
|
|
26
|
+
switch (pattern.type) {
|
|
27
|
+
case "Identifier":
|
|
28
|
+
yield pattern;
|
|
29
|
+
return;
|
|
30
|
+
case "ObjectPattern":
|
|
31
|
+
for (let property of pattern.properties) yield* extractIdentifiersFromPattern(property.type === "Property" ? property.value : property);
|
|
32
|
+
return;
|
|
33
|
+
case "ArrayPattern":
|
|
34
|
+
for (let element of pattern.elements) element && (yield* extractIdentifiersFromPattern(element));
|
|
35
|
+
return;
|
|
36
|
+
case "RestElement":
|
|
37
|
+
yield* extractIdentifiersFromPattern(pattern.argument);
|
|
38
|
+
return;
|
|
39
|
+
case "AssignmentPattern": yield* extractIdentifiersFromPattern(pattern.left);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Checks whether the given identifier node is evaluated after the assignment identifier.
|
|
44
|
+
* @param {AssignmentInfo} assignment The assignment info.
|
|
45
|
+
* @param {Identifier} identifier The identifier to check.
|
|
46
|
+
* @returns {boolean} `true` if the given identifier node is evaluated after the assignment identifier.
|
|
47
|
+
*/
|
|
48
|
+
function isIdentifierEvaluatedAfterAssignment(assignment, identifier) {
|
|
49
|
+
return !(identifier.range[0] < assignment.identifier.range[1] || assignment.expression && assignment.expression.range[0] <= identifier.range[0] && identifier.range[1] <= assignment.expression.range[1]);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Checks whether the given identifier node is used between the assigned identifier and the equal sign.
|
|
53
|
+
*
|
|
54
|
+
* e.g. let { x, y = x } = obj;
|
|
55
|
+
* ^ identifier to check
|
|
56
|
+
* ^ assigned identifier
|
|
57
|
+
* @param {AssignmentInfo} assignment The assignment info.
|
|
58
|
+
* @param {Identifier} identifier The identifier to check.
|
|
59
|
+
* @returns {boolean} `true` if the given identifier node is used between the assigned identifier and the equal sign.
|
|
60
|
+
*/
|
|
61
|
+
function isIdentifierUsedBetweenAssignedAndEqualSign(assignment, identifier) {
|
|
62
|
+
return assignment.expression ? assignment.identifier.range[1] <= identifier.range[0] && identifier.range[1] <= assignment.expression.range[0] : !1;
|
|
63
|
+
}
|
|
64
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
65
|
+
module.exports = {
|
|
66
|
+
meta: {
|
|
67
|
+
type: "problem",
|
|
68
|
+
docs: {
|
|
69
|
+
description: "Disallow variable assignments when the value is not used",
|
|
70
|
+
recommended: !1,
|
|
71
|
+
url: "https://eslint.org/docs/latest/rules/no-useless-assignment"
|
|
72
|
+
},
|
|
73
|
+
schema: [],
|
|
74
|
+
messages: { unnecessaryAssignment: "This assigned value is not used in subsequent statements." }
|
|
75
|
+
},
|
|
76
|
+
create(context) {
|
|
77
|
+
let sourceCode = context.sourceCode, scopeStack = null, codePathStartScopes = /* @__PURE__ */ new Set();
|
|
78
|
+
/**
|
|
79
|
+
* Gets the scope of code path start from given scope
|
|
80
|
+
* @param {Scope} scope The initial scope
|
|
81
|
+
* @returns {Scope} The scope of code path start
|
|
82
|
+
* @throws {Error} Unexpected error
|
|
83
|
+
*/
|
|
84
|
+
function getCodePathStartScope(scope) {
|
|
85
|
+
let target = scope;
|
|
86
|
+
for (; target;) {
|
|
87
|
+
if (codePathStartScopes.has(target)) return target;
|
|
88
|
+
target = target.upper;
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Verify the given scope stack.
|
|
94
|
+
* @param {ScopeStack} target The scope stack to verify.
|
|
95
|
+
* @returns {void}
|
|
96
|
+
*/
|
|
97
|
+
function verify(target) {
|
|
98
|
+
/**
|
|
99
|
+
* Checks whether the given identifier is used in the segment.
|
|
100
|
+
* @param {CodePathSegment} segment The code path segment.
|
|
101
|
+
* @param {Identifier} identifier The identifier to check.
|
|
102
|
+
* @returns {boolean} `true` if the identifier is used in the segment.
|
|
103
|
+
*/
|
|
104
|
+
function isIdentifierUsedInSegment(segment, identifier) {
|
|
105
|
+
let segmentInfo = target.segments[segment.id];
|
|
106
|
+
return segmentInfo.first && segmentInfo.last && segmentInfo.first.range[0] <= identifier.range[0] && identifier.range[1] <= segmentInfo.last.range[1];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Verifies whether the given assignment info is an used assignment.
|
|
110
|
+
* Report if it is an unused assignment.
|
|
111
|
+
* @param {AssignmentInfo} targetAssignment The assignment info to verify.
|
|
112
|
+
* @param {AssignmentInfo[]} allAssignments The list of all assignment info for variables.
|
|
113
|
+
* @returns {void}
|
|
114
|
+
*/
|
|
115
|
+
function verifyAssignmentIsUsed(targetAssignment, allAssignments) {
|
|
116
|
+
if (target.tryStatementBlocks.some((tryBlock) => tryBlock.range[0] <= targetAssignment.identifier.range[0] && targetAssignment.identifier.range[1] <= tryBlock.range[1])) return;
|
|
117
|
+
/**
|
|
118
|
+
* @typedef {Object} SubsequentSegmentData
|
|
119
|
+
* @property {CodePathSegment} segment The code path segment
|
|
120
|
+
* @property {AssignmentInfo} [assignment] The first occurrence of the assignment within the segment.
|
|
121
|
+
* There is no need to check if the variable is used after this assignment,
|
|
122
|
+
* as the value it was assigned will be used.
|
|
123
|
+
*/
|
|
124
|
+
/**
|
|
125
|
+
* Information used in `getSubsequentSegments()`.
|
|
126
|
+
* To avoid unnecessary iterations, cache information that has already been iterated over,
|
|
127
|
+
* and if additional iterations are needed, start iterating from the retained position.
|
|
128
|
+
*/
|
|
129
|
+
let subsequentSegmentData = {
|
|
130
|
+
results: [],
|
|
131
|
+
subsequentSegments: /* @__PURE__ */ new Set(),
|
|
132
|
+
queueSegments: targetAssignment.segments.flatMap((segment) => segment.nextSegments)
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Gets the subsequent segments from the segment of
|
|
136
|
+
* the assignment currently being validated (targetAssignment).
|
|
137
|
+
* @returns {Iterable<SubsequentSegmentData>} the subsequent segments
|
|
138
|
+
*/
|
|
139
|
+
function* getSubsequentSegments() {
|
|
140
|
+
for (yield* subsequentSegmentData.results; subsequentSegmentData.queueSegments.length > 0;) {
|
|
141
|
+
let nextSegment = subsequentSegmentData.queueSegments.shift();
|
|
142
|
+
if (subsequentSegmentData.subsequentSegments.has(nextSegment)) continue;
|
|
143
|
+
subsequentSegmentData.subsequentSegments.add(nextSegment);
|
|
144
|
+
let assignmentInSegment = allAssignments.find((otherAssignment) => otherAssignment.segments.includes(nextSegment) && !isIdentifierUsedBetweenAssignedAndEqualSign(otherAssignment, targetAssignment.identifier));
|
|
145
|
+
assignmentInSegment || subsequentSegmentData.queueSegments.push(...nextSegment.nextSegments);
|
|
146
|
+
/** @type {SubsequentSegmentData} */
|
|
147
|
+
let result = {
|
|
148
|
+
segment: nextSegment,
|
|
149
|
+
assignment: assignmentInSegment
|
|
150
|
+
};
|
|
151
|
+
subsequentSegmentData.results.push(result), yield result;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (targetAssignment.variable.references.some((ref) => ref.identifier.type !== "Identifier"))
|
|
155
|
+
/**
|
|
156
|
+
* Skip checking for a variable that has at least one non-identifier reference.
|
|
157
|
+
* It's generated by plugins and cannot be handled reliably in the core rule.
|
|
158
|
+
*/
|
|
159
|
+
return;
|
|
160
|
+
let readReferences = targetAssignment.variable.references.filter((reference) => reference.isRead());
|
|
161
|
+
if (!readReferences.length) return;
|
|
162
|
+
/**
|
|
163
|
+
* Other assignment on the current segment and after current assignment.
|
|
164
|
+
*/
|
|
165
|
+
let otherAssignmentAfterTargetAssignment = allAssignments.find((assignment) => assignment === targetAssignment || assignment.segments.length && assignment.segments.every((segment) => !targetAssignment.segments.includes(segment)) ? !1 : !!(isIdentifierEvaluatedAfterAssignment(targetAssignment, assignment.identifier) || assignment.expression && assignment.expression.range[0] <= targetAssignment.identifier.range[0] && targetAssignment.identifier.range[1] <= assignment.expression.range[1]));
|
|
166
|
+
for (let reference of readReferences) {
|
|
167
|
+
if (target.scope !== getCodePathStartScope(reference.from)) return;
|
|
168
|
+
if (isIdentifierEvaluatedAfterAssignment(targetAssignment, reference.identifier) && (isIdentifierUsedBetweenAssignedAndEqualSign(targetAssignment, reference.identifier) || targetAssignment.segments.some((segment) => isIdentifierUsedInSegment(segment, reference.identifier)))) {
|
|
169
|
+
if (otherAssignmentAfterTargetAssignment && isIdentifierEvaluatedAfterAssignment(otherAssignmentAfterTargetAssignment, reference.identifier)) continue;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (!otherAssignmentAfterTargetAssignment) {
|
|
173
|
+
for (let subsequentSegment of getSubsequentSegments()) if (isIdentifierUsedInSegment(subsequentSegment.segment, reference.identifier)) {
|
|
174
|
+
if (subsequentSegment.assignment && isIdentifierEvaluatedAfterAssignment(subsequentSegment.assignment, reference.identifier)) continue;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
context.report({
|
|
180
|
+
node: targetAssignment.identifier,
|
|
181
|
+
messageId: "unnecessaryAssignment"
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
for (let assignments of target.assignments.values()) {
|
|
185
|
+
assignments.sort((a, b) => a.identifier.range[0] - b.identifier.range[0]);
|
|
186
|
+
for (let assignment of assignments) verifyAssignmentIsUsed(assignment, assignments);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
onCodePathStart(codePath, node) {
|
|
191
|
+
let scope = sourceCode.getScope(node);
|
|
192
|
+
scopeStack = {
|
|
193
|
+
upper: scopeStack,
|
|
194
|
+
codePath,
|
|
195
|
+
scope,
|
|
196
|
+
segments: Object.create(null),
|
|
197
|
+
currentSegments: /* @__PURE__ */ new Set(),
|
|
198
|
+
assignments: /* @__PURE__ */ new Map(),
|
|
199
|
+
tryStatementBlocks: []
|
|
200
|
+
}, codePathStartScopes.add(scopeStack.scope);
|
|
201
|
+
},
|
|
202
|
+
onCodePathEnd() {
|
|
203
|
+
verify(scopeStack), scopeStack = scopeStack.upper;
|
|
204
|
+
},
|
|
205
|
+
onCodePathSegmentStart(segment) {
|
|
206
|
+
let segmentInfo = {
|
|
207
|
+
segment,
|
|
208
|
+
first: null,
|
|
209
|
+
last: null
|
|
210
|
+
};
|
|
211
|
+
scopeStack.segments[segment.id] = segmentInfo, scopeStack.currentSegments.add(segment);
|
|
212
|
+
},
|
|
213
|
+
onCodePathSegmentEnd(segment) {
|
|
214
|
+
scopeStack.currentSegments.delete(segment);
|
|
215
|
+
},
|
|
216
|
+
TryStatement(node) {
|
|
217
|
+
scopeStack.tryStatementBlocks.push(node.block);
|
|
218
|
+
},
|
|
219
|
+
Identifier(node) {
|
|
220
|
+
for (let segment of scopeStack.currentSegments) {
|
|
221
|
+
let segmentInfo = scopeStack.segments[segment.id];
|
|
222
|
+
segmentInfo.first ||= node, segmentInfo.last = node;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
":matches(VariableDeclarator[init!=null], AssignmentExpression, UpdateExpression):exit"(node) {
|
|
226
|
+
if (scopeStack.currentSegments.size === 0) return;
|
|
227
|
+
let assignments = scopeStack.assignments, pattern, expression = null;
|
|
228
|
+
node.type === "VariableDeclarator" ? (pattern = node.id, expression = node.init) : node.type === "AssignmentExpression" ? (pattern = node.left, expression = node.right) : pattern = node.argument;
|
|
229
|
+
for (let identifier of extractIdentifiersFromPattern(pattern)) {
|
|
230
|
+
/** @type {Variable} */
|
|
231
|
+
let variable = findVariable(sourceCode.getScope(identifier), identifier);
|
|
232
|
+
if (!variable || variable.scope.type === "global" && variable.defs.length === 0 || scopeStack.scope !== getCodePathStartScope(variable.scope) || variable.eslintUsed || variable.scope.type === "module" && (variable.defs.some((def) => def.type === "Variable" && def.parent.parent.type === "ExportNamedDeclaration" || def.type === "FunctionName" && (def.node.parent.type === "ExportNamedDeclaration" || def.node.parent.type === "ExportDefaultDeclaration") || def.type === "ClassName" && (def.node.parent.type === "ExportNamedDeclaration" || def.node.parent.type === "ExportDefaultDeclaration")) || variable.references.some((reference) => reference.identifier.parent.type === "ExportSpecifier"))) continue;
|
|
233
|
+
let list = assignments.get(variable);
|
|
234
|
+
list || (list = [], assignments.set(variable, list)), list.push({
|
|
235
|
+
variable,
|
|
236
|
+
identifier,
|
|
237
|
+
node,
|
|
238
|
+
expression,
|
|
239
|
+
segments: [...scopeStack.currentSegments]
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
}));
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src-js/generated/plugin-eslint/rules/no-useless-assignment.cjs
|
|
249
|
+
module.exports = require_no_useless_assignment().create;
|
|
250
|
+
//#endregion
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const require_chunk = require("../common/chunk.cjs"), require_eslint_utils$1 = require("../common/eslint-utils.cjs"), require_regexpp$1 = require("../common/regexpp.cjs");
|
|
2
|
+
//#region ../../node_modules/.pnpm/eslint@9.39.3_jiti@2.6.1/node_modules/eslint/lib/rules/no-useless-backreference.js
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Rule to disallow useless backreferences in regular expressions
|
|
5
|
+
* @author Milos Djermanovic
|
|
6
|
+
*/
|
|
7
|
+
var require_no_useless_backreference = /* @__PURE__ */ require_chunk.t(((exports, module) => {
|
|
8
|
+
let { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require_eslint_utils$1.t(), { RegExpParser, visitRegExpAST } = require_regexpp$1.t(), parser = new RegExpParser();
|
|
9
|
+
/**
|
|
10
|
+
* Finds the path from the given `regexpp` AST node to the root node.
|
|
11
|
+
* @param {regexpp.Node} node Node.
|
|
12
|
+
* @returns {regexpp.Node[]} Array that starts with the given node and ends with the root node.
|
|
13
|
+
*/
|
|
14
|
+
function getPathToRoot(node) {
|
|
15
|
+
let path = [], current = node;
|
|
16
|
+
do
|
|
17
|
+
path.push(current), current = current.parent;
|
|
18
|
+
while (current);
|
|
19
|
+
return path;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Determines whether the given `regexpp` AST node is a lookaround node.
|
|
23
|
+
* @param {regexpp.Node} node Node.
|
|
24
|
+
* @returns {boolean} `true` if it is a lookaround node.
|
|
25
|
+
*/
|
|
26
|
+
function isLookaround(node) {
|
|
27
|
+
return node.type === "Assertion" && (node.kind === "lookahead" || node.kind === "lookbehind");
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Determines whether the given `regexpp` AST node is a negative lookaround node.
|
|
31
|
+
* @param {regexpp.Node} node Node.
|
|
32
|
+
* @returns {boolean} `true` if it is a negative lookaround node.
|
|
33
|
+
*/
|
|
34
|
+
function isNegativeLookaround(node) {
|
|
35
|
+
return isLookaround(node) && node.negate;
|
|
36
|
+
}
|
|
37
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
38
|
+
module.exports = {
|
|
39
|
+
meta: {
|
|
40
|
+
type: "problem",
|
|
41
|
+
docs: {
|
|
42
|
+
description: "Disallow useless backreferences in regular expressions",
|
|
43
|
+
recommended: !0,
|
|
44
|
+
url: "https://eslint.org/docs/latest/rules/no-useless-backreference"
|
|
45
|
+
},
|
|
46
|
+
schema: [],
|
|
47
|
+
messages: {
|
|
48
|
+
nested: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} from within that group.",
|
|
49
|
+
forward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which appears later in the pattern.",
|
|
50
|
+
backward: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which appears before in the same lookbehind.",
|
|
51
|
+
disjunctive: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which is in another alternative.",
|
|
52
|
+
intoNegativeLookaround: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which is in a negative lookaround."
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
create(context) {
|
|
56
|
+
let sourceCode = context.sourceCode;
|
|
57
|
+
/**
|
|
58
|
+
* Checks and reports useless backreferences in the given regular expression.
|
|
59
|
+
* @param {ASTNode} node Node that represents regular expression. A regex literal or RegExp constructor call.
|
|
60
|
+
* @param {string} pattern Regular expression pattern.
|
|
61
|
+
* @param {string} flags Regular expression flags.
|
|
62
|
+
* @returns {void}
|
|
63
|
+
*/
|
|
64
|
+
function checkRegex(node, pattern, flags) {
|
|
65
|
+
let regExpAST;
|
|
66
|
+
try {
|
|
67
|
+
regExpAST = parser.parsePattern(pattern, 0, pattern.length, {
|
|
68
|
+
unicode: flags.includes("u"),
|
|
69
|
+
unicodeSets: flags.includes("v")
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
visitRegExpAST(regExpAST, { onBackreferenceEnter(bref) {
|
|
75
|
+
let groups = [bref.resolved].flat(), brefPath = getPathToRoot(bref), problems = groups.map((group) => {
|
|
76
|
+
let groupPath = getPathToRoot(group);
|
|
77
|
+
if (brefPath.includes(group)) return {
|
|
78
|
+
messageId: "nested",
|
|
79
|
+
group
|
|
80
|
+
};
|
|
81
|
+
let i = brefPath.length - 1, j = groupPath.length - 1;
|
|
82
|
+
do
|
|
83
|
+
i--, j--;
|
|
84
|
+
while (brefPath[i] === groupPath[j]);
|
|
85
|
+
let indexOfLowestCommonAncestor = j + 1, groupCut = groupPath.slice(0, indexOfLowestCommonAncestor), lowestCommonLookaround = groupPath.slice(indexOfLowestCommonAncestor).find(isLookaround), isMatchingBackward = lowestCommonLookaround && lowestCommonLookaround.kind === "lookbehind";
|
|
86
|
+
return groupCut.at(-1).type === "Alternative" ? {
|
|
87
|
+
messageId: "disjunctive",
|
|
88
|
+
group
|
|
89
|
+
} : !isMatchingBackward && bref.end <= group.start ? {
|
|
90
|
+
messageId: "forward",
|
|
91
|
+
group
|
|
92
|
+
} : isMatchingBackward && group.end <= bref.start ? {
|
|
93
|
+
messageId: "backward",
|
|
94
|
+
group
|
|
95
|
+
} : groupCut.some(isNegativeLookaround) ? {
|
|
96
|
+
messageId: "intoNegativeLookaround",
|
|
97
|
+
group
|
|
98
|
+
} : null;
|
|
99
|
+
});
|
|
100
|
+
if (problems.length === 0 || problems.some((problem) => !problem)) return;
|
|
101
|
+
let problemsToReport, problemsInSameDisjunction = problems.filter((problem) => problem.messageId !== "disjunctive");
|
|
102
|
+
problemsToReport = problemsInSameDisjunction.length ? problemsInSameDisjunction : problems;
|
|
103
|
+
let [{ messageId, group }, ...other] = problemsToReport, otherGroups = "";
|
|
104
|
+
other.length === 1 ? otherGroups = " and another group" : other.length > 1 && (otherGroups = ` and other ${other.length} groups`), context.report({
|
|
105
|
+
node,
|
|
106
|
+
messageId,
|
|
107
|
+
data: {
|
|
108
|
+
bref: bref.raw,
|
|
109
|
+
group: group.raw,
|
|
110
|
+
otherGroups
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
} });
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
"Literal[regex]"(node) {
|
|
117
|
+
let { pattern, flags } = node.regex;
|
|
118
|
+
checkRegex(node, pattern, flags);
|
|
119
|
+
},
|
|
120
|
+
Program(node) {
|
|
121
|
+
let scope = sourceCode.getScope(node), tracker = new ReferenceTracker(scope), traceMap = { RegExp: {
|
|
122
|
+
[CALL]: !0,
|
|
123
|
+
[CONSTRUCT]: !0
|
|
124
|
+
} };
|
|
125
|
+
for (let { node: refNode } of tracker.iterateGlobalReferences(traceMap)) {
|
|
126
|
+
let [patternNode, flagsNode] = refNode.arguments, pattern = getStringIfConstant(patternNode, scope), flags = getStringIfConstant(flagsNode, scope);
|
|
127
|
+
typeof pattern == "string" && checkRegex(refNode, pattern, flags || "");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}));
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src-js/generated/plugin-eslint/rules/no-useless-backreference.cjs
|
|
136
|
+
module.exports = require_no_useless_backreference().create;
|
|
137
|
+
//#endregion
|