eslint 9.22.0 → 9.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -46
- package/bin/eslint.js +92 -90
- package/conf/default-cli-options.js +22 -22
- package/conf/ecma-version.js +1 -1
- package/conf/globals.js +97 -98
- package/conf/replacements.json +24 -20
- package/conf/rule-type-list.json +88 -92
- package/lib/api.js +12 -12
- package/lib/cli-engine/cli-engine.js +830 -810
- package/lib/cli-engine/file-enumerator.js +381 -387
- package/lib/cli-engine/formatters/formatters-meta.json +16 -16
- package/lib/cli-engine/formatters/html.js +107 -99
- package/lib/cli-engine/formatters/json-with-metadata.js +5 -5
- package/lib/cli-engine/formatters/json.js +2 -2
- package/lib/cli-engine/formatters/stylish.js +96 -75
- package/lib/cli-engine/hash.js +1 -1
- package/lib/cli-engine/index.js +1 -1
- package/lib/cli-engine/lint-result-cache.js +144 -145
- package/lib/cli-engine/load-rules.js +16 -16
- package/lib/cli.js +638 -457
- package/lib/config/config-loader.js +726 -622
- package/lib/config/config.js +247 -221
- package/lib/config/default-config.js +54 -45
- package/lib/config/flat-config-array.js +167 -172
- package/lib/config/flat-config-helpers.js +72 -72
- package/lib/config/flat-config-schema.js +375 -368
- package/lib/config/rule-validator.js +139 -144
- package/lib/config-api.js +2 -2
- package/lib/eslint/eslint-helpers.js +756 -681
- package/lib/eslint/eslint.js +934 -912
- package/lib/eslint/index.js +2 -2
- package/lib/eslint/legacy-eslint.js +577 -533
- package/lib/languages/js/index.js +263 -264
- package/lib/languages/js/source-code/index.js +1 -1
- package/lib/languages/js/source-code/source-code.js +1128 -1057
- package/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js +39 -35
- package/lib/languages/js/source-code/token-store/backward-token-cursor.js +35 -36
- package/lib/languages/js/source-code/token-store/cursor.js +36 -36
- package/lib/languages/js/source-code/token-store/cursors.js +80 -52
- package/lib/languages/js/source-code/token-store/decorative-cursor.js +17 -18
- package/lib/languages/js/source-code/token-store/filter-cursor.js +19 -20
- package/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js +40 -32
- package/lib/languages/js/source-code/token-store/forward-token-cursor.js +40 -41
- package/lib/languages/js/source-code/token-store/index.js +592 -498
- package/lib/languages/js/source-code/token-store/limit-cursor.js +17 -18
- package/lib/languages/js/source-code/token-store/padded-token-cursor.js +23 -16
- package/lib/languages/js/source-code/token-store/skip-cursor.js +19 -20
- package/lib/languages/js/source-code/token-store/utils.js +63 -60
- package/lib/languages/js/validate-language-options.js +104 -89
- package/lib/linter/apply-disable-directives.js +467 -383
- package/lib/linter/code-path-analysis/code-path-analyzer.js +650 -672
- package/lib/linter/code-path-analysis/code-path-segment.js +215 -216
- package/lib/linter/code-path-analysis/code-path-state.js +2118 -2096
- package/lib/linter/code-path-analysis/code-path.js +307 -319
- package/lib/linter/code-path-analysis/debug-helpers.js +183 -163
- package/lib/linter/code-path-analysis/fork-context.js +296 -271
- package/lib/linter/code-path-analysis/id-generator.js +22 -23
- package/lib/linter/file-context.js +119 -120
- package/lib/linter/index.js +3 -3
- package/lib/linter/interpolate.js +16 -16
- package/lib/linter/linter.js +2403 -2045
- package/lib/linter/node-event-generator.js +284 -225
- package/lib/linter/report-translator.js +256 -219
- package/lib/linter/rule-fixer.js +122 -124
- package/lib/linter/rules.js +36 -36
- package/lib/linter/safe-emitter.js +18 -18
- package/lib/linter/source-code-fixer.js +94 -92
- package/lib/linter/timing.js +104 -101
- package/lib/linter/vfile.js +70 -73
- package/lib/options.js +404 -361
- package/lib/rule-tester/index.js +1 -1
- package/lib/rule-tester/rule-tester.js +1308 -1046
- package/lib/rules/accessor-pairs.js +298 -263
- package/lib/rules/array-bracket-newline.js +250 -238
- package/lib/rules/array-bracket-spacing.js +263 -224
- package/lib/rules/array-callback-return.js +402 -356
- package/lib/rules/array-element-newline.js +358 -313
- package/lib/rules/arrow-body-style.js +400 -281
- package/lib/rules/arrow-parens.js +206 -173
- package/lib/rules/arrow-spacing.js +169 -163
- package/lib/rules/block-scoped-var.js +125 -123
- package/lib/rules/block-spacing.js +186 -176
- package/lib/rules/brace-style.js +262 -199
- package/lib/rules/callback-return.js +203 -190
- package/lib/rules/camelcase.js +403 -392
- package/lib/rules/capitalized-comments.js +253 -232
- package/lib/rules/class-methods-use-this.js +224 -172
- package/lib/rules/comma-dangle.js +379 -346
- package/lib/rules/comma-spacing.js +193 -195
- package/lib/rules/comma-style.js +375 -316
- package/lib/rules/complexity.js +173 -169
- package/lib/rules/computed-property-spacing.js +236 -211
- package/lib/rules/consistent-return.js +181 -170
- package/lib/rules/consistent-this.js +167 -147
- package/lib/rules/constructor-super.js +412 -404
- package/lib/rules/curly.js +407 -332
- package/lib/rules/default-case-last.js +38 -31
- package/lib/rules/default-case.js +89 -85
- package/lib/rules/default-param-last.js +69 -54
- package/lib/rules/dot-location.js +122 -110
- package/lib/rules/dot-notation.js +192 -156
- package/lib/rules/eol-last.js +122 -120
- package/lib/rules/eqeqeq.js +168 -155
- package/lib/rules/for-direction.js +146 -121
- package/lib/rules/func-call-spacing.js +261 -231
- package/lib/rules/func-name-matching.js +293 -209
- package/lib/rules/func-names.js +165 -164
- package/lib/rules/func-style.js +159 -127
- package/lib/rules/function-call-argument-newline.js +152 -129
- package/lib/rules/function-paren-newline.js +349 -291
- package/lib/rules/generator-star-spacing.js +229 -210
- package/lib/rules/getter-return.js +208 -172
- package/lib/rules/global-require.js +85 -74
- package/lib/rules/grouped-accessor-pairs.js +170 -150
- package/lib/rules/guard-for-in.js +72 -63
- package/lib/rules/handle-callback-err.js +108 -103
- package/lib/rules/id-blacklist.js +182 -199
- package/lib/rules/id-denylist.js +168 -187
- package/lib/rules/id-length.js +197 -171
- package/lib/rules/id-match.js +344 -289
- package/lib/rules/implicit-arrow-linebreak.js +102 -79
- package/lib/rules/indent-legacy.js +1344 -1118
- package/lib/rules/indent.js +2272 -1759
- package/lib/rules/index.js +317 -292
- package/lib/rules/init-declarations.js +137 -107
- package/lib/rules/jsx-quotes.js +94 -82
- package/lib/rules/key-spacing.js +750 -633
- package/lib/rules/keyword-spacing.js +648 -605
- package/lib/rules/line-comment-position.js +142 -128
- package/lib/rules/linebreak-style.js +107 -106
- package/lib/rules/lines-around-comment.js +540 -448
- package/lib/rules/lines-around-directive.js +233 -203
- package/lib/rules/lines-between-class-members.js +305 -234
- package/lib/rules/logical-assignment-operators.js +582 -399
- package/lib/rules/max-classes-per-file.js +69 -68
- package/lib/rules/max-depth.js +146 -143
- package/lib/rules/max-len.js +473 -434
- package/lib/rules/max-lines-per-function.js +201 -176
- package/lib/rules/max-lines.js +158 -162
- package/lib/rules/max-nested-callbacks.js +102 -104
- package/lib/rules/max-params.js +78 -76
- package/lib/rules/max-statements-per-line.js +205 -198
- package/lib/rules/max-statements.js +168 -164
- package/lib/rules/multiline-comment-style.js +637 -479
- package/lib/rules/multiline-ternary.js +241 -176
- package/lib/rules/new-cap.js +233 -213
- package/lib/rules/new-parens.js +88 -79
- package/lib/rules/newline-after-var.js +287 -250
- package/lib/rules/newline-before-return.js +229 -222
- package/lib/rules/newline-per-chained-call.js +142 -127
- package/lib/rules/no-alert.js +90 -79
- package/lib/rules/no-array-constructor.js +125 -113
- package/lib/rules/no-async-promise-executor.js +30 -24
- package/lib/rules/no-await-in-loop.js +69 -71
- package/lib/rules/no-bitwise.js +124 -100
- package/lib/rules/no-buffer-constructor.js +55 -47
- package/lib/rules/no-caller.js +39 -33
- package/lib/rules/no-case-declarations.js +61 -57
- package/lib/rules/no-catch-shadow.js +76 -73
- package/lib/rules/no-class-assign.js +51 -48
- package/lib/rules/no-compare-neg-zero.js +62 -48
- package/lib/rules/no-cond-assign.js +148 -132
- package/lib/rules/no-confusing-arrow.js +98 -81
- package/lib/rules/no-console.js +202 -199
- package/lib/rules/no-const-assign.js +47 -41
- package/lib/rules/no-constant-binary-expression.js +500 -405
- package/lib/rules/no-constant-condition.js +158 -143
- package/lib/rules/no-constructor-return.js +49 -49
- package/lib/rules/no-continue.js +25 -27
- package/lib/rules/no-control-regex.js +125 -121
- package/lib/rules/no-debugger.js +28 -30
- package/lib/rules/no-delete-var.js +29 -29
- package/lib/rules/no-div-regex.js +47 -41
- package/lib/rules/no-dupe-args.js +68 -69
- package/lib/rules/no-dupe-class-members.js +102 -89
- package/lib/rules/no-dupe-else-if.js +100 -77
- package/lib/rules/no-dupe-keys.js +133 -110
- package/lib/rules/no-duplicate-case.js +50 -43
- package/lib/rules/no-duplicate-imports.js +179 -176
- package/lib/rules/no-else-return.js +430 -385
- package/lib/rules/no-empty-character-class.js +57 -50
- package/lib/rules/no-empty-function.js +127 -128
- package/lib/rules/no-empty-pattern.js +63 -58
- package/lib/rules/no-empty-static-block.js +37 -35
- package/lib/rules/no-empty.js +98 -86
- package/lib/rules/no-eq-null.js +37 -32
- package/lib/rules/no-eval.js +256 -250
- package/lib/rules/no-ex-assign.js +42 -39
- package/lib/rules/no-extend-native.js +161 -159
- package/lib/rules/no-extra-bind.js +201 -190
- package/lib/rules/no-extra-boolean-cast.js +398 -348
- package/lib/rules/no-extra-label.js +150 -131
- package/lib/rules/no-extra-parens.js +1654 -1325
- package/lib/rules/no-extra-semi.js +146 -144
- package/lib/rules/no-fallthrough.js +199 -157
- package/lib/rules/no-floating-decimal.js +74 -66
- package/lib/rules/no-func-assign.js +54 -55
- package/lib/rules/no-global-assign.js +78 -73
- package/lib/rules/no-implicit-coercion.js +349 -293
- package/lib/rules/no-implicit-globals.js +158 -135
- package/lib/rules/no-implied-eval.js +140 -112
- package/lib/rules/no-import-assign.js +145 -159
- package/lib/rules/no-inline-comments.js +101 -95
- package/lib/rules/no-inner-declarations.js +115 -101
- package/lib/rules/no-invalid-regexp.js +222 -190
- package/lib/rules/no-invalid-this.js +123 -117
- package/lib/rules/no-irregular-whitespace.js +266 -252
- package/lib/rules/no-iterator.js +29 -33
- package/lib/rules/no-label-var.js +59 -62
- package/lib/rules/no-labels.js +138 -133
- package/lib/rules/no-lone-blocks.js +127 -123
- package/lib/rules/no-lonely-if.js +108 -77
- package/lib/rules/no-loop-func.js +238 -213
- package/lib/rules/no-loss-of-precision.js +218 -201
- package/lib/rules/no-magic-numbers.js +246 -218
- package/lib/rules/no-misleading-character-class.js +499 -446
- package/lib/rules/no-mixed-operators.js +188 -182
- package/lib/rules/no-mixed-requires.js +253 -240
- package/lib/rules/no-mixed-spaces-and-tabs.js +134 -121
- package/lib/rules/no-multi-assign.js +46 -44
- package/lib/rules/no-multi-spaces.js +163 -143
- package/lib/rules/no-multi-str.js +42 -41
- package/lib/rules/no-multiple-empty-lines.js +196 -158
- package/lib/rules/no-native-reassign.js +90 -85
- package/lib/rules/no-negated-condition.js +79 -75
- package/lib/rules/no-negated-in-lhs.js +45 -43
- package/lib/rules/no-nested-ternary.js +33 -32
- package/lib/rules/no-new-func.js +71 -62
- package/lib/rules/no-new-native-nonconstructor.js +43 -39
- package/lib/rules/no-new-object.js +48 -48
- package/lib/rules/no-new-require.js +48 -47
- package/lib/rules/no-new-symbol.js +52 -50
- package/lib/rules/no-new-wrappers.js +43 -41
- package/lib/rules/no-new.js +28 -29
- package/lib/rules/no-nonoctal-decimal-escape.js +141 -121
- package/lib/rules/no-obj-calls.js +66 -53
- package/lib/rules/no-object-constructor.js +104 -97
- package/lib/rules/no-octal-escape.js +40 -43
- package/lib/rules/no-octal.js +32 -32
- package/lib/rules/no-param-reassign.js +235 -217
- package/lib/rules/no-path-concat.js +66 -67
- package/lib/rules/no-plusplus.js +60 -61
- package/lib/rules/no-process-env.js +49 -48
- package/lib/rules/no-process-exit.js +54 -50
- package/lib/rules/no-promise-executor-return.js +214 -182
- package/lib/rules/no-proto.js +26 -29
- package/lib/rules/no-prototype-builtins.js +146 -124
- package/lib/rules/no-redeclare.js +154 -152
- package/lib/rules/no-regex-spaces.js +183 -161
- package/lib/rules/no-restricted-exports.js +208 -185
- package/lib/rules/no-restricted-globals.js +111 -112
- package/lib/rules/no-restricted-imports.js +657 -537
- package/lib/rules/no-restricted-modules.js +222 -202
- package/lib/rules/no-restricted-properties.js +181 -153
- package/lib/rules/no-restricted-syntax.js +56 -52
- package/lib/rules/no-return-assign.js +55 -50
- package/lib/rules/no-return-await.js +148 -124
- package/lib/rules/no-script-url.js +52 -45
- package/lib/rules/no-self-assign.js +148 -146
- package/lib/rules/no-self-compare.js +63 -46
- package/lib/rules/no-sequences.js +135 -116
- package/lib/rules/no-setter-return.js +185 -152
- package/lib/rules/no-shadow-restricted-names.js +61 -46
- package/lib/rules/no-shadow.js +342 -316
- package/lib/rules/no-spaced-func.js +82 -77
- package/lib/rules/no-sparse-arrays.js +54 -59
- package/lib/rules/no-sync.js +61 -60
- package/lib/rules/no-tabs.js +83 -72
- package/lib/rules/no-template-curly-in-string.js +33 -32
- package/lib/rules/no-ternary.js +25 -29
- package/lib/rules/no-this-before-super.js +321 -319
- package/lib/rules/no-throw-literal.js +31 -36
- package/lib/rules/no-trailing-spaces.js +199 -191
- package/lib/rules/no-undef-init.js +76 -61
- package/lib/rules/no-undef.js +51 -48
- package/lib/rules/no-undefined.js +73 -75
- package/lib/rules/no-underscore-dangle.js +370 -327
- package/lib/rules/no-unexpected-multiline.js +112 -102
- package/lib/rules/no-unmodified-loop-condition.js +254 -254
- package/lib/rules/no-unneeded-ternary.js +212 -147
- package/lib/rules/no-unreachable-loop.js +145 -142
- package/lib/rules/no-unreachable.js +255 -248
- package/lib/rules/no-unsafe-finally.js +93 -85
- package/lib/rules/no-unsafe-negation.js +105 -83
- package/lib/rules/no-unsafe-optional-chaining.js +192 -178
- package/lib/rules/no-unused-expressions.js +178 -162
- package/lib/rules/no-unused-labels.js +139 -124
- package/lib/rules/no-unused-private-class-members.js +206 -182
- package/lib/rules/no-unused-vars.js +1669 -1449
- package/lib/rules/no-use-before-define.js +229 -231
- package/lib/rules/no-useless-assignment.js +590 -511
- package/lib/rules/no-useless-backreference.js +212 -193
- package/lib/rules/no-useless-call.js +58 -53
- package/lib/rules/no-useless-catch.js +40 -40
- package/lib/rules/no-useless-computed-key.js +144 -115
- package/lib/rules/no-useless-concat.js +65 -60
- package/lib/rules/no-useless-constructor.js +158 -111
- package/lib/rules/no-useless-escape.js +342 -291
- package/lib/rules/no-useless-rename.js +183 -156
- package/lib/rules/no-useless-return.js +344 -312
- package/lib/rules/no-var.js +233 -212
- package/lib/rules/no-void.js +50 -48
- package/lib/rules/no-warning-comments.js +191 -186
- package/lib/rules/no-whitespace-before-property.js +131 -115
- package/lib/rules/no-with.js +24 -26
- package/lib/rules/nonblock-statement-body-position.js +149 -130
- package/lib/rules/object-curly-newline.js +306 -265
- package/lib/rules/object-curly-spacing.js +360 -314
- package/lib/rules/object-property-newline.js +137 -106
- package/lib/rules/object-shorthand.js +607 -502
- package/lib/rules/one-var-declaration-per-line.js +104 -100
- package/lib/rules/one-var.js +653 -537
- package/lib/rules/operator-assignment.js +219 -161
- package/lib/rules/operator-linebreak.js +295 -251
- package/lib/rules/padded-blocks.js +346 -308
- package/lib/rules/padding-line-between-statements.js +443 -439
- package/lib/rules/prefer-arrow-callback.js +362 -313
- package/lib/rules/prefer-const.js +418 -377
- package/lib/rules/prefer-destructuring.js +301 -279
- package/lib/rules/prefer-exponentiation-operator.js +176 -133
- package/lib/rules/prefer-named-capture-group.js +153 -140
- package/lib/rules/prefer-numeric-literals.js +121 -113
- package/lib/rules/prefer-object-has-own.js +116 -82
- package/lib/rules/prefer-object-spread.js +213 -193
- package/lib/rules/prefer-promise-reject-errors.js +140 -122
- package/lib/rules/prefer-reflect.js +127 -107
- package/lib/rules/prefer-regex-literals.js +578 -466
- package/lib/rules/prefer-rest-params.js +79 -80
- package/lib/rules/prefer-spread.js +47 -44
- package/lib/rules/prefer-template.js +266 -195
- package/lib/rules/quote-props.js +373 -307
- package/lib/rules/quotes.js +374 -326
- package/lib/rules/radix.js +152 -136
- package/lib/rules/require-atomic-updates.js +316 -285
- package/lib/rules/require-await.js +144 -116
- package/lib/rules/require-unicode-regexp.js +282 -177
- package/lib/rules/require-yield.js +53 -54
- package/lib/rules/rest-spread-spacing.js +128 -116
- package/lib/rules/semi-spacing.js +281 -250
- package/lib/rules/semi-style.js +176 -134
- package/lib/rules/semi.js +456 -436
- package/lib/rules/sort-imports.js +306 -233
- package/lib/rules/sort-keys.js +219 -188
- package/lib/rules/sort-vars.js +127 -93
- package/lib/rules/space-before-blocks.js +199 -189
- package/lib/rules/space-before-function-paren.js +186 -166
- package/lib/rules/space-in-parens.js +359 -288
- package/lib/rules/space-infix-ops.js +237 -201
- package/lib/rules/space-unary-ops.js +356 -298
- package/lib/rules/spaced-comment.js +363 -319
- package/lib/rules/strict.js +265 -230
- package/lib/rules/switch-colon-spacing.js +130 -122
- package/lib/rules/symbol-description.js +45 -48
- package/lib/rules/template-curly-spacing.js +148 -142
- package/lib/rules/template-tag-spacing.js +98 -88
- package/lib/rules/unicode-bom.js +54 -56
- package/lib/rules/use-isnan.js +237 -206
- package/lib/rules/utils/ast-utils.js +2039 -1860
- package/lib/rules/utils/char-source.js +162 -155
- package/lib/rules/utils/fix-tracker.js +83 -80
- package/lib/rules/utils/keywords.js +59 -59
- package/lib/rules/utils/lazy-loading-rule-map.js +79 -76
- package/lib/rules/utils/regular-expressions.js +32 -24
- package/lib/rules/utils/unicode/index.js +4 -4
- package/lib/rules/utils/unicode/is-combining-character.js +1 -1
- package/lib/rules/utils/unicode/is-emoji-modifier.js +1 -1
- package/lib/rules/utils/unicode/is-regional-indicator-symbol.js +1 -1
- package/lib/rules/utils/unicode/is-surrogate-pair.js +1 -1
- package/lib/rules/valid-typeof.js +153 -111
- package/lib/rules/vars-on-top.js +152 -145
- package/lib/rules/wrap-iife.js +204 -191
- package/lib/rules/wrap-regex.js +70 -58
- package/lib/rules/yield-star-spacing.js +145 -134
- package/lib/rules/yoda.js +283 -272
- package/lib/services/parser-service.js +35 -35
- package/lib/services/processor-service.js +66 -73
- package/lib/services/suppressions-service.js +289 -0
- package/lib/shared/ajv.js +14 -14
- package/lib/shared/assert.js +3 -4
- package/lib/shared/ast-utils.js +7 -6
- package/lib/shared/deep-merge-arrays.js +24 -22
- package/lib/shared/directives.js +3 -2
- package/lib/shared/flags.js +50 -17
- package/lib/shared/logging.js +24 -25
- package/lib/shared/option-utils.js +43 -36
- package/lib/shared/runtime-info.js +136 -127
- package/lib/shared/serialization.js +27 -27
- package/lib/shared/severity.js +22 -22
- package/lib/shared/stats.js +5 -5
- package/lib/shared/string-utils.js +16 -16
- package/lib/shared/text-table.js +28 -27
- package/lib/shared/traverser.js +153 -146
- package/lib/shared/types.js +4 -27
- package/lib/types/index.d.ts +2010 -1559
- package/lib/types/rules.d.ts +5253 -5140
- package/lib/types/use-at-your-own-risk.d.ts +32 -30
- package/lib/unsupported-api.js +5 -5
- package/messages/all-files-ignored.js +3 -3
- package/messages/all-matched-files-ignored.js +3 -3
- package/messages/config-file-missing.js +2 -2
- package/messages/config-plugin-missing.js +3 -3
- package/messages/config-serialize-function.js +9 -7
- package/messages/eslintrc-incompat.js +13 -15
- package/messages/eslintrc-plugins.js +3 -4
- package/messages/extend-config-missing.js +3 -3
- package/messages/failed-to-read-json.js +3 -3
- package/messages/file-not-found.js +3 -3
- package/messages/invalid-rule-options.js +2 -2
- package/messages/invalid-rule-severity.js +2 -2
- package/messages/no-config-found.js +3 -3
- package/messages/plugin-conflict.js +8 -8
- package/messages/plugin-invalid.js +3 -3
- package/messages/plugin-missing.js +3 -3
- package/messages/print-config-with-directory-path.js +2 -2
- package/messages/shared.js +6 -1
- package/messages/whitespace-found.js +3 -3
- package/package.json +14 -20
@@ -39,1454 +39,1674 @@ const astUtils = require("./utils/ast-utils");
|
|
39
39
|
// Rule Definition
|
40
40
|
//------------------------------------------------------------------------------
|
41
41
|
|
42
|
-
/** @type {import('../
|
42
|
+
/** @type {import('../types').Rule.RuleModule} */
|
43
43
|
module.exports = {
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
44
|
+
meta: {
|
45
|
+
type: "problem",
|
46
|
+
|
47
|
+
docs: {
|
48
|
+
description: "Disallow unused variables",
|
49
|
+
recommended: true,
|
50
|
+
url: "https://eslint.org/docs/latest/rules/no-unused-vars",
|
51
|
+
},
|
52
|
+
|
53
|
+
hasSuggestions: true,
|
54
|
+
|
55
|
+
schema: [
|
56
|
+
{
|
57
|
+
oneOf: [
|
58
|
+
{
|
59
|
+
enum: ["all", "local"],
|
60
|
+
},
|
61
|
+
{
|
62
|
+
type: "object",
|
63
|
+
properties: {
|
64
|
+
vars: {
|
65
|
+
enum: ["all", "local"],
|
66
|
+
},
|
67
|
+
varsIgnorePattern: {
|
68
|
+
type: "string",
|
69
|
+
},
|
70
|
+
args: {
|
71
|
+
enum: ["all", "after-used", "none"],
|
72
|
+
},
|
73
|
+
ignoreRestSiblings: {
|
74
|
+
type: "boolean",
|
75
|
+
},
|
76
|
+
argsIgnorePattern: {
|
77
|
+
type: "string",
|
78
|
+
},
|
79
|
+
caughtErrors: {
|
80
|
+
enum: ["all", "none"],
|
81
|
+
},
|
82
|
+
caughtErrorsIgnorePattern: {
|
83
|
+
type: "string",
|
84
|
+
},
|
85
|
+
destructuredArrayIgnorePattern: {
|
86
|
+
type: "string",
|
87
|
+
},
|
88
|
+
ignoreClassWithStaticInitBlock: {
|
89
|
+
type: "boolean",
|
90
|
+
},
|
91
|
+
reportUsedIgnorePattern: {
|
92
|
+
type: "boolean",
|
93
|
+
},
|
94
|
+
},
|
95
|
+
additionalProperties: false,
|
96
|
+
},
|
97
|
+
],
|
98
|
+
},
|
99
|
+
],
|
100
|
+
|
101
|
+
messages: {
|
102
|
+
unusedVar:
|
103
|
+
"'{{varName}}' is {{action}} but never used{{additional}}.",
|
104
|
+
usedIgnoredVar:
|
105
|
+
"'{{varName}}' is marked as ignored but is used{{additional}}.",
|
106
|
+
removeVar: "Remove unused variable '{{varName}}'.",
|
107
|
+
},
|
108
|
+
},
|
109
|
+
|
110
|
+
create(context) {
|
111
|
+
const sourceCode = context.sourceCode;
|
112
|
+
|
113
|
+
const REST_PROPERTY_TYPE =
|
114
|
+
/^(?:RestElement|(?:Experimental)?RestProperty)$/u;
|
115
|
+
|
116
|
+
const config = {
|
117
|
+
vars: "all",
|
118
|
+
args: "after-used",
|
119
|
+
ignoreRestSiblings: false,
|
120
|
+
caughtErrors: "all",
|
121
|
+
ignoreClassWithStaticInitBlock: false,
|
122
|
+
reportUsedIgnorePattern: false,
|
123
|
+
};
|
124
|
+
|
125
|
+
const firstOption = context.options[0];
|
126
|
+
|
127
|
+
if (firstOption) {
|
128
|
+
if (typeof firstOption === "string") {
|
129
|
+
config.vars = firstOption;
|
130
|
+
} else {
|
131
|
+
config.vars = firstOption.vars || config.vars;
|
132
|
+
config.args = firstOption.args || config.args;
|
133
|
+
config.ignoreRestSiblings =
|
134
|
+
firstOption.ignoreRestSiblings || config.ignoreRestSiblings;
|
135
|
+
config.caughtErrors =
|
136
|
+
firstOption.caughtErrors || config.caughtErrors;
|
137
|
+
config.ignoreClassWithStaticInitBlock =
|
138
|
+
firstOption.ignoreClassWithStaticInitBlock ||
|
139
|
+
config.ignoreClassWithStaticInitBlock;
|
140
|
+
config.reportUsedIgnorePattern =
|
141
|
+
firstOption.reportUsedIgnorePattern ||
|
142
|
+
config.reportUsedIgnorePattern;
|
143
|
+
|
144
|
+
if (firstOption.varsIgnorePattern) {
|
145
|
+
config.varsIgnorePattern = new RegExp(
|
146
|
+
firstOption.varsIgnorePattern,
|
147
|
+
"u",
|
148
|
+
);
|
149
|
+
}
|
150
|
+
|
151
|
+
if (firstOption.argsIgnorePattern) {
|
152
|
+
config.argsIgnorePattern = new RegExp(
|
153
|
+
firstOption.argsIgnorePattern,
|
154
|
+
"u",
|
155
|
+
);
|
156
|
+
}
|
157
|
+
|
158
|
+
if (firstOption.caughtErrorsIgnorePattern) {
|
159
|
+
config.caughtErrorsIgnorePattern = new RegExp(
|
160
|
+
firstOption.caughtErrorsIgnorePattern,
|
161
|
+
"u",
|
162
|
+
);
|
163
|
+
}
|
164
|
+
|
165
|
+
if (firstOption.destructuredArrayIgnorePattern) {
|
166
|
+
config.destructuredArrayIgnorePattern = new RegExp(
|
167
|
+
firstOption.destructuredArrayIgnorePattern,
|
168
|
+
"u",
|
169
|
+
);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
/**
|
175
|
+
* Determines what variable type a def is.
|
176
|
+
* @param {Object} def the declaration to check
|
177
|
+
* @returns {VariableType} a simple name for the types of variables that this rule supports
|
178
|
+
*/
|
179
|
+
function defToVariableType(def) {
|
180
|
+
/*
|
181
|
+
* This `destructuredArrayIgnorePattern` error report works differently from the catch
|
182
|
+
* clause and parameter error reports. _Both_ the `varsIgnorePattern` and the
|
183
|
+
* `destructuredArrayIgnorePattern` will be checked for array destructuring. However,
|
184
|
+
* for the purposes of the report, the currently defined behavior is to only inform the
|
185
|
+
* user of the `destructuredArrayIgnorePattern` if it's present (regardless of the fact
|
186
|
+
* that the `varsIgnorePattern` would also apply). If it's not present, the user will be
|
187
|
+
* informed of the `varsIgnorePattern`, assuming that's present.
|
188
|
+
*/
|
189
|
+
if (
|
190
|
+
config.destructuredArrayIgnorePattern &&
|
191
|
+
def.name.parent.type === "ArrayPattern"
|
192
|
+
) {
|
193
|
+
return "array-destructure";
|
194
|
+
}
|
195
|
+
|
196
|
+
switch (def.type) {
|
197
|
+
case "CatchClause":
|
198
|
+
return "catch-clause";
|
199
|
+
case "Parameter":
|
200
|
+
return "parameter";
|
201
|
+
|
202
|
+
default:
|
203
|
+
return "variable";
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
/**
|
208
|
+
* Gets a given variable's description and configured ignore pattern
|
209
|
+
* based on the provided variableType
|
210
|
+
* @param {VariableType} variableType a simple name for the types of variables that this rule supports
|
211
|
+
* @throws {Error} (Unreachable)
|
212
|
+
* @returns {[string | undefined, string | undefined]} the given variable's description and
|
213
|
+
* ignore pattern
|
214
|
+
*/
|
215
|
+
function getVariableDescription(variableType) {
|
216
|
+
let pattern;
|
217
|
+
let variableDescription;
|
218
|
+
|
219
|
+
switch (variableType) {
|
220
|
+
case "array-destructure":
|
221
|
+
pattern = config.destructuredArrayIgnorePattern;
|
222
|
+
variableDescription = "elements of array destructuring";
|
223
|
+
break;
|
224
|
+
|
225
|
+
case "catch-clause":
|
226
|
+
pattern = config.caughtErrorsIgnorePattern;
|
227
|
+
variableDescription = "caught errors";
|
228
|
+
break;
|
229
|
+
|
230
|
+
case "parameter":
|
231
|
+
pattern = config.argsIgnorePattern;
|
232
|
+
variableDescription = "args";
|
233
|
+
break;
|
234
|
+
|
235
|
+
case "variable":
|
236
|
+
pattern = config.varsIgnorePattern;
|
237
|
+
variableDescription = "vars";
|
238
|
+
break;
|
239
|
+
|
240
|
+
default:
|
241
|
+
throw new Error(
|
242
|
+
`Unexpected variable type: ${variableType}`,
|
243
|
+
);
|
244
|
+
}
|
245
|
+
|
246
|
+
if (pattern) {
|
247
|
+
pattern = pattern.toString();
|
248
|
+
}
|
249
|
+
|
250
|
+
return [variableDescription, pattern];
|
251
|
+
}
|
252
|
+
|
253
|
+
/**
|
254
|
+
* Generates the message data about the variable being defined and unused,
|
255
|
+
* including the ignore pattern if configured.
|
256
|
+
* @param {Variable} unusedVar eslint-scope variable object.
|
257
|
+
* @returns {UnusedVarMessageData} The message data to be used with this unused variable.
|
258
|
+
*/
|
259
|
+
function getDefinedMessageData(unusedVar) {
|
260
|
+
const def = unusedVar.defs && unusedVar.defs[0];
|
261
|
+
let additionalMessageData = "";
|
262
|
+
|
263
|
+
if (def) {
|
264
|
+
const [variableDescription, pattern] = getVariableDescription(
|
265
|
+
defToVariableType(def),
|
266
|
+
);
|
267
|
+
|
268
|
+
if (pattern && variableDescription) {
|
269
|
+
additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`;
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
return {
|
274
|
+
varName: unusedVar.name,
|
275
|
+
action: "defined",
|
276
|
+
additional: additionalMessageData,
|
277
|
+
};
|
278
|
+
}
|
279
|
+
|
280
|
+
/**
|
281
|
+
* Generate the warning message about the variable being
|
282
|
+
* assigned and unused, including the ignore pattern if configured.
|
283
|
+
* @param {Variable} unusedVar eslint-scope variable object.
|
284
|
+
* @returns {UnusedVarMessageData} The message data to be used with this unused variable.
|
285
|
+
*/
|
286
|
+
function getAssignedMessageData(unusedVar) {
|
287
|
+
const def = unusedVar.defs && unusedVar.defs[0];
|
288
|
+
let additionalMessageData = "";
|
289
|
+
|
290
|
+
if (def) {
|
291
|
+
const [variableDescription, pattern] = getVariableDescription(
|
292
|
+
defToVariableType(def),
|
293
|
+
);
|
294
|
+
|
295
|
+
if (pattern && variableDescription) {
|
296
|
+
additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
300
|
+
return {
|
301
|
+
varName: unusedVar.name,
|
302
|
+
action: "assigned a value",
|
303
|
+
additional: additionalMessageData,
|
304
|
+
};
|
305
|
+
}
|
306
|
+
|
307
|
+
/**
|
308
|
+
* Generate the warning message about a variable being used even though
|
309
|
+
* it is marked as being ignored.
|
310
|
+
* @param {Variable} variable eslint-scope variable object
|
311
|
+
* @param {VariableType} variableType a simple name for the types of variables that this rule supports
|
312
|
+
* @returns {UsedIgnoredVarMessageData} The message data to be used with
|
313
|
+
* this used ignored variable.
|
314
|
+
*/
|
315
|
+
function getUsedIgnoredMessageData(variable, variableType) {
|
316
|
+
const [variableDescription, pattern] =
|
317
|
+
getVariableDescription(variableType);
|
318
|
+
|
319
|
+
let additionalMessageData = "";
|
320
|
+
|
321
|
+
if (pattern && variableDescription) {
|
322
|
+
additionalMessageData = `. Used ${variableDescription} must not match ${pattern}`;
|
323
|
+
}
|
324
|
+
|
325
|
+
return {
|
326
|
+
varName: variable.name,
|
327
|
+
additional: additionalMessageData,
|
328
|
+
};
|
329
|
+
}
|
330
|
+
|
331
|
+
//--------------------------------------------------------------------------
|
332
|
+
// Helpers
|
333
|
+
//--------------------------------------------------------------------------
|
334
|
+
|
335
|
+
const STATEMENT_TYPE = /(?:Statement|Declaration)$/u;
|
336
|
+
|
337
|
+
/**
|
338
|
+
* Determines if a given variable is being exported from a module.
|
339
|
+
* @param {Variable} variable eslint-scope variable object.
|
340
|
+
* @returns {boolean} True if the variable is exported, false if not.
|
341
|
+
* @private
|
342
|
+
*/
|
343
|
+
function isExported(variable) {
|
344
|
+
const definition = variable.defs[0];
|
345
|
+
|
346
|
+
if (definition) {
|
347
|
+
let node = definition.node;
|
348
|
+
|
349
|
+
if (node.type === "VariableDeclarator") {
|
350
|
+
node = node.parent;
|
351
|
+
} else if (definition.type === "Parameter") {
|
352
|
+
return false;
|
353
|
+
}
|
354
|
+
|
355
|
+
return node.parent.type.indexOf("Export") === 0;
|
356
|
+
}
|
357
|
+
return false;
|
358
|
+
}
|
359
|
+
|
360
|
+
/**
|
361
|
+
* Checks whether a node is a sibling of the rest property or not.
|
362
|
+
* @param {ASTNode} node a node to check
|
363
|
+
* @returns {boolean} True if the node is a sibling of the rest property, otherwise false.
|
364
|
+
*/
|
365
|
+
function hasRestSibling(node) {
|
366
|
+
return (
|
367
|
+
node.type === "Property" &&
|
368
|
+
node.parent.type === "ObjectPattern" &&
|
369
|
+
REST_PROPERTY_TYPE.test(node.parent.properties.at(-1).type)
|
370
|
+
);
|
371
|
+
}
|
372
|
+
|
373
|
+
/**
|
374
|
+
* Determines if a variable has a sibling rest property
|
375
|
+
* @param {Variable} variable eslint-scope variable object.
|
376
|
+
* @returns {boolean} True if the variable has a sibling rest property, false if not.
|
377
|
+
* @private
|
378
|
+
*/
|
379
|
+
function hasRestSpreadSibling(variable) {
|
380
|
+
if (config.ignoreRestSiblings) {
|
381
|
+
const hasRestSiblingDefinition = variable.defs.some(def =>
|
382
|
+
hasRestSibling(def.name.parent),
|
383
|
+
);
|
384
|
+
const hasRestSiblingReference = variable.references.some(ref =>
|
385
|
+
hasRestSibling(ref.identifier.parent),
|
386
|
+
);
|
387
|
+
|
388
|
+
return hasRestSiblingDefinition || hasRestSiblingReference;
|
389
|
+
}
|
390
|
+
|
391
|
+
return false;
|
392
|
+
}
|
393
|
+
|
394
|
+
/**
|
395
|
+
* Determines if a reference is a read operation.
|
396
|
+
* @param {Reference} ref An eslint-scope Reference
|
397
|
+
* @returns {boolean} whether the given reference represents a read operation
|
398
|
+
* @private
|
399
|
+
*/
|
400
|
+
function isReadRef(ref) {
|
401
|
+
return ref.isRead();
|
402
|
+
}
|
403
|
+
|
404
|
+
/**
|
405
|
+
* Determine if an identifier is referencing an enclosing function name.
|
406
|
+
* @param {Reference} ref The reference to check.
|
407
|
+
* @param {ASTNode[]} nodes The candidate function nodes.
|
408
|
+
* @returns {boolean} True if it's a self-reference, false if not.
|
409
|
+
* @private
|
410
|
+
*/
|
411
|
+
function isSelfReference(ref, nodes) {
|
412
|
+
let scope = ref.from;
|
413
|
+
|
414
|
+
while (scope) {
|
415
|
+
if (nodes.includes(scope.block)) {
|
416
|
+
return true;
|
417
|
+
}
|
418
|
+
|
419
|
+
scope = scope.upper;
|
420
|
+
}
|
421
|
+
|
422
|
+
return false;
|
423
|
+
}
|
424
|
+
|
425
|
+
/**
|
426
|
+
* Gets a list of function definitions for a specified variable.
|
427
|
+
* @param {Variable} variable eslint-scope variable object.
|
428
|
+
* @returns {ASTNode[]} Function nodes.
|
429
|
+
* @private
|
430
|
+
*/
|
431
|
+
function getFunctionDefinitions(variable) {
|
432
|
+
const functionDefinitions = [];
|
433
|
+
|
434
|
+
variable.defs.forEach(def => {
|
435
|
+
const { type, node } = def;
|
436
|
+
|
437
|
+
// FunctionDeclarations
|
438
|
+
if (type === "FunctionName") {
|
439
|
+
functionDefinitions.push(node);
|
440
|
+
}
|
441
|
+
|
442
|
+
// FunctionExpressions
|
443
|
+
if (
|
444
|
+
type === "Variable" &&
|
445
|
+
node.init &&
|
446
|
+
(node.init.type === "FunctionExpression" ||
|
447
|
+
node.init.type === "ArrowFunctionExpression")
|
448
|
+
) {
|
449
|
+
functionDefinitions.push(node.init);
|
450
|
+
}
|
451
|
+
});
|
452
|
+
return functionDefinitions;
|
453
|
+
}
|
454
|
+
|
455
|
+
/**
|
456
|
+
* Checks the position of given nodes.
|
457
|
+
* @param {ASTNode} inner A node which is expected as inside.
|
458
|
+
* @param {ASTNode} outer A node which is expected as outside.
|
459
|
+
* @returns {boolean} `true` if the `inner` node exists in the `outer` node.
|
460
|
+
* @private
|
461
|
+
*/
|
462
|
+
function isInside(inner, outer) {
|
463
|
+
return (
|
464
|
+
inner.range[0] >= outer.range[0] &&
|
465
|
+
inner.range[1] <= outer.range[1]
|
466
|
+
);
|
467
|
+
}
|
468
|
+
|
469
|
+
/**
|
470
|
+
* Checks whether a given node is unused expression or not.
|
471
|
+
* @param {ASTNode} node The node itself
|
472
|
+
* @returns {boolean} The node is an unused expression.
|
473
|
+
* @private
|
474
|
+
*/
|
475
|
+
function isUnusedExpression(node) {
|
476
|
+
const parent = node.parent;
|
477
|
+
|
478
|
+
if (parent.type === "ExpressionStatement") {
|
479
|
+
return true;
|
480
|
+
}
|
481
|
+
|
482
|
+
if (parent.type === "SequenceExpression") {
|
483
|
+
const isLastExpression = parent.expressions.at(-1) === node;
|
484
|
+
|
485
|
+
if (!isLastExpression) {
|
486
|
+
return true;
|
487
|
+
}
|
488
|
+
return isUnusedExpression(parent);
|
489
|
+
}
|
490
|
+
|
491
|
+
return false;
|
492
|
+
}
|
493
|
+
|
494
|
+
/**
|
495
|
+
* If a given reference is left-hand side of an assignment, this gets
|
496
|
+
* the right-hand side node of the assignment.
|
497
|
+
*
|
498
|
+
* In the following cases, this returns null.
|
499
|
+
*
|
500
|
+
* - The reference is not the LHS of an assignment expression.
|
501
|
+
* - The reference is inside of a loop.
|
502
|
+
* - The reference is inside of a function scope which is different from
|
503
|
+
* the declaration.
|
504
|
+
* @param {eslint-scope.Reference} ref A reference to check.
|
505
|
+
* @param {ASTNode} prevRhsNode The previous RHS node.
|
506
|
+
* @returns {ASTNode|null} The RHS node or null.
|
507
|
+
* @private
|
508
|
+
*/
|
509
|
+
function getRhsNode(ref, prevRhsNode) {
|
510
|
+
const id = ref.identifier;
|
511
|
+
const parent = id.parent;
|
512
|
+
const refScope = ref.from.variableScope;
|
513
|
+
const varScope = ref.resolved.scope.variableScope;
|
514
|
+
const canBeUsedLater =
|
515
|
+
refScope !== varScope || astUtils.isInLoop(id);
|
516
|
+
|
517
|
+
/*
|
518
|
+
* Inherits the previous node if this reference is in the node.
|
519
|
+
* This is for `a = a + a`-like code.
|
520
|
+
*/
|
521
|
+
if (prevRhsNode && isInside(id, prevRhsNode)) {
|
522
|
+
return prevRhsNode;
|
523
|
+
}
|
524
|
+
|
525
|
+
if (
|
526
|
+
parent.type === "AssignmentExpression" &&
|
527
|
+
isUnusedExpression(parent) &&
|
528
|
+
id === parent.left &&
|
529
|
+
!canBeUsedLater
|
530
|
+
) {
|
531
|
+
return parent.right;
|
532
|
+
}
|
533
|
+
return null;
|
534
|
+
}
|
535
|
+
|
536
|
+
/**
|
537
|
+
* Checks whether a given function node is stored to somewhere or not.
|
538
|
+
* If the function node is stored, the function can be used later.
|
539
|
+
* @param {ASTNode} funcNode A function node to check.
|
540
|
+
* @param {ASTNode} rhsNode The RHS node of the previous assignment.
|
541
|
+
* @returns {boolean} `true` if under the following conditions:
|
542
|
+
* - the funcNode is assigned to a variable.
|
543
|
+
* - the funcNode is bound as an argument of a function call.
|
544
|
+
* - the function is bound to a property and the object satisfies above conditions.
|
545
|
+
* @private
|
546
|
+
*/
|
547
|
+
function isStorableFunction(funcNode, rhsNode) {
|
548
|
+
let node = funcNode;
|
549
|
+
let parent = funcNode.parent;
|
550
|
+
|
551
|
+
while (parent && isInside(parent, rhsNode)) {
|
552
|
+
switch (parent.type) {
|
553
|
+
case "SequenceExpression":
|
554
|
+
if (parent.expressions.at(-1) !== node) {
|
555
|
+
return false;
|
556
|
+
}
|
557
|
+
break;
|
558
|
+
|
559
|
+
case "CallExpression":
|
560
|
+
case "NewExpression":
|
561
|
+
return parent.callee !== node;
|
562
|
+
|
563
|
+
case "AssignmentExpression":
|
564
|
+
case "TaggedTemplateExpression":
|
565
|
+
case "YieldExpression":
|
566
|
+
return true;
|
567
|
+
|
568
|
+
default:
|
569
|
+
if (STATEMENT_TYPE.test(parent.type)) {
|
570
|
+
/*
|
571
|
+
* If it encountered statements, this is a complex pattern.
|
572
|
+
* Since analyzing complex patterns is hard, this returns `true` to avoid false positive.
|
573
|
+
*/
|
574
|
+
return true;
|
575
|
+
}
|
576
|
+
}
|
577
|
+
|
578
|
+
node = parent;
|
579
|
+
parent = parent.parent;
|
580
|
+
}
|
581
|
+
|
582
|
+
return false;
|
583
|
+
}
|
584
|
+
|
585
|
+
/**
|
586
|
+
* Checks whether a given Identifier node exists inside of a function node which can be used later.
|
587
|
+
*
|
588
|
+
* "can be used later" means:
|
589
|
+
* - the function is assigned to a variable.
|
590
|
+
* - the function is bound to a property and the object can be used later.
|
591
|
+
* - the function is bound as an argument of a function call.
|
592
|
+
*
|
593
|
+
* If a reference exists in a function which can be used later, the reference is read when the function is called.
|
594
|
+
* @param {ASTNode} id An Identifier node to check.
|
595
|
+
* @param {ASTNode} rhsNode The RHS node of the previous assignment.
|
596
|
+
* @returns {boolean} `true` if the `id` node exists inside of a function node which can be used later.
|
597
|
+
* @private
|
598
|
+
*/
|
599
|
+
function isInsideOfStorableFunction(id, rhsNode) {
|
600
|
+
const funcNode = astUtils.getUpperFunction(id);
|
601
|
+
|
602
|
+
return (
|
603
|
+
funcNode &&
|
604
|
+
isInside(funcNode, rhsNode) &&
|
605
|
+
isStorableFunction(funcNode, rhsNode)
|
606
|
+
);
|
607
|
+
}
|
608
|
+
|
609
|
+
/**
|
610
|
+
* Checks whether a given reference is a read to update itself or not.
|
611
|
+
* @param {eslint-scope.Reference} ref A reference to check.
|
612
|
+
* @param {ASTNode} rhsNode The RHS node of the previous assignment.
|
613
|
+
* @returns {boolean} The reference is a read to update itself.
|
614
|
+
* @private
|
615
|
+
*/
|
616
|
+
function isReadForItself(ref, rhsNode) {
|
617
|
+
const id = ref.identifier;
|
618
|
+
const parent = id.parent;
|
619
|
+
|
620
|
+
return (
|
621
|
+
ref.isRead() &&
|
622
|
+
// self update. e.g. `a += 1`, `a++`
|
623
|
+
((parent.type === "AssignmentExpression" &&
|
624
|
+
parent.left === id &&
|
625
|
+
isUnusedExpression(parent) &&
|
626
|
+
!astUtils.isLogicalAssignmentOperator(parent.operator)) ||
|
627
|
+
(parent.type === "UpdateExpression" &&
|
628
|
+
isUnusedExpression(parent)) ||
|
629
|
+
// in RHS of an assignment for itself. e.g. `a = a + 1`
|
630
|
+
(rhsNode &&
|
631
|
+
isInside(id, rhsNode) &&
|
632
|
+
!isInsideOfStorableFunction(id, rhsNode)))
|
633
|
+
);
|
634
|
+
}
|
635
|
+
|
636
|
+
/**
|
637
|
+
* Determine if an identifier is used either in for-in or for-of loops.
|
638
|
+
* @param {Reference} ref The reference to check.
|
639
|
+
* @returns {boolean} whether reference is used in the for-in loops
|
640
|
+
* @private
|
641
|
+
*/
|
642
|
+
function isForInOfRef(ref) {
|
643
|
+
let target = ref.identifier.parent;
|
644
|
+
|
645
|
+
// "for (var ...) { return; }"
|
646
|
+
if (target.type === "VariableDeclarator") {
|
647
|
+
target = target.parent.parent;
|
648
|
+
}
|
649
|
+
|
650
|
+
if (
|
651
|
+
target.type !== "ForInStatement" &&
|
652
|
+
target.type !== "ForOfStatement"
|
653
|
+
) {
|
654
|
+
return false;
|
655
|
+
}
|
656
|
+
|
657
|
+
// "for (...) { return; }"
|
658
|
+
if (target.body.type === "BlockStatement") {
|
659
|
+
target = target.body.body[0];
|
660
|
+
|
661
|
+
// "for (...) return;"
|
662
|
+
} else {
|
663
|
+
target = target.body;
|
664
|
+
}
|
665
|
+
|
666
|
+
// For empty loop body
|
667
|
+
if (!target) {
|
668
|
+
return false;
|
669
|
+
}
|
670
|
+
|
671
|
+
return target.type === "ReturnStatement";
|
672
|
+
}
|
673
|
+
|
674
|
+
/**
|
675
|
+
* Determines if the variable is used.
|
676
|
+
* @param {Variable} variable The variable to check.
|
677
|
+
* @returns {boolean} True if the variable is used
|
678
|
+
* @private
|
679
|
+
*/
|
680
|
+
function isUsedVariable(variable) {
|
681
|
+
if (variable.eslintUsed) {
|
682
|
+
return true;
|
683
|
+
}
|
684
|
+
|
685
|
+
const functionNodes = getFunctionDefinitions(variable);
|
686
|
+
const isFunctionDefinition = functionNodes.length > 0;
|
687
|
+
|
688
|
+
let rhsNode = null;
|
689
|
+
|
690
|
+
return variable.references.some(ref => {
|
691
|
+
if (isForInOfRef(ref)) {
|
692
|
+
return true;
|
693
|
+
}
|
694
|
+
|
695
|
+
const forItself = isReadForItself(ref, rhsNode);
|
696
|
+
|
697
|
+
rhsNode = getRhsNode(ref, rhsNode);
|
698
|
+
|
699
|
+
return (
|
700
|
+
isReadRef(ref) &&
|
701
|
+
!forItself &&
|
702
|
+
!(
|
703
|
+
isFunctionDefinition &&
|
704
|
+
isSelfReference(ref, functionNodes)
|
705
|
+
)
|
706
|
+
);
|
707
|
+
});
|
708
|
+
}
|
709
|
+
|
710
|
+
/**
|
711
|
+
* Checks whether the given variable is after the last used parameter.
|
712
|
+
* @param {eslint-scope.Variable} variable The variable to check.
|
713
|
+
* @returns {boolean} `true` if the variable is defined after the last
|
714
|
+
* used parameter.
|
715
|
+
*/
|
716
|
+
function isAfterLastUsedArg(variable) {
|
717
|
+
const def = variable.defs[0];
|
718
|
+
const params = sourceCode.getDeclaredVariables(def.node);
|
719
|
+
const posteriorParams = params.slice(params.indexOf(variable) + 1);
|
720
|
+
|
721
|
+
// If any used parameters occur after this parameter, do not report.
|
722
|
+
return !posteriorParams.some(
|
723
|
+
v => v.references.length > 0 || v.eslintUsed,
|
724
|
+
);
|
725
|
+
}
|
726
|
+
|
727
|
+
/**
|
728
|
+
* Gets an array of variables without read references.
|
729
|
+
* @param {Scope} scope an eslint-scope Scope object.
|
730
|
+
* @param {Variable[]} unusedVars an array that saving result.
|
731
|
+
* @returns {Variable[]} unused variables of the scope and descendant scopes.
|
732
|
+
* @private
|
733
|
+
*/
|
734
|
+
function collectUnusedVariables(scope, unusedVars) {
|
735
|
+
const variables = scope.variables;
|
736
|
+
const childScopes = scope.childScopes;
|
737
|
+
let i, l;
|
738
|
+
|
739
|
+
if (scope.type !== "global" || config.vars === "all") {
|
740
|
+
for (i = 0, l = variables.length; i < l; ++i) {
|
741
|
+
const variable = variables[i];
|
742
|
+
|
743
|
+
// skip a variable of class itself name in the class scope
|
744
|
+
if (
|
745
|
+
scope.type === "class" &&
|
746
|
+
scope.block.id === variable.identifiers[0]
|
747
|
+
) {
|
748
|
+
continue;
|
749
|
+
}
|
750
|
+
|
751
|
+
// skip function expression names
|
752
|
+
if (scope.functionExpressionScope) {
|
753
|
+
continue;
|
754
|
+
}
|
755
|
+
|
756
|
+
// skip variables marked with markVariableAsUsed()
|
757
|
+
if (
|
758
|
+
!config.reportUsedIgnorePattern &&
|
759
|
+
variable.eslintUsed
|
760
|
+
) {
|
761
|
+
continue;
|
762
|
+
}
|
763
|
+
|
764
|
+
// skip implicit "arguments" variable
|
765
|
+
if (
|
766
|
+
scope.type === "function" &&
|
767
|
+
variable.name === "arguments" &&
|
768
|
+
variable.identifiers.length === 0
|
769
|
+
) {
|
770
|
+
continue;
|
771
|
+
}
|
772
|
+
|
773
|
+
// explicit global variables don't have definitions.
|
774
|
+
const def = variable.defs[0];
|
775
|
+
|
776
|
+
if (def) {
|
777
|
+
const type = def.type;
|
778
|
+
const refUsedInArrayPatterns = variable.references.some(
|
779
|
+
ref =>
|
780
|
+
ref.identifier.parent.type === "ArrayPattern",
|
781
|
+
);
|
782
|
+
|
783
|
+
// skip elements of array destructuring patterns
|
784
|
+
if (
|
785
|
+
(def.name.parent.type === "ArrayPattern" ||
|
786
|
+
refUsedInArrayPatterns) &&
|
787
|
+
config.destructuredArrayIgnorePattern &&
|
788
|
+
config.destructuredArrayIgnorePattern.test(
|
789
|
+
def.name.name,
|
790
|
+
)
|
791
|
+
) {
|
792
|
+
if (
|
793
|
+
config.reportUsedIgnorePattern &&
|
794
|
+
isUsedVariable(variable)
|
795
|
+
) {
|
796
|
+
context.report({
|
797
|
+
node: def.name,
|
798
|
+
messageId: "usedIgnoredVar",
|
799
|
+
data: getUsedIgnoredMessageData(
|
800
|
+
variable,
|
801
|
+
"array-destructure",
|
802
|
+
),
|
803
|
+
});
|
804
|
+
}
|
805
|
+
|
806
|
+
continue;
|
807
|
+
}
|
808
|
+
|
809
|
+
if (type === "ClassName") {
|
810
|
+
const hasStaticBlock = def.node.body.body.some(
|
811
|
+
node => node.type === "StaticBlock",
|
812
|
+
);
|
813
|
+
|
814
|
+
if (
|
815
|
+
config.ignoreClassWithStaticInitBlock &&
|
816
|
+
hasStaticBlock
|
817
|
+
) {
|
818
|
+
continue;
|
819
|
+
}
|
820
|
+
}
|
821
|
+
|
822
|
+
// skip catch variables
|
823
|
+
if (type === "CatchClause") {
|
824
|
+
if (config.caughtErrors === "none") {
|
825
|
+
continue;
|
826
|
+
}
|
827
|
+
|
828
|
+
// skip ignored parameters
|
829
|
+
if (
|
830
|
+
config.caughtErrorsIgnorePattern &&
|
831
|
+
config.caughtErrorsIgnorePattern.test(
|
832
|
+
def.name.name,
|
833
|
+
)
|
834
|
+
) {
|
835
|
+
if (
|
836
|
+
config.reportUsedIgnorePattern &&
|
837
|
+
isUsedVariable(variable)
|
838
|
+
) {
|
839
|
+
context.report({
|
840
|
+
node: def.name,
|
841
|
+
messageId: "usedIgnoredVar",
|
842
|
+
data: getUsedIgnoredMessageData(
|
843
|
+
variable,
|
844
|
+
"catch-clause",
|
845
|
+
),
|
846
|
+
});
|
847
|
+
}
|
848
|
+
|
849
|
+
continue;
|
850
|
+
}
|
851
|
+
} else if (type === "Parameter") {
|
852
|
+
// skip any setter argument
|
853
|
+
if (
|
854
|
+
(def.node.parent.type === "Property" ||
|
855
|
+
def.node.parent.type ===
|
856
|
+
"MethodDefinition") &&
|
857
|
+
def.node.parent.kind === "set"
|
858
|
+
) {
|
859
|
+
continue;
|
860
|
+
}
|
861
|
+
|
862
|
+
// if "args" option is "none", skip any parameter
|
863
|
+
if (config.args === "none") {
|
864
|
+
continue;
|
865
|
+
}
|
866
|
+
|
867
|
+
// skip ignored parameters
|
868
|
+
if (
|
869
|
+
config.argsIgnorePattern &&
|
870
|
+
config.argsIgnorePattern.test(def.name.name)
|
871
|
+
) {
|
872
|
+
if (
|
873
|
+
config.reportUsedIgnorePattern &&
|
874
|
+
isUsedVariable(variable)
|
875
|
+
) {
|
876
|
+
context.report({
|
877
|
+
node: def.name,
|
878
|
+
messageId: "usedIgnoredVar",
|
879
|
+
data: getUsedIgnoredMessageData(
|
880
|
+
variable,
|
881
|
+
"parameter",
|
882
|
+
),
|
883
|
+
});
|
884
|
+
}
|
885
|
+
|
886
|
+
continue;
|
887
|
+
}
|
888
|
+
|
889
|
+
// if "args" option is "after-used", skip used variables
|
890
|
+
if (
|
891
|
+
config.args === "after-used" &&
|
892
|
+
astUtils.isFunction(def.name.parent) &&
|
893
|
+
!isAfterLastUsedArg(variable)
|
894
|
+
) {
|
895
|
+
continue;
|
896
|
+
}
|
897
|
+
} else {
|
898
|
+
// skip ignored variables
|
899
|
+
if (
|
900
|
+
config.varsIgnorePattern &&
|
901
|
+
config.varsIgnorePattern.test(def.name.name)
|
902
|
+
) {
|
903
|
+
if (
|
904
|
+
config.reportUsedIgnorePattern &&
|
905
|
+
isUsedVariable(variable)
|
906
|
+
) {
|
907
|
+
context.report({
|
908
|
+
node: def.name,
|
909
|
+
messageId: "usedIgnoredVar",
|
910
|
+
data: getUsedIgnoredMessageData(
|
911
|
+
variable,
|
912
|
+
"variable",
|
913
|
+
),
|
914
|
+
});
|
915
|
+
}
|
916
|
+
|
917
|
+
continue;
|
918
|
+
}
|
919
|
+
}
|
920
|
+
}
|
921
|
+
|
922
|
+
if (
|
923
|
+
!isUsedVariable(variable) &&
|
924
|
+
!isExported(variable) &&
|
925
|
+
!hasRestSpreadSibling(variable)
|
926
|
+
) {
|
927
|
+
unusedVars.push(variable);
|
928
|
+
}
|
929
|
+
}
|
930
|
+
}
|
931
|
+
|
932
|
+
for (i = 0, l = childScopes.length; i < l; ++i) {
|
933
|
+
collectUnusedVariables(childScopes[i], unusedVars);
|
934
|
+
}
|
935
|
+
|
936
|
+
return unusedVars;
|
937
|
+
}
|
938
|
+
|
939
|
+
/**
|
940
|
+
* fixes unused variables
|
941
|
+
* @param {Object} fixer fixer object
|
942
|
+
* @param {Object} unusedVar unused variable to fix
|
943
|
+
* @returns {Object} fixer object
|
944
|
+
*/
|
945
|
+
function handleFixes(fixer, unusedVar) {
|
946
|
+
const id = unusedVar.identifiers[0];
|
947
|
+
const parent = id.parent;
|
948
|
+
const parentType = parent.type;
|
949
|
+
const tokenBefore = sourceCode.getTokenBefore(id);
|
950
|
+
const tokenAfter = sourceCode.getTokenAfter(id);
|
951
|
+
const isFunction = astUtils.isFunction;
|
952
|
+
const isLoop = astUtils.isLoop;
|
953
|
+
const allWriteReferences = unusedVar.references.filter(ref =>
|
954
|
+
ref.isWrite(),
|
955
|
+
);
|
956
|
+
|
957
|
+
/**
|
958
|
+
* get range from token before of a given node
|
959
|
+
* @param {ASTNode} node node of identifier
|
960
|
+
* @param {number} skips number of token to skip
|
961
|
+
* @returns {number} start range of token before the identifier
|
962
|
+
*/
|
963
|
+
function getPreviousTokenStart(node, skips) {
|
964
|
+
return sourceCode.getTokenBefore(node, skips).range[0];
|
965
|
+
}
|
966
|
+
|
967
|
+
/**
|
968
|
+
* get range to token after of a given node
|
969
|
+
* @param {ASTNode} node node of identifier
|
970
|
+
* @param {number} skips number of token to skip
|
971
|
+
* @returns {number} end range of token after the identifier
|
972
|
+
*/
|
973
|
+
function getNextTokenEnd(node, skips) {
|
974
|
+
return sourceCode.getTokenAfter(node, skips).range[1];
|
975
|
+
}
|
976
|
+
|
977
|
+
/**
|
978
|
+
* get the value of token before of a given node
|
979
|
+
* @param {ASTNode} node node of identifier
|
980
|
+
* @returns {string} value of token before the identifier
|
981
|
+
*/
|
982
|
+
function getTokenBeforeValue(node) {
|
983
|
+
return sourceCode.getTokenBefore(node).value;
|
984
|
+
}
|
985
|
+
|
986
|
+
/**
|
987
|
+
* get the value of token after of a given node
|
988
|
+
* @param {ASTNode} node node of identifier
|
989
|
+
* @returns {string} value of token after the identifier
|
990
|
+
*/
|
991
|
+
function getTokenAfterValue(node) {
|
992
|
+
return sourceCode.getTokenAfter(node).value;
|
993
|
+
}
|
994
|
+
|
995
|
+
/**
|
996
|
+
* Check if an array has a single element with null as other element.
|
997
|
+
* @param {ASTNode} node ArrayPattern node
|
998
|
+
* @returns {boolean} true if array has single element with other null elements
|
999
|
+
*/
|
1000
|
+
function hasSingleElement(node) {
|
1001
|
+
return node.elements.filter(e => e !== null).length === 1;
|
1002
|
+
}
|
1003
|
+
|
1004
|
+
/**
|
1005
|
+
* check whether import specifier has an import of particular type
|
1006
|
+
* @param {ASTNode} node ImportDeclaration node
|
1007
|
+
* @param {string} type type of import to check
|
1008
|
+
* @returns {boolean} true if import specifier has import of specified type
|
1009
|
+
*/
|
1010
|
+
function hasImportOfCertainType(node, type) {
|
1011
|
+
return node.specifiers.some(e => e.type === type);
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
/**
|
1015
|
+
* Check whether declaration is safe to remove or not
|
1016
|
+
* @param {ASTNode} nextToken next token of unused variable
|
1017
|
+
* @param {ASTNode} prevToken previous token of unused variable
|
1018
|
+
* @returns {boolean} true if declaration is not safe to remove
|
1019
|
+
*/
|
1020
|
+
function isDeclarationNotSafeToRemove(nextToken, prevToken) {
|
1021
|
+
return (
|
1022
|
+
nextToken.type === "String" ||
|
1023
|
+
(prevToken &&
|
1024
|
+
!astUtils.isSemicolonToken(prevToken) &&
|
1025
|
+
!astUtils.isOpeningBraceToken(prevToken))
|
1026
|
+
);
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
/**
|
1030
|
+
* give fixes for unused variables in function parameters
|
1031
|
+
* @param {ASTNode} node node to check
|
1032
|
+
* @returns {Object} fixer object
|
1033
|
+
*/
|
1034
|
+
function fixFunctionParameters(node) {
|
1035
|
+
const parentNode = node.parent;
|
1036
|
+
|
1037
|
+
if (isFunction(parentNode)) {
|
1038
|
+
// remove unused function parameter if there is only a single parameter
|
1039
|
+
if (parentNode.params.length === 1) {
|
1040
|
+
return fixer.removeRange(node.range);
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
// remove first unused function parameter when there are multiple parameters
|
1044
|
+
if (
|
1045
|
+
getTokenBeforeValue(node) === "(" &&
|
1046
|
+
getTokenAfterValue(node) === ","
|
1047
|
+
) {
|
1048
|
+
return fixer.removeRange([
|
1049
|
+
node.range[0],
|
1050
|
+
getNextTokenEnd(node),
|
1051
|
+
]);
|
1052
|
+
}
|
1053
|
+
|
1054
|
+
// remove unused function parameters except first one when there are multiple parameters
|
1055
|
+
return fixer.removeRange([
|
1056
|
+
getPreviousTokenStart(node),
|
1057
|
+
node.range[1],
|
1058
|
+
]);
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
return null;
|
1062
|
+
}
|
1063
|
+
|
1064
|
+
/**
|
1065
|
+
* fix unused variable declarations and function parameters
|
1066
|
+
* @param {ASTNode} node parent node to identifier
|
1067
|
+
* @returns {Object} fixer object
|
1068
|
+
*/
|
1069
|
+
function fixVariables(node) {
|
1070
|
+
const parentNode = node.parent;
|
1071
|
+
|
1072
|
+
// remove unused declared variables such as var a = b; or var a = b, c;
|
1073
|
+
if (parentNode.type === "VariableDeclarator") {
|
1074
|
+
// skip variable in for (const [ foo ] of bar);
|
1075
|
+
if (isLoop(parentNode.parent.parent)) {
|
1076
|
+
return null;
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
/*
|
1080
|
+
* remove unused declared variable with single declaration such as 'var a = b;'
|
1081
|
+
* remove complete declaration when there is an unused variable in 'const { a } = foo;', same for arrays.
|
1082
|
+
*/
|
1083
|
+
if (parentNode.parent.declarations.length === 1) {
|
1084
|
+
// if next token is a string it could become a directive if node is removed -> no suggestion.
|
1085
|
+
const nextToken = sourceCode.getTokenAfter(
|
1086
|
+
parentNode.parent,
|
1087
|
+
);
|
1088
|
+
|
1089
|
+
// if previous token exists and is not ";" or "{" not sure about ASI rules -> no suggestion.
|
1090
|
+
const prevToken = sourceCode.getTokenBefore(
|
1091
|
+
parentNode.parent,
|
1092
|
+
);
|
1093
|
+
|
1094
|
+
if (
|
1095
|
+
nextToken &&
|
1096
|
+
isDeclarationNotSafeToRemove(nextToken, prevToken)
|
1097
|
+
) {
|
1098
|
+
return null;
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
return fixer.removeRange(parentNode.parent.range);
|
1102
|
+
}
|
1103
|
+
|
1104
|
+
/*
|
1105
|
+
* remove unused declared variable with multiple declaration except first one such as 'var a = b, c = d;'
|
1106
|
+
* fix 'let bar = "hello", { a } = foo;' to 'let bar = "hello";' if 'a' is unused, same for arrays.
|
1107
|
+
*/
|
1108
|
+
if (getTokenBeforeValue(parentNode) === ",") {
|
1109
|
+
return fixer.removeRange([
|
1110
|
+
getPreviousTokenStart(parentNode),
|
1111
|
+
parentNode.range[1],
|
1112
|
+
]);
|
1113
|
+
}
|
1114
|
+
|
1115
|
+
/*
|
1116
|
+
* remove first unused declared variable when there are multiple declarations
|
1117
|
+
* fix 'let { a } = foo, bar = "hello";' to 'let bar = "hello";' if 'a' is unused, same for arrays.
|
1118
|
+
*/
|
1119
|
+
return fixer.removeRange([
|
1120
|
+
parentNode.range[0],
|
1121
|
+
getNextTokenEnd(parentNode),
|
1122
|
+
]);
|
1123
|
+
}
|
1124
|
+
|
1125
|
+
// fixes [{a: {k}}], [{a: [k]}]
|
1126
|
+
if (getTokenBeforeValue(node) === ":") {
|
1127
|
+
if (parentNode.parent.type === "ObjectPattern") {
|
1128
|
+
// eslint-disable-next-line no-use-before-define -- due to interdependency of functions
|
1129
|
+
return fixObjectWithValueSeparator(node);
|
1130
|
+
}
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
// fix unused function parameters
|
1134
|
+
return fixFunctionParameters(node);
|
1135
|
+
}
|
1136
|
+
|
1137
|
+
/**
|
1138
|
+
* fix nested object like { a: { b } }
|
1139
|
+
* @param {ASTNode} node parent node to check
|
1140
|
+
* @returns {Object} fixer object
|
1141
|
+
*/
|
1142
|
+
function fixNestedObjectVariable(node) {
|
1143
|
+
const parentNode = node.parent;
|
1144
|
+
|
1145
|
+
// fix for { a: { b: { c: { d } } } }
|
1146
|
+
if (
|
1147
|
+
parentNode.parent.parent.parent.type === "ObjectPattern" &&
|
1148
|
+
parentNode.parent.properties.length === 1
|
1149
|
+
) {
|
1150
|
+
return fixNestedObjectVariable(parentNode.parent);
|
1151
|
+
}
|
1152
|
+
|
1153
|
+
// fix for { a: { b } }
|
1154
|
+
if (parentNode.parent.type === "ObjectPattern") {
|
1155
|
+
// fix for unused variables in dectructured object with single property in variable decalartion and function parameter
|
1156
|
+
if (parentNode.parent.properties.length === 1) {
|
1157
|
+
return fixVariables(parentNode.parent);
|
1158
|
+
}
|
1159
|
+
|
1160
|
+
// fix for first unused property when there are multiple properties such as '{ a: { b }, c }'
|
1161
|
+
if (getTokenBeforeValue(parentNode) === "{") {
|
1162
|
+
return fixer.removeRange([
|
1163
|
+
parentNode.range[0],
|
1164
|
+
getNextTokenEnd(parentNode),
|
1165
|
+
]);
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
// fix for unused property except first one when there are multiple properties such as '{ k, a: { b } }'
|
1169
|
+
return fixer.removeRange([
|
1170
|
+
getPreviousTokenStart(parentNode),
|
1171
|
+
parentNode.range[1],
|
1172
|
+
]);
|
1173
|
+
}
|
1174
|
+
|
1175
|
+
return null;
|
1176
|
+
}
|
1177
|
+
|
1178
|
+
/**
|
1179
|
+
* fix unused variables in array and nested array
|
1180
|
+
* @param {ASTNode} node parent node to check
|
1181
|
+
* @returns {Object} fixer object
|
1182
|
+
*/
|
1183
|
+
function fixNestedArrayVariable(node) {
|
1184
|
+
const parentNode = node.parent;
|
1185
|
+
|
1186
|
+
// fix for nested arrays [[ a ]]
|
1187
|
+
if (
|
1188
|
+
parentNode.parent.type === "ArrayPattern" &&
|
1189
|
+
hasSingleElement(parentNode)
|
1190
|
+
) {
|
1191
|
+
return fixNestedArrayVariable(parentNode);
|
1192
|
+
}
|
1193
|
+
|
1194
|
+
if (hasSingleElement(parentNode)) {
|
1195
|
+
// fixes { a: [{ b }] } or { a: [[ b ]] }
|
1196
|
+
if (getTokenBeforeValue(parentNode) === ":") {
|
1197
|
+
return fixVariables(parentNode);
|
1198
|
+
}
|
1199
|
+
|
1200
|
+
// fixes [a, ...[[ b ]]] or [a, ...[{ b }]]
|
1201
|
+
if (parentNode.parent.type === "RestElement") {
|
1202
|
+
// eslint-disable-next-line no-use-before-define -- due to interdependency of functions
|
1203
|
+
return fixRestInPattern(parentNode.parent);
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
// fix unused variables in destructured array in variable declaration or function parameter
|
1207
|
+
return fixVariables(parentNode);
|
1208
|
+
}
|
1209
|
+
|
1210
|
+
// remove last unused array element
|
1211
|
+
if (
|
1212
|
+
getTokenBeforeValue(node) === "," &&
|
1213
|
+
getTokenAfterValue(node) === "]"
|
1214
|
+
) {
|
1215
|
+
return fixer.removeRange([
|
1216
|
+
getPreviousTokenStart(node),
|
1217
|
+
node.range[1],
|
1218
|
+
]);
|
1219
|
+
}
|
1220
|
+
|
1221
|
+
// remove unused array element
|
1222
|
+
return fixer.removeRange(node.range);
|
1223
|
+
}
|
1224
|
+
|
1225
|
+
/**
|
1226
|
+
* fix cases like {a: {k}} or {a: [k]}
|
1227
|
+
* @param {ASTNode} node parent node to check
|
1228
|
+
* @returns {Object} fixer object
|
1229
|
+
*/
|
1230
|
+
function fixObjectWithValueSeparator(node) {
|
1231
|
+
const parentNode = node.parent.parent;
|
1232
|
+
|
1233
|
+
// fix cases like [{a : { b }}] or [{a : [ b ]}]
|
1234
|
+
if (
|
1235
|
+
parentNode.parent.type === "ArrayPattern" &&
|
1236
|
+
parentNode.properties.length === 1
|
1237
|
+
) {
|
1238
|
+
return fixNestedArrayVariable(parentNode);
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
// fix cases like {a: {k}} or {a: [k]}
|
1242
|
+
return fixNestedObjectVariable(node);
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
/**
|
1246
|
+
* fix ...[[a]] or ...[{a}] like patterns
|
1247
|
+
* @param {ASTNode} node parent node to check
|
1248
|
+
* @returns {Object} fixer object
|
1249
|
+
*/
|
1250
|
+
function fixRestInPattern(node) {
|
1251
|
+
const parentNode = node.parent;
|
1252
|
+
|
1253
|
+
// fix ...[[a]] or ...[{a}] in function parameters
|
1254
|
+
if (isFunction(parentNode)) {
|
1255
|
+
if (parentNode.params.length === 1) {
|
1256
|
+
return fixer.removeRange(node.range);
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
return fixer.removeRange([
|
1260
|
+
getPreviousTokenStart(node),
|
1261
|
+
node.range[1],
|
1262
|
+
]);
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
// fix rest in nested array pattern like [[a, ...[b]]]
|
1266
|
+
if (parentNode.type === "ArrayPattern") {
|
1267
|
+
// fix [[...[b]]]
|
1268
|
+
if (hasSingleElement(parentNode)) {
|
1269
|
+
if (parentNode.parent.type === "ArrayPattern") {
|
1270
|
+
return fixNestedArrayVariable(parentNode);
|
1271
|
+
}
|
1272
|
+
|
1273
|
+
// fix 'const [...[b]] = foo; and function foo([...[b]]) {}
|
1274
|
+
return fixVariables(parentNode);
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
// fix [[a, ...[b]]]
|
1278
|
+
return fixer.removeRange([
|
1279
|
+
getPreviousTokenStart(node),
|
1280
|
+
node.range[1],
|
1281
|
+
]);
|
1282
|
+
}
|
1283
|
+
|
1284
|
+
return null;
|
1285
|
+
}
|
1286
|
+
|
1287
|
+
// skip fix when variable has references that would be left behind
|
1288
|
+
if (
|
1289
|
+
allWriteReferences.some(
|
1290
|
+
ref => ref.identifier.range[0] !== id.range[0],
|
1291
|
+
)
|
1292
|
+
) {
|
1293
|
+
return null;
|
1294
|
+
}
|
1295
|
+
|
1296
|
+
// remove declared variables such as var a; or var a, b;
|
1297
|
+
if (parentType === "VariableDeclarator") {
|
1298
|
+
if (parent.parent.declarations.length === 1) {
|
1299
|
+
// prevent fix of variable in forOf and forIn loops.
|
1300
|
+
if (
|
1301
|
+
isLoop(parent.parent.parent) &&
|
1302
|
+
parent.parent.parent.body !== parent.parent
|
1303
|
+
) {
|
1304
|
+
return null;
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
// removes only variable not semicolon in 'if (foo()) var bar;' or in 'loops' or in 'with' statement.
|
1308
|
+
if (
|
1309
|
+
parent.parent.parent.type === "IfStatement" ||
|
1310
|
+
isLoop(parent.parent.parent) ||
|
1311
|
+
(parent.parent.parent.type === "WithStatement" &&
|
1312
|
+
parent.parent.parent.body === parent.parent)
|
1313
|
+
) {
|
1314
|
+
return fixer.replaceText(parent.parent, ";");
|
1315
|
+
}
|
1316
|
+
|
1317
|
+
// if next token is a string it could become a directive if node is removed -> no suggestion.
|
1318
|
+
const nextToken = sourceCode.getTokenAfter(parent.parent);
|
1319
|
+
|
1320
|
+
// if previous token exists and is not ";" or "{" not sure about ASI rules -> no suggestion.
|
1321
|
+
const prevToken = sourceCode.getTokenBefore(parent.parent);
|
1322
|
+
|
1323
|
+
if (
|
1324
|
+
nextToken &&
|
1325
|
+
isDeclarationNotSafeToRemove(nextToken, prevToken)
|
1326
|
+
) {
|
1327
|
+
return null;
|
1328
|
+
}
|
1329
|
+
|
1330
|
+
// remove unused declared variable with single declaration like 'var a = b;'
|
1331
|
+
return fixer.removeRange(parent.parent.range);
|
1332
|
+
}
|
1333
|
+
|
1334
|
+
// remove unused declared variable with multiple declaration except first one like 'var a = b, c = d;'
|
1335
|
+
if (tokenBefore.value === ",") {
|
1336
|
+
return fixer.removeRange([
|
1337
|
+
tokenBefore.range[0],
|
1338
|
+
parent.range[1],
|
1339
|
+
]);
|
1340
|
+
}
|
1341
|
+
|
1342
|
+
// remove first unused declared variable when there are multiple declarations
|
1343
|
+
return fixer.removeRange([
|
1344
|
+
parent.range[0],
|
1345
|
+
getNextTokenEnd(parent),
|
1346
|
+
]);
|
1347
|
+
}
|
1348
|
+
|
1349
|
+
// remove variables in object patterns
|
1350
|
+
if (parent.parent.type === "ObjectPattern") {
|
1351
|
+
if (parent.parent.properties.length === 1) {
|
1352
|
+
// fix [a, ...{b}]
|
1353
|
+
if (parent.parent.parent.type === "RestElement") {
|
1354
|
+
return fixRestInPattern(parent.parent.parent);
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
// fix [{ a }]
|
1358
|
+
if (parent.parent.parent.type === "ArrayPattern") {
|
1359
|
+
return fixNestedArrayVariable(parent.parent);
|
1360
|
+
}
|
1361
|
+
|
1362
|
+
/*
|
1363
|
+
* var {a} = foo;
|
1364
|
+
* function a({a}) {}
|
1365
|
+
* fix const { a: { b } } = foo;
|
1366
|
+
*/
|
1367
|
+
return fixVariables(parent.parent);
|
1368
|
+
}
|
1369
|
+
|
1370
|
+
// fix const { a:b } = foo;
|
1371
|
+
if (tokenBefore.value === ":") {
|
1372
|
+
// remove first unused variable in const { a:b } = foo;
|
1373
|
+
if (
|
1374
|
+
getTokenBeforeValue(parent) === "{" &&
|
1375
|
+
getTokenAfterValue(parent) === ","
|
1376
|
+
) {
|
1377
|
+
return fixer.removeRange([
|
1378
|
+
parent.range[0],
|
1379
|
+
getNextTokenEnd(parent),
|
1380
|
+
]);
|
1381
|
+
}
|
1382
|
+
|
1383
|
+
// remove unused variables in const { a: b, c: d } = foo; except first one
|
1384
|
+
return fixer.removeRange([
|
1385
|
+
getPreviousTokenStart(parent),
|
1386
|
+
id.range[1],
|
1387
|
+
]);
|
1388
|
+
}
|
1389
|
+
}
|
1390
|
+
|
1391
|
+
// remove unused variables inside an array
|
1392
|
+
if (parentType === "ArrayPattern") {
|
1393
|
+
if (hasSingleElement(parent)) {
|
1394
|
+
// fix [a, ...[b]]
|
1395
|
+
if (parent.parent.type === "RestElement") {
|
1396
|
+
return fixRestInPattern(parent.parent);
|
1397
|
+
}
|
1398
|
+
|
1399
|
+
// fix [ [a] ]
|
1400
|
+
if (parent.parent.type === "ArrayPattern") {
|
1401
|
+
return fixNestedArrayVariable(parent);
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
/*
|
1405
|
+
* fix var [a] = foo;
|
1406
|
+
* fix function foo([a]) {}
|
1407
|
+
* fix const { a: [b] } = foo;
|
1408
|
+
*/
|
1409
|
+
return fixVariables(parent);
|
1410
|
+
}
|
1411
|
+
|
1412
|
+
// if "a" is unused in [a, b ,c] fixes to [, b, c]
|
1413
|
+
if (tokenBefore.value === "," && tokenAfter.value === ",") {
|
1414
|
+
return fixer.removeRange(id.range);
|
1415
|
+
}
|
1416
|
+
}
|
1417
|
+
|
1418
|
+
// remove unused rest elements
|
1419
|
+
if (parentType === "RestElement") {
|
1420
|
+
// fix [a, ...rest]
|
1421
|
+
if (parent.parent.type === "ArrayPattern") {
|
1422
|
+
if (hasSingleElement(parent.parent)) {
|
1423
|
+
// fix [[...rest]] when there is only rest element
|
1424
|
+
if (parent.parent.parent.type === "ArrayPattern") {
|
1425
|
+
return fixNestedArrayVariable(parent.parent);
|
1426
|
+
}
|
1427
|
+
|
1428
|
+
// fix 'const [...rest] = foo;' and 'function foo([...rest]) {}'
|
1429
|
+
return fixVariables(parent.parent);
|
1430
|
+
}
|
1431
|
+
|
1432
|
+
// fix [a, ...rest]
|
1433
|
+
return fixer.removeRange([
|
1434
|
+
getPreviousTokenStart(id, 1),
|
1435
|
+
id.range[1],
|
1436
|
+
]);
|
1437
|
+
}
|
1438
|
+
|
1439
|
+
// fix { a, ...rest}
|
1440
|
+
if (parent.parent.type === "ObjectPattern") {
|
1441
|
+
// fix 'const {...rest} = foo;' and 'function foo({...rest}) {}'
|
1442
|
+
if (parent.parent.properties.length === 1) {
|
1443
|
+
return fixVariables(parent.parent);
|
1444
|
+
}
|
1445
|
+
|
1446
|
+
// fix { a, ...rest} when there are multiple properties
|
1447
|
+
return fixer.removeRange([
|
1448
|
+
getPreviousTokenStart(id, 1),
|
1449
|
+
id.range[1],
|
1450
|
+
]);
|
1451
|
+
}
|
1452
|
+
|
1453
|
+
// fix function foo(...rest) {}
|
1454
|
+
if (isFunction(parent.parent)) {
|
1455
|
+
// remove unused rest in function parameter if there is only single parameter
|
1456
|
+
if (parent.parent.params.length === 1) {
|
1457
|
+
return fixer.removeRange(parent.range);
|
1458
|
+
}
|
1459
|
+
|
1460
|
+
// remove unused rest in function parameter if there multiple parameter
|
1461
|
+
return fixer.removeRange([
|
1462
|
+
getPreviousTokenStart(parent),
|
1463
|
+
parent.range[1],
|
1464
|
+
]);
|
1465
|
+
}
|
1466
|
+
}
|
1467
|
+
|
1468
|
+
if (parentType === "AssignmentPattern") {
|
1469
|
+
// fix [a = aDefault]
|
1470
|
+
if (parent.parent.type === "ArrayPattern") {
|
1471
|
+
return fixNestedArrayVariable(parent);
|
1472
|
+
}
|
1473
|
+
|
1474
|
+
// fix {a = aDefault}
|
1475
|
+
if (parent.parent.parent.type === "ObjectPattern") {
|
1476
|
+
if (parent.parent.parent.properties.length === 1) {
|
1477
|
+
// fixes [{a = aDefault}]
|
1478
|
+
if (
|
1479
|
+
parent.parent.parent.parent.type === "ArrayPattern"
|
1480
|
+
) {
|
1481
|
+
return fixNestedArrayVariable(parent.parent.parent);
|
1482
|
+
}
|
1483
|
+
|
1484
|
+
// fix 'const {a = aDefault} = foo;' and 'function foo({a = aDefault}) {}'
|
1485
|
+
return fixVariables(parent.parent.parent);
|
1486
|
+
}
|
1487
|
+
|
1488
|
+
// fix unused 'a' in {a = aDefault} if it is the first property
|
1489
|
+
if (
|
1490
|
+
getTokenBeforeValue(parent.parent) === "{" &&
|
1491
|
+
getTokenAfterValue(parent.parent) === ","
|
1492
|
+
) {
|
1493
|
+
return fixer.removeRange([
|
1494
|
+
parent.parent.range[0],
|
1495
|
+
getNextTokenEnd(parent.parent),
|
1496
|
+
]);
|
1497
|
+
}
|
1498
|
+
|
1499
|
+
// fix unused 'b' in {a, b = aDefault} if it is not the first property
|
1500
|
+
return fixer.removeRange([
|
1501
|
+
getPreviousTokenStart(parent.parent),
|
1502
|
+
parent.parent.range[1],
|
1503
|
+
]);
|
1504
|
+
}
|
1505
|
+
|
1506
|
+
// fix unused assignment patterns in function parameters
|
1507
|
+
if (isFunction(parent.parent)) {
|
1508
|
+
return fixFunctionParameters(parent);
|
1509
|
+
}
|
1510
|
+
}
|
1511
|
+
|
1512
|
+
// remove unused functions
|
1513
|
+
if (parentType === "FunctionDeclaration" && parent.id === id) {
|
1514
|
+
return fixer.removeRange(parent.range);
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
// remove unused default import
|
1518
|
+
if (parentType === "ImportDefaultSpecifier") {
|
1519
|
+
// remove unused default import when there are not other imports
|
1520
|
+
if (
|
1521
|
+
!hasImportOfCertainType(parent.parent, "ImportSpecifier") &&
|
1522
|
+
!hasImportOfCertainType(
|
1523
|
+
parent.parent,
|
1524
|
+
"ImportNamespaceSpecifier",
|
1525
|
+
)
|
1526
|
+
) {
|
1527
|
+
return fixer.removeRange([
|
1528
|
+
parent.range[0],
|
1529
|
+
parent.parent.source.range[0],
|
1530
|
+
]);
|
1531
|
+
}
|
1532
|
+
|
1533
|
+
// remove unused default import when there are other imports also
|
1534
|
+
return fixer.removeRange([id.range[0], tokenAfter.range[1]]);
|
1535
|
+
}
|
1536
|
+
|
1537
|
+
if (parentType === "ImportSpecifier") {
|
1538
|
+
// remove unused imports when there is a single import
|
1539
|
+
if (
|
1540
|
+
parent.parent.specifiers.filter(
|
1541
|
+
e => e.type === "ImportSpecifier",
|
1542
|
+
).length === 1
|
1543
|
+
) {
|
1544
|
+
// remove unused import when there is no default import
|
1545
|
+
if (
|
1546
|
+
!hasImportOfCertainType(
|
1547
|
+
parent.parent,
|
1548
|
+
"ImportDefaultSpecifier",
|
1549
|
+
)
|
1550
|
+
) {
|
1551
|
+
return fixer.removeRange(parent.parent.range);
|
1552
|
+
}
|
1553
|
+
|
1554
|
+
// fixes "import foo from 'module';" to "import 'module';"
|
1555
|
+
return fixer.removeRange([
|
1556
|
+
getPreviousTokenStart(parent, 1),
|
1557
|
+
tokenAfter.range[1],
|
1558
|
+
]);
|
1559
|
+
}
|
1560
|
+
|
1561
|
+
if (getTokenBeforeValue(parent) === "{") {
|
1562
|
+
return fixer.removeRange([
|
1563
|
+
parent.range[0],
|
1564
|
+
getNextTokenEnd(parent),
|
1565
|
+
]);
|
1566
|
+
}
|
1567
|
+
|
1568
|
+
return fixer.removeRange([
|
1569
|
+
getPreviousTokenStart(parent),
|
1570
|
+
parent.range[1],
|
1571
|
+
]);
|
1572
|
+
}
|
1573
|
+
|
1574
|
+
if (parentType === "ImportNamespaceSpecifier") {
|
1575
|
+
if (
|
1576
|
+
hasImportOfCertainType(
|
1577
|
+
parent.parent,
|
1578
|
+
"ImportDefaultSpecifier",
|
1579
|
+
)
|
1580
|
+
) {
|
1581
|
+
return fixer.removeRange([
|
1582
|
+
getPreviousTokenStart(parent),
|
1583
|
+
parent.range[1],
|
1584
|
+
]);
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
// fixes "import * as foo from 'module';" to "import 'module';"
|
1588
|
+
return fixer.removeRange([
|
1589
|
+
parent.range[0],
|
1590
|
+
parent.parent.source.range[0],
|
1591
|
+
]);
|
1592
|
+
}
|
1593
|
+
|
1594
|
+
// skip error in catch(error) variable
|
1595
|
+
if (parentType === "CatchClause") {
|
1596
|
+
return null;
|
1597
|
+
}
|
1598
|
+
|
1599
|
+
// remove unused declared classes
|
1600
|
+
if (parentType === "ClassDeclaration") {
|
1601
|
+
return fixer.removeRange(parent.range);
|
1602
|
+
}
|
1603
|
+
|
1604
|
+
// remove unused variable that is in a sequence [a,b] fixes to [a]
|
1605
|
+
if (tokenBefore?.value === ",") {
|
1606
|
+
return fixer.removeRange([tokenBefore.range[0], id.range[1]]);
|
1607
|
+
}
|
1608
|
+
|
1609
|
+
// remove unused variable that is in a sequence inside function arguments and object pattern
|
1610
|
+
if (tokenAfter.value === ",") {
|
1611
|
+
// fix function foo(a, b) {}
|
1612
|
+
if (tokenBefore.value === "(") {
|
1613
|
+
return fixer.removeRange([
|
1614
|
+
id.range[0],
|
1615
|
+
tokenAfter.range[1],
|
1616
|
+
]);
|
1617
|
+
}
|
1618
|
+
|
1619
|
+
// fix const {a, b} = foo;
|
1620
|
+
if (tokenBefore.value === "{") {
|
1621
|
+
return fixer.removeRange([
|
1622
|
+
id.range[0],
|
1623
|
+
tokenAfter.range[1],
|
1624
|
+
]);
|
1625
|
+
}
|
1626
|
+
}
|
1627
|
+
|
1628
|
+
if (
|
1629
|
+
parentType === "ArrowFunctionExpression" &&
|
1630
|
+
parent.params.length === 1 &&
|
1631
|
+
tokenAfter?.value !== ")"
|
1632
|
+
) {
|
1633
|
+
return fixer.replaceText(id, "()");
|
1634
|
+
}
|
1635
|
+
|
1636
|
+
return fixer.removeRange(id.range);
|
1637
|
+
}
|
1638
|
+
|
1639
|
+
//--------------------------------------------------------------------------
|
1640
|
+
// Public
|
1641
|
+
//--------------------------------------------------------------------------
|
1642
|
+
|
1643
|
+
return {
|
1644
|
+
"Program:exit"(programNode) {
|
1645
|
+
const unusedVars = collectUnusedVariables(
|
1646
|
+
sourceCode.getScope(programNode),
|
1647
|
+
[],
|
1648
|
+
);
|
1649
|
+
|
1650
|
+
for (let i = 0, l = unusedVars.length; i < l; ++i) {
|
1651
|
+
const unusedVar = unusedVars[i];
|
1652
|
+
|
1653
|
+
// Report the first declaration.
|
1654
|
+
if (unusedVar.defs.length > 0) {
|
1655
|
+
// report last write reference, https://github.com/eslint/eslint/issues/14324
|
1656
|
+
const writeReferences = unusedVar.references.filter(
|
1657
|
+
ref =>
|
1658
|
+
ref.isWrite() &&
|
1659
|
+
ref.from.variableScope ===
|
1660
|
+
unusedVar.scope.variableScope,
|
1661
|
+
);
|
1662
|
+
|
1663
|
+
let referenceToReport;
|
1664
|
+
|
1665
|
+
if (writeReferences.length > 0) {
|
1666
|
+
referenceToReport = writeReferences.at(-1);
|
1667
|
+
}
|
1668
|
+
|
1669
|
+
context.report({
|
1670
|
+
node: referenceToReport
|
1671
|
+
? referenceToReport.identifier
|
1672
|
+
: unusedVar.identifiers[0],
|
1673
|
+
messageId: "unusedVar",
|
1674
|
+
data: unusedVar.references.some(ref =>
|
1675
|
+
ref.isWrite(),
|
1676
|
+
)
|
1677
|
+
? getAssignedMessageData(unusedVar)
|
1678
|
+
: getDefinedMessageData(unusedVar),
|
1679
|
+
suggest: [
|
1680
|
+
{
|
1681
|
+
messageId: "removeVar",
|
1682
|
+
data: {
|
1683
|
+
varName: unusedVar.name,
|
1684
|
+
},
|
1685
|
+
fix(fixer) {
|
1686
|
+
return handleFixes(fixer, unusedVar);
|
1687
|
+
},
|
1688
|
+
},
|
1689
|
+
],
|
1690
|
+
});
|
1691
|
+
|
1692
|
+
// If there are no regular declaration, report the first `/*globals*/` comment directive.
|
1693
|
+
} else if (unusedVar.eslintExplicitGlobalComments) {
|
1694
|
+
const directiveComment =
|
1695
|
+
unusedVar.eslintExplicitGlobalComments[0];
|
1696
|
+
|
1697
|
+
context.report({
|
1698
|
+
node: programNode,
|
1699
|
+
loc: astUtils.getNameLocationInGlobalDirectiveComment(
|
1700
|
+
sourceCode,
|
1701
|
+
directiveComment,
|
1702
|
+
unusedVar.name,
|
1703
|
+
),
|
1704
|
+
messageId: "unusedVar",
|
1705
|
+
data: getDefinedMessageData(unusedVar),
|
1706
|
+
});
|
1707
|
+
}
|
1708
|
+
}
|
1709
|
+
},
|
1710
|
+
};
|
1711
|
+
},
|
1492
1712
|
};
|