eslint 8.57.1 → 9.39.1

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.
Files changed (458) hide show
  1. package/README.md +165 -115
  2. package/bin/eslint.js +112 -89
  3. package/conf/default-cli-options.js +22 -22
  4. package/conf/ecma-version.js +16 -0
  5. package/conf/globals.js +109 -94
  6. package/conf/replacements.json +24 -20
  7. package/conf/rule-type-list.json +89 -26
  8. package/lib/api.js +16 -20
  9. package/lib/cli-engine/cli-engine.js +841 -810
  10. package/lib/cli-engine/file-enumerator.js +384 -390
  11. package/lib/cli-engine/formatters/formatters-meta.json +17 -45
  12. package/lib/cli-engine/formatters/html.js +110 -102
  13. package/lib/cli-engine/formatters/json-with-metadata.js +5 -5
  14. package/lib/cli-engine/formatters/json.js +2 -2
  15. package/lib/cli-engine/formatters/stylish.js +97 -76
  16. package/lib/cli-engine/hash.js +1 -1
  17. package/lib/cli-engine/index.js +1 -1
  18. package/lib/cli-engine/lint-result-cache.js +165 -148
  19. package/lib/cli-engine/load-rules.js +17 -17
  20. package/lib/cli.js +481 -399
  21. package/lib/config/config-loader.js +816 -0
  22. package/lib/config/config.js +674 -0
  23. package/lib/config/default-config.js +57 -46
  24. package/lib/config/flat-config-array.js +170 -333
  25. package/lib/config/flat-config-schema.js +389 -389
  26. package/lib/config-api.js +12 -0
  27. package/lib/eslint/eslint-helpers.js +1196 -663
  28. package/lib/eslint/eslint.js +1262 -607
  29. package/lib/eslint/index.js +3 -3
  30. package/lib/eslint/legacy-eslint.js +786 -0
  31. package/lib/eslint/worker.js +173 -0
  32. package/lib/languages/js/index.js +336 -0
  33. package/lib/languages/js/source-code/index.js +7 -0
  34. package/lib/languages/js/source-code/source-code.js +1364 -0
  35. package/lib/languages/js/source-code/token-store/backward-token-comment-cursor.js +61 -0
  36. package/lib/languages/js/source-code/token-store/backward-token-cursor.js +57 -0
  37. package/lib/{source-code → languages/js/source-code}/token-store/cursor.js +36 -36
  38. package/lib/languages/js/source-code/token-store/cursors.js +120 -0
  39. package/lib/{source-code → languages/js/source-code}/token-store/decorative-cursor.js +17 -18
  40. package/lib/{source-code → languages/js/source-code}/token-store/filter-cursor.js +19 -20
  41. package/lib/languages/js/source-code/token-store/forward-token-comment-cursor.js +65 -0
  42. package/lib/languages/js/source-code/token-store/forward-token-cursor.js +62 -0
  43. package/lib/languages/js/source-code/token-store/index.js +721 -0
  44. package/lib/{source-code → languages/js/source-code}/token-store/limit-cursor.js +17 -18
  45. package/lib/languages/js/source-code/token-store/padded-token-cursor.js +45 -0
  46. package/lib/{source-code → languages/js/source-code}/token-store/skip-cursor.js +19 -20
  47. package/lib/languages/js/source-code/token-store/utils.js +110 -0
  48. package/lib/languages/js/validate-language-options.js +196 -0
  49. package/lib/linter/apply-disable-directives.js +490 -371
  50. package/lib/linter/code-path-analysis/code-path-analyzer.js +650 -674
  51. package/lib/linter/code-path-analysis/code-path-segment.js +215 -216
  52. package/lib/linter/code-path-analysis/code-path-state.js +2118 -2096
  53. package/lib/linter/code-path-analysis/code-path.js +307 -317
  54. package/lib/linter/code-path-analysis/debug-helpers.js +183 -163
  55. package/lib/linter/code-path-analysis/fork-context.js +297 -272
  56. package/lib/linter/code-path-analysis/id-generator.js +22 -23
  57. package/lib/linter/esquery.js +332 -0
  58. package/lib/linter/file-context.js +144 -0
  59. package/lib/linter/file-report.js +608 -0
  60. package/lib/linter/index.js +3 -5
  61. package/lib/linter/interpolate.js +38 -16
  62. package/lib/linter/linter.js +2328 -1785
  63. package/lib/linter/rule-fixer.js +136 -107
  64. package/lib/linter/rules.js +37 -46
  65. package/lib/linter/source-code-fixer.js +96 -94
  66. package/lib/linter/source-code-traverser.js +333 -0
  67. package/lib/linter/source-code-visitor.js +81 -0
  68. package/lib/linter/timing.js +145 -97
  69. package/lib/linter/vfile.js +115 -0
  70. package/lib/options.js +464 -326
  71. package/lib/rule-tester/index.js +3 -1
  72. package/lib/rule-tester/rule-tester.js +1371 -998
  73. package/lib/rules/accessor-pairs.js +333 -259
  74. package/lib/rules/array-bracket-newline.js +250 -220
  75. package/lib/rules/array-bracket-spacing.js +286 -229
  76. package/lib/rules/array-callback-return.js +401 -354
  77. package/lib/rules/array-element-newline.js +358 -295
  78. package/lib/rules/arrow-body-style.js +400 -278
  79. package/lib/rules/arrow-parens.js +206 -155
  80. package/lib/rules/arrow-spacing.js +169 -145
  81. package/lib/rules/block-scoped-var.js +125 -123
  82. package/lib/rules/block-spacing.js +186 -158
  83. package/lib/rules/brace-style.js +262 -181
  84. package/lib/rules/callback-return.js +203 -174
  85. package/lib/rules/camelcase.js +403 -380
  86. package/lib/rules/capitalized-comments.js +253 -228
  87. package/lib/rules/class-methods-use-this.js +231 -168
  88. package/lib/rules/comma-dangle.js +379 -328
  89. package/lib/rules/comma-spacing.js +193 -177
  90. package/lib/rules/comma-style.js +375 -298
  91. package/lib/rules/complexity.js +180 -144
  92. package/lib/rules/computed-property-spacing.js +236 -193
  93. package/lib/rules/consistent-return.js +181 -170
  94. package/lib/rules/consistent-this.js +167 -141
  95. package/lib/rules/constructor-super.js +418 -411
  96. package/lib/rules/curly.js +407 -468
  97. package/lib/rules/default-case-last.js +39 -32
  98. package/lib/rules/default-case.js +89 -83
  99. package/lib/rules/default-param-last.js +69 -53
  100. package/lib/rules/dot-location.js +122 -92
  101. package/lib/rules/dot-notation.js +193 -153
  102. package/lib/rules/eol-last.js +122 -102
  103. package/lib/rules/eqeqeq.js +191 -155
  104. package/lib/rules/for-direction.js +150 -122
  105. package/lib/rules/func-call-spacing.js +261 -213
  106. package/lib/rules/func-name-matching.js +294 -209
  107. package/lib/rules/func-names.js +165 -164
  108. package/lib/rules/func-style.js +209 -86
  109. package/lib/rules/function-call-argument-newline.js +152 -111
  110. package/lib/rules/function-paren-newline.js +349 -273
  111. package/lib/rules/generator-star-spacing.js +229 -192
  112. package/lib/rules/getter-return.js +208 -170
  113. package/lib/rules/global-require.js +85 -58
  114. package/lib/rules/grouped-accessor-pairs.js +201 -148
  115. package/lib/rules/guard-for-in.js +72 -63
  116. package/lib/rules/handle-callback-err.js +108 -87
  117. package/lib/rules/id-blacklist.js +182 -187
  118. package/lib/rules/id-denylist.js +174 -179
  119. package/lib/rules/id-length.js +197 -157
  120. package/lib/rules/id-match.js +350 -286
  121. package/lib/rules/implicit-arrow-linebreak.js +102 -61
  122. package/lib/rules/indent-legacy.js +1345 -1102
  123. package/lib/rules/indent.js +2272 -1741
  124. package/lib/rules/index.js +320 -294
  125. package/lib/rules/init-declarations.js +139 -106
  126. package/lib/rules/jsx-quotes.js +94 -64
  127. package/lib/rules/key-spacing.js +750 -615
  128. package/lib/rules/keyword-spacing.js +648 -587
  129. package/lib/rules/line-comment-position.js +143 -108
  130. package/lib/rules/linebreak-style.js +115 -88
  131. package/lib/rules/lines-around-comment.js +540 -430
  132. package/lib/rules/lines-around-directive.js +233 -185
  133. package/lib/rules/lines-between-class-members.js +305 -216
  134. package/lib/rules/logical-assignment-operators.js +582 -398
  135. package/lib/rules/max-classes-per-file.js +69 -68
  136. package/lib/rules/max-depth.js +146 -143
  137. package/lib/rules/max-len.js +473 -416
  138. package/lib/rules/max-lines-per-function.js +201 -176
  139. package/lib/rules/max-lines.js +158 -162
  140. package/lib/rules/max-nested-callbacks.js +102 -104
  141. package/lib/rules/max-params.js +102 -75
  142. package/lib/rules/max-statements-per-line.js +205 -180
  143. package/lib/rules/max-statements.js +168 -164
  144. package/lib/rules/multiline-comment-style.js +638 -460
  145. package/lib/rules/multiline-ternary.js +241 -158
  146. package/lib/rules/new-cap.js +233 -232
  147. package/lib/rules/new-parens.js +88 -61
  148. package/lib/rules/newline-after-var.js +287 -233
  149. package/lib/rules/newline-before-return.js +229 -204
  150. package/lib/rules/newline-per-chained-call.js +142 -109
  151. package/lib/rules/no-alert.js +90 -79
  152. package/lib/rules/no-array-constructor.js +175 -113
  153. package/lib/rules/no-async-promise-executor.js +30 -24
  154. package/lib/rules/no-await-in-loop.js +79 -70
  155. package/lib/rules/no-bitwise.js +113 -87
  156. package/lib/rules/no-buffer-constructor.js +61 -37
  157. package/lib/rules/no-caller.js +39 -33
  158. package/lib/rules/no-case-declarations.js +61 -45
  159. package/lib/rules/no-catch-shadow.js +76 -62
  160. package/lib/rules/no-class-assign.js +51 -48
  161. package/lib/rules/no-compare-neg-zero.js +62 -48
  162. package/lib/rules/no-cond-assign.js +148 -132
  163. package/lib/rules/no-confusing-arrow.js +98 -63
  164. package/lib/rules/no-console.js +202 -188
  165. package/lib/rules/no-const-assign.js +58 -41
  166. package/lib/rules/no-constant-binary-expression.js +501 -407
  167. package/lib/rules/no-constant-condition.js +158 -131
  168. package/lib/rules/no-constructor-return.js +49 -49
  169. package/lib/rules/no-continue.js +25 -26
  170. package/lib/rules/no-control-regex.js +125 -121
  171. package/lib/rules/no-debugger.js +28 -30
  172. package/lib/rules/no-delete-var.js +29 -29
  173. package/lib/rules/no-div-regex.js +47 -40
  174. package/lib/rules/no-dupe-args.js +79 -69
  175. package/lib/rules/no-dupe-class-members.js +102 -89
  176. package/lib/rules/no-dupe-else-if.js +100 -77
  177. package/lib/rules/no-dupe-keys.js +133 -110
  178. package/lib/rules/no-duplicate-case.js +50 -43
  179. package/lib/rules/no-duplicate-imports.js +266 -188
  180. package/lib/rules/no-else-return.js +430 -385
  181. package/lib/rules/no-empty-character-class.js +57 -50
  182. package/lib/rules/no-empty-function.js +197 -128
  183. package/lib/rules/no-empty-pattern.js +63 -56
  184. package/lib/rules/no-empty-static-block.js +61 -35
  185. package/lib/rules/no-empty.js +135 -85
  186. package/lib/rules/no-eq-null.js +37 -32
  187. package/lib/rules/no-eval.js +258 -249
  188. package/lib/rules/no-ex-assign.js +42 -39
  189. package/lib/rules/no-extend-native.js +161 -160
  190. package/lib/rules/no-extra-bind.js +201 -190
  191. package/lib/rules/no-extra-boolean-cast.js +398 -295
  192. package/lib/rules/no-extra-label.js +150 -130
  193. package/lib/rules/no-extra-parens.js +1654 -1307
  194. package/lib/rules/no-extra-semi.js +146 -126
  195. package/lib/rules/no-fallthrough.js +200 -136
  196. package/lib/rules/no-floating-decimal.js +74 -48
  197. package/lib/rules/no-func-assign.js +54 -55
  198. package/lib/rules/no-global-assign.js +78 -72
  199. package/lib/rules/no-implicit-coercion.js +350 -262
  200. package/lib/rules/no-implicit-globals.js +174 -133
  201. package/lib/rules/no-implied-eval.js +150 -112
  202. package/lib/rules/no-import-assign.js +145 -159
  203. package/lib/rules/no-inline-comments.js +101 -96
  204. package/lib/rules/no-inner-declarations.js +115 -78
  205. package/lib/rules/no-invalid-regexp.js +223 -174
  206. package/lib/rules/no-invalid-this.js +145 -117
  207. package/lib/rules/no-irregular-whitespace.js +266 -250
  208. package/lib/rules/no-iterator.js +29 -33
  209. package/lib/rules/no-label-var.js +59 -61
  210. package/lib/rules/no-labels.js +138 -131
  211. package/lib/rules/no-lone-blocks.js +127 -123
  212. package/lib/rules/no-lonely-if.js +105 -67
  213. package/lib/rules/no-loop-func.js +245 -184
  214. package/lib/rules/no-loss-of-precision.js +236 -201
  215. package/lib/rules/no-magic-numbers.js +339 -217
  216. package/lib/rules/no-misleading-character-class.js +548 -253
  217. package/lib/rules/no-mixed-operators.js +188 -164
  218. package/lib/rules/no-mixed-requires.js +253 -224
  219. package/lib/rules/no-mixed-spaces-and-tabs.js +135 -103
  220. package/lib/rules/no-multi-assign.js +46 -47
  221. package/lib/rules/no-multi-spaces.js +163 -125
  222. package/lib/rules/no-multi-str.js +42 -40
  223. package/lib/rules/no-multiple-empty-lines.js +196 -140
  224. package/lib/rules/no-native-reassign.js +90 -74
  225. package/lib/rules/no-negated-condition.js +79 -74
  226. package/lib/rules/no-negated-in-lhs.js +45 -32
  227. package/lib/rules/no-nested-ternary.js +33 -31
  228. package/lib/rules/no-new-func.js +71 -62
  229. package/lib/rules/no-new-native-nonconstructor.js +43 -39
  230. package/lib/rules/no-new-object.js +48 -39
  231. package/lib/rules/no-new-require.js +48 -31
  232. package/lib/rules/no-new-symbol.js +61 -43
  233. package/lib/rules/no-new-wrappers.js +43 -41
  234. package/lib/rules/no-new.js +28 -29
  235. package/lib/rules/no-nonoctal-decimal-escape.js +149 -121
  236. package/lib/rules/no-obj-calls.js +66 -53
  237. package/lib/rules/no-object-constructor.js +104 -97
  238. package/lib/rules/no-octal-escape.js +40 -43
  239. package/lib/rules/no-octal.js +29 -32
  240. package/lib/rules/no-param-reassign.js +236 -218
  241. package/lib/rules/no-path-concat.js +66 -51
  242. package/lib/rules/no-plusplus.js +60 -63
  243. package/lib/rules/no-process-env.js +49 -32
  244. package/lib/rules/no-process-exit.js +48 -28
  245. package/lib/rules/no-promise-executor-return.js +205 -204
  246. package/lib/rules/no-proto.js +26 -29
  247. package/lib/rules/no-prototype-builtins.js +146 -124
  248. package/lib/rules/no-redeclare.js +154 -155
  249. package/lib/rules/no-regex-spaces.js +183 -161
  250. package/lib/rules/no-restricted-exports.js +208 -174
  251. package/lib/rules/no-restricted-globals.js +254 -112
  252. package/lib/rules/no-restricted-imports.js +824 -384
  253. package/lib/rules/no-restricted-modules.js +222 -186
  254. package/lib/rules/no-restricted-properties.js +218 -153
  255. package/lib/rules/no-restricted-syntax.js +56 -52
  256. package/lib/rules/no-return-assign.js +56 -49
  257. package/lib/rules/no-return-await.js +147 -120
  258. package/lib/rules/no-script-url.js +53 -46
  259. package/lib/rules/no-self-assign.js +148 -145
  260. package/lib/rules/no-self-compare.js +63 -46
  261. package/lib/rules/no-sequences.js +135 -115
  262. package/lib/rules/no-setter-return.js +176 -178
  263. package/lib/rules/no-shadow-restricted-names.js +84 -36
  264. package/lib/rules/no-shadow.js +598 -310
  265. package/lib/rules/no-spaced-func.js +82 -60
  266. package/lib/rules/no-sparse-arrays.js +46 -28
  267. package/lib/rules/no-sync.js +61 -44
  268. package/lib/rules/no-tabs.js +83 -54
  269. package/lib/rules/no-template-curly-in-string.js +33 -32
  270. package/lib/rules/no-ternary.js +25 -28
  271. package/lib/rules/no-this-before-super.js +332 -298
  272. package/lib/rules/no-throw-literal.js +31 -36
  273. package/lib/rules/no-trailing-spaces.js +208 -174
  274. package/lib/rules/no-unassigned-vars.js +80 -0
  275. package/lib/rules/no-undef-init.js +86 -60
  276. package/lib/rules/no-undef.js +52 -47
  277. package/lib/rules/no-undefined.js +73 -74
  278. package/lib/rules/no-underscore-dangle.js +370 -322
  279. package/lib/rules/no-unexpected-multiline.js +112 -102
  280. package/lib/rules/no-unmodified-loop-condition.js +254 -254
  281. package/lib/rules/no-unneeded-ternary.js +212 -146
  282. package/lib/rules/no-unreachable-loop.js +145 -140
  283. package/lib/rules/no-unreachable.js +255 -248
  284. package/lib/rules/no-unsafe-finally.js +93 -85
  285. package/lib/rules/no-unsafe-negation.js +105 -81
  286. package/lib/rules/no-unsafe-optional-chaining.js +193 -177
  287. package/lib/rules/no-unused-expressions.js +199 -158
  288. package/lib/rules/no-unused-labels.js +139 -124
  289. package/lib/rules/no-unused-private-class-members.js +206 -182
  290. package/lib/rules/no-unused-vars.js +1708 -687
  291. package/lib/rules/no-use-before-define.js +327 -229
  292. package/lib/rules/no-useless-assignment.js +654 -0
  293. package/lib/rules/no-useless-backreference.js +212 -143
  294. package/lib/rules/no-useless-call.js +58 -53
  295. package/lib/rules/no-useless-catch.js +40 -40
  296. package/lib/rules/no-useless-computed-key.js +144 -108
  297. package/lib/rules/no-useless-concat.js +65 -59
  298. package/lib/rules/no-useless-constructor.js +160 -97
  299. package/lib/rules/no-useless-escape.js +364 -291
  300. package/lib/rules/no-useless-rename.js +183 -153
  301. package/lib/rules/no-useless-return.js +344 -307
  302. package/lib/rules/no-var.js +245 -212
  303. package/lib/rules/no-void.js +51 -46
  304. package/lib/rules/no-warning-comments.js +191 -183
  305. package/lib/rules/no-whitespace-before-property.js +131 -97
  306. package/lib/rules/no-with.js +24 -26
  307. package/lib/rules/nonblock-statement-body-position.js +149 -112
  308. package/lib/rules/object-curly-newline.js +306 -247
  309. package/lib/rules/object-curly-spacing.js +360 -296
  310. package/lib/rules/object-property-newline.js +137 -88
  311. package/lib/rules/object-shorthand.js +632 -500
  312. package/lib/rules/one-var-declaration-per-line.js +104 -82
  313. package/lib/rules/one-var.js +686 -536
  314. package/lib/rules/operator-assignment.js +219 -158
  315. package/lib/rules/operator-linebreak.js +295 -233
  316. package/lib/rules/padded-blocks.js +346 -290
  317. package/lib/rules/padding-line-between-statements.js +443 -421
  318. package/lib/rules/prefer-arrow-callback.js +371 -315
  319. package/lib/rules/prefer-const.js +418 -373
  320. package/lib/rules/prefer-destructuring.js +309 -278
  321. package/lib/rules/prefer-exponentiation-operator.js +176 -132
  322. package/lib/rules/prefer-named-capture-group.js +160 -141
  323. package/lib/rules/prefer-numeric-literals.js +121 -112
  324. package/lib/rules/prefer-object-has-own.js +116 -82
  325. package/lib/rules/prefer-object-spread.js +214 -193
  326. package/lib/rules/prefer-promise-reject-errors.js +140 -118
  327. package/lib/rules/prefer-reflect.js +126 -103
  328. package/lib/rules/prefer-regex-literals.js +561 -463
  329. package/lib/rules/prefer-rest-params.js +79 -80
  330. package/lib/rules/prefer-spread.js +47 -43
  331. package/lib/rules/prefer-template.js +266 -194
  332. package/lib/rules/preserve-caught-error.js +535 -0
  333. package/lib/rules/quote-props.js +373 -289
  334. package/lib/rules/quotes.js +374 -308
  335. package/lib/rules/radix.js +152 -134
  336. package/lib/rules/require-atomic-updates.js +316 -282
  337. package/lib/rules/require-await.js +153 -82
  338. package/lib/rules/require-unicode-regexp.js +296 -108
  339. package/lib/rules/require-yield.js +53 -54
  340. package/lib/rules/rest-spread-spacing.js +128 -98
  341. package/lib/rules/semi-spacing.js +281 -232
  342. package/lib/rules/semi-style.js +176 -116
  343. package/lib/rules/semi.js +456 -418
  344. package/lib/rules/sort-imports.js +307 -229
  345. package/lib/rules/sort-keys.js +219 -181
  346. package/lib/rules/sort-vars.js +127 -91
  347. package/lib/rules/space-before-blocks.js +199 -171
  348. package/lib/rules/space-before-function-paren.js +186 -148
  349. package/lib/rules/space-in-parens.js +359 -270
  350. package/lib/rules/space-infix-ops.js +237 -183
  351. package/lib/rules/space-unary-ops.js +356 -280
  352. package/lib/rules/spaced-comment.js +363 -301
  353. package/lib/rules/strict.js +266 -229
  354. package/lib/rules/switch-colon-spacing.js +130 -104
  355. package/lib/rules/symbol-description.js +45 -48
  356. package/lib/rules/template-curly-spacing.js +148 -124
  357. package/lib/rules/template-tag-spacing.js +98 -70
  358. package/lib/rules/unicode-bom.js +54 -54
  359. package/lib/rules/use-isnan.js +237 -110
  360. package/lib/rules/utils/ast-utils.js +2139 -1688
  361. package/lib/rules/utils/char-source.js +247 -0
  362. package/lib/rules/utils/fix-tracker.js +99 -88
  363. package/lib/rules/utils/keywords.js +59 -59
  364. package/lib/rules/utils/lazy-loading-rule-map.js +81 -78
  365. package/lib/rules/utils/regular-expressions.js +35 -19
  366. package/lib/rules/utils/unicode/index.js +9 -4
  367. package/lib/rules/utils/unicode/is-combining-character.js +1 -1
  368. package/lib/rules/utils/unicode/is-emoji-modifier.js +1 -1
  369. package/lib/rules/utils/unicode/is-regional-indicator-symbol.js +1 -1
  370. package/lib/rules/utils/unicode/is-surrogate-pair.js +1 -1
  371. package/lib/rules/valid-typeof.js +153 -109
  372. package/lib/rules/vars-on-top.js +152 -144
  373. package/lib/rules/wrap-iife.js +204 -173
  374. package/lib/rules/wrap-regex.js +77 -47
  375. package/lib/rules/yield-star-spacing.js +145 -116
  376. package/lib/rules/yoda.js +283 -274
  377. package/lib/services/parser-service.js +65 -0
  378. package/lib/services/processor-service.js +101 -0
  379. package/lib/services/suppressions-service.js +302 -0
  380. package/lib/services/warning-service.js +98 -0
  381. package/lib/shared/ajv.js +14 -14
  382. package/lib/shared/assert.js +21 -0
  383. package/lib/shared/ast-utils.js +7 -6
  384. package/lib/shared/deep-merge-arrays.js +62 -0
  385. package/lib/shared/directives.js +3 -2
  386. package/lib/shared/flags.js +108 -0
  387. package/lib/shared/logging.js +24 -16
  388. package/lib/shared/naming.js +109 -0
  389. package/lib/shared/option-utils.js +63 -0
  390. package/lib/shared/relative-module-resolver.js +18 -40
  391. package/lib/shared/runtime-info.js +138 -128
  392. package/lib/shared/serialization.js +78 -0
  393. package/lib/shared/severity.js +22 -22
  394. package/lib/shared/stats.js +30 -0
  395. package/lib/shared/string-utils.js +19 -21
  396. package/lib/shared/text-table.js +68 -0
  397. package/lib/shared/translate-cli-options.js +281 -0
  398. package/lib/shared/traverser.js +153 -146
  399. package/lib/types/config-api.d.ts +12 -0
  400. package/lib/types/index.d.ts +1473 -0
  401. package/lib/types/rules.d.ts +5589 -0
  402. package/lib/types/universal.d.ts +6 -0
  403. package/lib/types/use-at-your-own-risk.d.ts +87 -0
  404. package/lib/universal.js +10 -0
  405. package/lib/unsupported-api.js +8 -9
  406. package/messages/all-files-ignored.js +3 -3
  407. package/messages/all-matched-files-ignored.js +21 -0
  408. package/messages/config-file-missing.js +16 -0
  409. package/messages/config-plugin-missing.js +14 -0
  410. package/messages/config-serialize-function.js +30 -0
  411. package/messages/eslintrc-incompat.js +35 -16
  412. package/messages/eslintrc-plugins.js +8 -5
  413. package/messages/extend-config-missing.js +3 -3
  414. package/messages/failed-to-read-json.js +3 -3
  415. package/messages/file-not-found.js +3 -3
  416. package/messages/invalid-rule-options.js +2 -2
  417. package/messages/invalid-rule-severity.js +2 -2
  418. package/messages/no-config-found.js +4 -4
  419. package/messages/plugin-conflict.js +9 -9
  420. package/messages/plugin-invalid.js +4 -4
  421. package/messages/plugin-missing.js +4 -4
  422. package/messages/print-config-with-directory-path.js +2 -2
  423. package/messages/shared.js +6 -1
  424. package/messages/whitespace-found.js +3 -3
  425. package/package.json +105 -60
  426. package/conf/config-schema.js +0 -93
  427. package/lib/cli-engine/formatters/checkstyle.js +0 -60
  428. package/lib/cli-engine/formatters/compact.js +0 -60
  429. package/lib/cli-engine/formatters/jslint-xml.js +0 -41
  430. package/lib/cli-engine/formatters/junit.js +0 -82
  431. package/lib/cli-engine/formatters/tap.js +0 -95
  432. package/lib/cli-engine/formatters/unix.js +0 -58
  433. package/lib/cli-engine/formatters/visualstudio.js +0 -63
  434. package/lib/cli-engine/xml-escape.js +0 -34
  435. package/lib/config/flat-config-helpers.js +0 -111
  436. package/lib/config/rule-validator.js +0 -158
  437. package/lib/eslint/flat-eslint.js +0 -1159
  438. package/lib/linter/config-comment-parser.js +0 -185
  439. package/lib/linter/node-event-generator.js +0 -354
  440. package/lib/linter/report-translator.js +0 -369
  441. package/lib/linter/safe-emitter.js +0 -52
  442. package/lib/rule-tester/flat-rule-tester.js +0 -1131
  443. package/lib/rules/require-jsdoc.js +0 -122
  444. package/lib/rules/utils/patterns/letters.js +0 -36
  445. package/lib/rules/valid-jsdoc.js +0 -516
  446. package/lib/shared/config-validator.js +0 -347
  447. package/lib/shared/deprecation-warnings.js +0 -58
  448. package/lib/shared/types.js +0 -216
  449. package/lib/source-code/index.js +0 -5
  450. package/lib/source-code/source-code.js +0 -1055
  451. package/lib/source-code/token-store/backward-token-comment-cursor.js +0 -57
  452. package/lib/source-code/token-store/backward-token-cursor.js +0 -58
  453. package/lib/source-code/token-store/cursors.js +0 -90
  454. package/lib/source-code/token-store/forward-token-comment-cursor.js +0 -57
  455. package/lib/source-code/token-store/forward-token-cursor.js +0 -63
  456. package/lib/source-code/token-store/index.js +0 -627
  457. package/lib/source-code/token-store/padded-token-cursor.js +0 -38
  458. package/lib/source-code/token-store/utils.js +0 -107
@@ -14,62 +14,85 @@ const esutils = require("esutils");
14
14
  const espree = require("espree");
15
15
  const escapeRegExp = require("escape-string-regexp");
16
16
  const {
17
- breakableTypePattern,
18
- createGlobalLinebreakMatcher,
19
- lineBreakPattern,
20
- shebangPattern
17
+ breakableTypePattern,
18
+ createGlobalLinebreakMatcher,
19
+ lineBreakPattern,
20
+ shebangPattern,
21
21
  } = require("../../shared/ast-utils");
22
+ const globals = require("../../../conf/globals");
23
+ const { LATEST_ECMA_VERSION } = require("../../../conf/ecma-version");
22
24
 
23
25
  //------------------------------------------------------------------------------
24
26
  // Helpers
25
27
  //------------------------------------------------------------------------------
26
28
 
27
- const anyFunctionPattern = /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/u;
29
+ const anyFunctionPattern =
30
+ /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression)$/u;
28
31
  const anyLoopPattern = /^(?:DoWhile|For|ForIn|ForOf|While)Statement$/u;
29
- const arrayMethodWithThisArgPattern = /^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|some)$/u;
32
+ const arrayMethodWithThisArgPattern =
33
+ /^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|some)$/u;
30
34
  const arrayOrTypedArrayPattern = /Array$/u;
31
35
  const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/u;
32
36
  const thisTagPattern = /^[\s*]*@this/mu;
33
37
 
34
-
35
- const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u;
38
+ const COMMENTS_IGNORE_PATTERN =
39
+ /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u;
36
40
  const ESLINT_DIRECTIVE_PATTERN = /^(?:eslint[- ]|(?:globals?|exported) )/u;
37
41
  const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
38
42
 
39
43
  // A set of node types that can contain a list of statements
40
- const STATEMENT_LIST_PARENTS = new Set(["Program", "BlockStatement", "StaticBlock", "SwitchCase"]);
44
+ const STATEMENT_LIST_PARENTS = new Set([
45
+ "Program",
46
+ "BlockStatement",
47
+ "StaticBlock",
48
+ "SwitchCase",
49
+ ]);
50
+ const LEXICAL_DECLARATION_KINDS = new Set([
51
+ "let",
52
+ "const",
53
+ "using",
54
+ "await using",
55
+ ]);
41
56
 
42
57
  const DECIMAL_INTEGER_PATTERN = /^(?:0|0[0-7]*[89]\d*|[1-9](?:_?\d)*)$/u;
43
58
 
44
59
  // Tests the presence of at least one LegacyOctalEscapeSequence or NonOctalDecimalEscapeSequence in a raw string
45
- const OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN = /^(?:[^\\]|\\.)*\\(?:[1-9]|0[0-9])/su;
60
+ const OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN =
61
+ /^(?:[^\\]|\\.)*\\(?:[1-9]|0\d)/su;
46
62
 
47
63
  const LOGICAL_ASSIGNMENT_OPERATORS = new Set(["&&=", "||=", "??="]);
48
64
 
65
+ /**
66
+ * All builtin global variables defined in the latest ECMAScript specification.
67
+ * @type {Record<string,boolean>} Key is the name of the variable. Value is `true` if the variable is considered writable, `false` otherwise.
68
+ */
69
+ const ECMASCRIPT_GLOBALS = globals[`es${LATEST_ECMA_VERSION}`];
70
+
49
71
  /**
50
72
  * Checks reference if is non initializer and writable.
51
73
  * @param {Reference} reference A reference to check.
52
- * @param {int} index The index of the reference in the references.
74
+ * @param {number} index The index of the reference in the references.
53
75
  * @param {Reference[]} references The array that the reference belongs to.
54
76
  * @returns {boolean} Success/Failure
55
77
  * @private
56
78
  */
57
79
  function isModifyingReference(reference, index, references) {
58
- const identifier = reference.identifier;
59
-
60
- /*
61
- * Destructuring assignments can have multiple default value, so
62
- * possibly there are multiple writeable references for the same
63
- * identifier.
64
- */
65
- const modifyingDifferentIdentifier = index === 0 ||
66
- references[index - 1].identifier !== identifier;
67
-
68
- return (identifier &&
69
- reference.init === false &&
70
- reference.isWrite() &&
71
- modifyingDifferentIdentifier
72
- );
80
+ const identifier = reference.identifier;
81
+
82
+ /*
83
+ * Destructuring assignments can have multiple default value, so
84
+ * possibly there are multiple writeable references for the same
85
+ * identifier.
86
+ */
87
+ const modifyingDifferentIdentifier =
88
+ index === 0 || references[index - 1].identifier !== identifier;
89
+
90
+ return (
91
+ identifier &&
92
+ reference.init === false &&
93
+ reference.isWrite() &&
94
+ modifyingDifferentIdentifier
95
+ );
73
96
  }
74
97
 
75
98
  /**
@@ -78,7 +101,7 @@ function isModifyingReference(reference, index, references) {
78
101
  * @returns {boolean} `true` if the string starts with uppercase.
79
102
  */
80
103
  function startsWithUpperCase(s) {
81
- return s[0] !== s[0].toLocaleLowerCase();
104
+ return s[0] !== s[0].toLocaleLowerCase();
82
105
  }
83
106
 
84
107
  /**
@@ -87,7 +110,7 @@ function startsWithUpperCase(s) {
87
110
  * @returns {boolean} Whether or not a node is a constructor.
88
111
  */
89
112
  function isES5Constructor(node) {
90
- return (node.id && startsWithUpperCase(node.id.name));
113
+ return node.id && startsWithUpperCase(node.id.name);
91
114
  }
92
115
 
93
116
  /**
@@ -96,12 +119,16 @@ function isES5Constructor(node) {
96
119
  * @returns {Node|null} A found function node.
97
120
  */
98
121
  function getUpperFunction(node) {
99
- for (let currentNode = node; currentNode; currentNode = currentNode.parent) {
100
- if (anyFunctionPattern.test(currentNode.type)) {
101
- return currentNode;
102
- }
103
- }
104
- return null;
122
+ for (
123
+ let currentNode = node;
124
+ currentNode;
125
+ currentNode = currentNode.parent
126
+ ) {
127
+ if (anyFunctionPattern.test(currentNode.type)) {
128
+ return currentNode;
129
+ }
130
+ }
131
+ return null;
105
132
  }
106
133
 
107
134
  /**
@@ -115,7 +142,7 @@ function getUpperFunction(node) {
115
142
  * @returns {boolean} `true` if the node is a function node.
116
143
  */
117
144
  function isFunction(node) {
118
- return Boolean(node && anyFunctionPattern.test(node.type));
145
+ return Boolean(node && anyFunctionPattern.test(node.type));
119
146
  }
120
147
 
121
148
  /**
@@ -131,7 +158,7 @@ function isFunction(node) {
131
158
  * @returns {boolean} `true` if the node is a loop node.
132
159
  */
133
160
  function isLoop(node) {
134
- return Boolean(node && anyLoopPattern.test(node.type));
161
+ return Boolean(node && anyLoopPattern.test(node.type));
135
162
  }
136
163
 
137
164
  /**
@@ -140,13 +167,17 @@ function isLoop(node) {
140
167
  * @returns {boolean} `true` if the node is in a loop.
141
168
  */
142
169
  function isInLoop(node) {
143
- for (let currentNode = node; currentNode && !isFunction(currentNode); currentNode = currentNode.parent) {
144
- if (isLoop(currentNode)) {
145
- return true;
146
- }
147
- }
148
-
149
- return false;
170
+ for (
171
+ let currentNode = node;
172
+ currentNode && !isFunction(currentNode);
173
+ currentNode = currentNode.parent
174
+ ) {
175
+ if (isLoop(currentNode)) {
176
+ return true;
177
+ }
178
+ }
179
+
180
+ return false;
150
181
  }
151
182
 
152
183
  /**
@@ -155,15 +186,19 @@ function isInLoop(node) {
155
186
  * @returns {boolean} `true` if the node is a `null` literal
156
187
  */
157
188
  function isNullLiteral(node) {
158
-
159
- /*
160
- * Checking `node.value === null` does not guarantee that a literal is a null literal.
161
- * When parsing values that cannot be represented in the current environment (e.g. unicode
162
- * regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
163
- * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
164
- * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
165
- */
166
- return node.type === "Literal" && node.value === null && !node.regex && !node.bigint;
189
+ /*
190
+ * Checking `node.value === null` does not guarantee that a literal is a null literal.
191
+ * When parsing values that cannot be represented in the current environment (e.g. unicode
192
+ * regexes in Node 4), `node.value` is set to `null` because it wouldn't be possible to
193
+ * set `node.value` to a unicode regex. To make sure a literal is actually `null`, check
194
+ * `node.regex` instead. Also see: https://github.com/eslint/eslint/issues/8020
195
+ */
196
+ return (
197
+ node.type === "Literal" &&
198
+ node.value === null &&
199
+ !node.regex &&
200
+ !node.bigint
201
+ );
167
202
  }
168
203
 
169
204
  /**
@@ -173,11 +208,11 @@ function isNullLiteral(node) {
173
208
  * @public
174
209
  */
175
210
  function isNullOrUndefined(node) {
176
- return (
177
- isNullLiteral(node) ||
178
- (node.type === "Identifier" && node.name === "undefined") ||
179
- (node.type === "UnaryExpression" && node.operator === "void")
180
- );
211
+ return (
212
+ isNullLiteral(node) ||
213
+ (node.type === "Identifier" && node.name === "undefined") ||
214
+ (node.type === "UnaryExpression" && node.operator === "void")
215
+ );
181
216
  }
182
217
 
183
218
  /**
@@ -186,7 +221,7 @@ function isNullOrUndefined(node) {
186
221
  * @returns {boolean} Whether or not the node is callee.
187
222
  */
188
223
  function isCallee(node) {
189
- return node.parent.type === "CallExpression" && node.parent.callee === node;
224
+ return node.parent.type === "CallExpression" && node.parent.callee === node;
190
225
  }
191
226
 
192
227
  /**
@@ -199,35 +234,34 @@ function isCallee(node) {
199
234
  * @returns {string|null} String value if it can be determined. Otherwise, `null`.
200
235
  */
201
236
  function getStaticStringValue(node) {
202
- switch (node.type) {
203
- case "Literal":
204
- if (node.value === null) {
205
- if (isNullLiteral(node)) {
206
- return String(node.value); // "null"
207
- }
208
- if (node.regex) {
209
- return `/${node.regex.pattern}/${node.regex.flags}`;
210
- }
211
- if (node.bigint) {
212
- return node.bigint;
213
- }
214
-
215
- // Otherwise, this is an unknown literal. The function will return null.
216
-
217
- } else {
218
- return String(node.value);
219
- }
220
- break;
221
- case "TemplateLiteral":
222
- if (node.expressions.length === 0 && node.quasis.length === 1) {
223
- return node.quasis[0].value.cooked;
224
- }
225
- break;
226
-
227
- // no default
228
- }
229
-
230
- return null;
237
+ switch (node.type) {
238
+ case "Literal":
239
+ if (node.value === null) {
240
+ if (isNullLiteral(node)) {
241
+ return String(node.value); // "null"
242
+ }
243
+ if (node.regex) {
244
+ return `/${node.regex.pattern}/${node.regex.flags}`;
245
+ }
246
+ if (node.bigint) {
247
+ return node.bigint;
248
+ }
249
+
250
+ // Otherwise, this is an unknown literal. The function will return null.
251
+ } else {
252
+ return String(node.value);
253
+ }
254
+ break;
255
+ case "TemplateLiteral":
256
+ if (node.expressions.length === 0 && node.quasis.length === 1) {
257
+ return node.quasis[0].value.cooked;
258
+ }
259
+ break;
260
+
261
+ // no default
262
+ }
263
+
264
+ return null;
231
265
  }
232
266
 
233
267
  /**
@@ -261,34 +295,36 @@ function getStaticStringValue(node) {
261
295
  * @returns {string|null} The property name if static. Otherwise, null.
262
296
  */
263
297
  function getStaticPropertyName(node) {
264
- let prop;
298
+ let prop;
265
299
 
266
- switch (node && node.type) {
267
- case "ChainExpression":
268
- return getStaticPropertyName(node.expression);
300
+ switch (node && node.type) {
301
+ case "ChainExpression":
302
+ return getStaticPropertyName(node.expression);
269
303
 
270
- case "Property":
271
- case "PropertyDefinition":
272
- case "MethodDefinition":
273
- prop = node.key;
274
- break;
304
+ case "Property":
305
+ case "PropertyDefinition":
306
+ case "MethodDefinition":
307
+ case "TSPropertySignature":
308
+ case "TSMethodSignature":
309
+ prop = node.key;
310
+ break;
275
311
 
276
- case "MemberExpression":
277
- prop = node.property;
278
- break;
312
+ case "MemberExpression":
313
+ prop = node.property;
314
+ break;
279
315
 
280
- // no default
281
- }
316
+ // no default
317
+ }
282
318
 
283
- if (prop) {
284
- if (prop.type === "Identifier" && !node.computed) {
285
- return prop.name;
286
- }
319
+ if (prop) {
320
+ if (prop.type === "Identifier" && !node.computed) {
321
+ return prop.name;
322
+ }
287
323
 
288
- return getStaticStringValue(prop);
289
- }
324
+ return getStaticStringValue(prop);
325
+ }
290
326
 
291
- return null;
327
+ return null;
292
328
  }
293
329
 
294
330
  /**
@@ -297,7 +333,7 @@ function getStaticPropertyName(node) {
297
333
  * @returns {ASTNode} The `ChainExpression#expression` value if the node is a `ChainExpression` node. Otherwise, the node.
298
334
  */
299
335
  function skipChainExpression(node) {
300
- return node && node.type === "ChainExpression" ? node.expression : node;
336
+ return node && node.type === "ChainExpression" ? node.expression : node;
301
337
  }
302
338
 
303
339
  /**
@@ -307,9 +343,9 @@ function skipChainExpression(node) {
307
343
  * @returns {boolean} `true` if the `actual` is an expected value.
308
344
  */
309
345
  function checkText(actual, expected) {
310
- return typeof expected === "string"
311
- ? actual === expected
312
- : expected.test(actual);
346
+ return typeof expected === "string"
347
+ ? actual === expected
348
+ : expected.test(actual);
313
349
  }
314
350
 
315
351
  /**
@@ -319,7 +355,7 @@ function checkText(actual, expected) {
319
355
  * @returns {boolean} `true` if the node is an Identifier node with the name.
320
356
  */
321
357
  function isSpecificId(node, name) {
322
- return node.type === "Identifier" && checkText(node.name, name);
358
+ return node.type === "Identifier" && checkText(node.name, name);
323
359
  }
324
360
 
325
361
  /**
@@ -332,25 +368,28 @@ function isSpecificId(node, name) {
332
368
  * The node is a `MemberExpression` or `ChainExpression`.
333
369
  */
334
370
  function isSpecificMemberAccess(node, objectName, propertyName) {
335
- const checkNode = skipChainExpression(node);
371
+ const checkNode = skipChainExpression(node);
336
372
 
337
- if (checkNode.type !== "MemberExpression") {
338
- return false;
339
- }
373
+ if (checkNode.type !== "MemberExpression") {
374
+ return false;
375
+ }
340
376
 
341
- if (objectName && !isSpecificId(checkNode.object, objectName)) {
342
- return false;
343
- }
377
+ if (objectName && !isSpecificId(checkNode.object, objectName)) {
378
+ return false;
379
+ }
344
380
 
345
- if (propertyName) {
346
- const actualPropertyName = getStaticPropertyName(checkNode);
381
+ if (propertyName) {
382
+ const actualPropertyName = getStaticPropertyName(checkNode);
347
383
 
348
- if (typeof actualPropertyName !== "string" || !checkText(actualPropertyName, propertyName)) {
349
- return false;
350
- }
351
- }
384
+ if (
385
+ typeof actualPropertyName !== "string" ||
386
+ !checkText(actualPropertyName, propertyName)
387
+ ) {
388
+ return false;
389
+ }
390
+ }
352
391
 
353
- return true;
392
+ return true;
354
393
  }
355
394
 
356
395
  /**
@@ -360,23 +399,22 @@ function isSpecificMemberAccess(node, objectName, propertyName) {
360
399
  * @returns {boolean} `true` if the two literal nodes are the same value.
361
400
  */
362
401
  function equalLiteralValue(left, right) {
363
-
364
- // RegExp literal.
365
- if (left.regex || right.regex) {
366
- return Boolean(
367
- left.regex &&
368
- right.regex &&
369
- left.regex.pattern === right.regex.pattern &&
370
- left.regex.flags === right.regex.flags
371
- );
372
- }
373
-
374
- // BigInt literal.
375
- if (left.bigint || right.bigint) {
376
- return left.bigint === right.bigint;
377
- }
378
-
379
- return left.value === right.value;
402
+ // RegExp literal.
403
+ if (left.regex || right.regex) {
404
+ return Boolean(
405
+ left.regex &&
406
+ right.regex &&
407
+ left.regex.pattern === right.regex.pattern &&
408
+ left.regex.flags === right.regex.flags,
409
+ );
410
+ }
411
+
412
+ // BigInt literal.
413
+ if (left.bigint || right.bigint) {
414
+ return left.bigint === right.bigint;
415
+ }
416
+
417
+ return left.value === right.value;
380
418
  }
381
419
 
382
420
  /**
@@ -391,61 +429,83 @@ function equalLiteralValue(left, right) {
391
429
  * @returns {boolean} `true` if both sides match and reference the same value.
392
430
  */
393
431
  function isSameReference(left, right, disableStaticComputedKey = false) {
394
- if (left.type !== right.type) {
395
-
396
- // Handle `a.b` and `a?.b` are samely.
397
- if (left.type === "ChainExpression") {
398
- return isSameReference(left.expression, right, disableStaticComputedKey);
399
- }
400
- if (right.type === "ChainExpression") {
401
- return isSameReference(left, right.expression, disableStaticComputedKey);
402
- }
403
-
404
- return false;
405
- }
406
-
407
- switch (left.type) {
408
- case "Super":
409
- case "ThisExpression":
410
- return true;
411
-
412
- case "Identifier":
413
- case "PrivateIdentifier":
414
- return left.name === right.name;
415
- case "Literal":
416
- return equalLiteralValue(left, right);
417
-
418
- case "ChainExpression":
419
- return isSameReference(left.expression, right.expression, disableStaticComputedKey);
420
-
421
- case "MemberExpression": {
422
- if (!disableStaticComputedKey) {
423
- const nameA = getStaticPropertyName(left);
424
-
425
- // x.y = x["y"]
426
- if (nameA !== null) {
427
- return (
428
- isSameReference(left.object, right.object, disableStaticComputedKey) &&
429
- nameA === getStaticPropertyName(right)
430
- );
431
- }
432
- }
433
-
434
- /*
435
- * x[0] = x[0]
436
- * x[y] = x[y]
437
- * x.y = x.y
438
- */
439
- return (
440
- left.computed === right.computed &&
441
- isSameReference(left.object, right.object, disableStaticComputedKey) &&
442
- isSameReference(left.property, right.property, disableStaticComputedKey)
443
- );
444
- }
445
-
446
- default:
447
- return false;
448
- }
432
+ if (left.type !== right.type) {
433
+ // Handle `a.b` and `a?.b` are samely.
434
+ if (left.type === "ChainExpression") {
435
+ return isSameReference(
436
+ left.expression,
437
+ right,
438
+ disableStaticComputedKey,
439
+ );
440
+ }
441
+ if (right.type === "ChainExpression") {
442
+ return isSameReference(
443
+ left,
444
+ right.expression,
445
+ disableStaticComputedKey,
446
+ );
447
+ }
448
+
449
+ return false;
450
+ }
451
+
452
+ switch (left.type) {
453
+ case "Super":
454
+ case "ThisExpression":
455
+ return true;
456
+
457
+ case "Identifier":
458
+ case "PrivateIdentifier":
459
+ return left.name === right.name;
460
+ case "Literal":
461
+ return equalLiteralValue(left, right);
462
+
463
+ case "ChainExpression":
464
+ return isSameReference(
465
+ left.expression,
466
+ right.expression,
467
+ disableStaticComputedKey,
468
+ );
469
+
470
+ case "MemberExpression": {
471
+ if (!disableStaticComputedKey) {
472
+ const nameA = getStaticPropertyName(left);
473
+
474
+ // x.y = x["y"]
475
+ if (nameA !== null) {
476
+ return (
477
+ isSameReference(
478
+ left.object,
479
+ right.object,
480
+ disableStaticComputedKey,
481
+ ) && nameA === getStaticPropertyName(right)
482
+ );
483
+ }
484
+ }
485
+
486
+ /*
487
+ * x[0] = x[0]
488
+ * x[y] = x[y]
489
+ * x.y = x.y
490
+ */
491
+ return (
492
+ left.computed === right.computed &&
493
+ isSameReference(
494
+ left.object,
495
+ right.object,
496
+ disableStaticComputedKey,
497
+ ) &&
498
+ isSameReference(
499
+ left.property,
500
+ right.property,
501
+ disableStaticComputedKey,
502
+ )
503
+ );
504
+ }
505
+
506
+ default:
507
+ return false;
508
+ }
449
509
  }
450
510
 
451
511
  /**
@@ -454,7 +514,7 @@ function isSameReference(left, right, disableStaticComputedKey = false) {
454
514
  * @returns {boolean} Whether or not the node is a `Reflect.apply`.
455
515
  */
456
516
  function isReflectApply(node) {
457
- return isSpecificMemberAccess(node, "Reflect", "apply");
517
+ return isSpecificMemberAccess(node, "Reflect", "apply");
458
518
  }
459
519
 
460
520
  /**
@@ -463,7 +523,7 @@ function isReflectApply(node) {
463
523
  * @returns {boolean} Whether or not the node is a `Array.from`.
464
524
  */
465
525
  function isArrayFromMethod(node) {
466
- return isSpecificMemberAccess(node, arrayOrTypedArrayPattern, "from");
526
+ return isSpecificMemberAccess(node, arrayOrTypedArrayPattern, "from");
467
527
  }
468
528
 
469
529
  /**
@@ -472,7 +532,7 @@ function isArrayFromMethod(node) {
472
532
  * @returns {boolean} Whether or not the node is a method which expects a function as a first argument, and `thisArg` as a second argument.
473
533
  */
474
534
  function isMethodWhichHasThisArg(node) {
475
- return isSpecificMemberAccess(node, null, arrayMethodWithThisArgPattern);
535
+ return isSpecificMemberAccess(node, null, arrayMethodWithThisArgPattern);
476
536
  }
477
537
 
478
538
  /**
@@ -481,7 +541,7 @@ function isMethodWhichHasThisArg(node) {
481
541
  * @returns {Function} Negated function.
482
542
  */
483
543
  function negate(f) {
484
- return token => !f(token);
544
+ return token => !f(token);
485
545
  }
486
546
 
487
547
  /**
@@ -491,17 +551,19 @@ function negate(f) {
491
551
  * @returns {boolean} Whether or not the node has a `@this` tag in its comments.
492
552
  */
493
553
  function hasJSDocThisTag(node, sourceCode) {
494
- const jsdocComment = sourceCode.getJSDocComment(node);
495
-
496
- if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
497
- return true;
498
- }
499
-
500
- // Checks `@this` in its leading comments for callbacks,
501
- // because callbacks don't have its JSDoc comment.
502
- // e.g.
503
- // sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
504
- return sourceCode.getCommentsBefore(node).some(comment => thisTagPattern.test(comment.value));
554
+ const jsdocComment = sourceCode.getJSDocComment(node);
555
+
556
+ if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
557
+ return true;
558
+ }
559
+
560
+ // Checks `@this` in its leading comments for callbacks,
561
+ // because callbacks don't have its JSDoc comment.
562
+ // e.g.
563
+ // sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
564
+ return sourceCode
565
+ .getCommentsBefore(node)
566
+ .some(comment => thisTagPattern.test(comment.value));
505
567
  }
506
568
 
507
569
  /**
@@ -512,12 +574,16 @@ function hasJSDocThisTag(node, sourceCode) {
512
574
  * @private
513
575
  */
514
576
  function isParenthesised(sourceCode, node) {
515
- const previousToken = sourceCode.getTokenBefore(node),
516
- nextToken = sourceCode.getTokenAfter(node);
517
-
518
- return Boolean(previousToken && nextToken) &&
519
- previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
520
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
577
+ const previousToken = sourceCode.getTokenBefore(node),
578
+ nextToken = sourceCode.getTokenAfter(node);
579
+
580
+ return (
581
+ Boolean(previousToken && nextToken) &&
582
+ previousToken.value === "(" &&
583
+ previousToken.range[1] <= node.range[0] &&
584
+ nextToken.value === ")" &&
585
+ nextToken.range[0] >= node.range[1]
586
+ );
521
587
  }
522
588
 
523
589
  /**
@@ -526,7 +592,7 @@ function isParenthesised(sourceCode, node) {
526
592
  * @returns {boolean} `true` if the token is a `=` token.
527
593
  */
528
594
  function isEqToken(token) {
529
- return token.value === "=" && token.type === "Punctuator";
595
+ return token.value === "=" && token.type === "Punctuator";
530
596
  }
531
597
 
532
598
  /**
@@ -535,7 +601,7 @@ function isEqToken(token) {
535
601
  * @returns {boolean} `true` if the token is an arrow token.
536
602
  */
537
603
  function isArrowToken(token) {
538
- return token.value === "=>" && token.type === "Punctuator";
604
+ return token.value === "=>" && token.type === "Punctuator";
539
605
  }
540
606
 
541
607
  /**
@@ -544,7 +610,7 @@ function isArrowToken(token) {
544
610
  * @returns {boolean} `true` if the token is a comma token.
545
611
  */
546
612
  function isCommaToken(token) {
547
- return token.value === "," && token.type === "Punctuator";
613
+ return token.value === "," && token.type === "Punctuator";
548
614
  }
549
615
 
550
616
  /**
@@ -553,7 +619,7 @@ function isCommaToken(token) {
553
619
  * @returns {boolean} `true` if the token is a dot token.
554
620
  */
555
621
  function isDotToken(token) {
556
- return token.value === "." && token.type === "Punctuator";
622
+ return token.value === "." && token.type === "Punctuator";
557
623
  }
558
624
 
559
625
  /**
@@ -562,7 +628,7 @@ function isDotToken(token) {
562
628
  * @returns {boolean} `true` if the token is a `?.` token.
563
629
  */
564
630
  function isQuestionDotToken(token) {
565
- return token.value === "?." && token.type === "Punctuator";
631
+ return token.value === "?." && token.type === "Punctuator";
566
632
  }
567
633
 
568
634
  /**
@@ -571,7 +637,7 @@ function isQuestionDotToken(token) {
571
637
  * @returns {boolean} `true` if the token is a semicolon token.
572
638
  */
573
639
  function isSemicolonToken(token) {
574
- return token.value === ";" && token.type === "Punctuator";
640
+ return token.value === ";" && token.type === "Punctuator";
575
641
  }
576
642
 
577
643
  /**
@@ -580,7 +646,7 @@ function isSemicolonToken(token) {
580
646
  * @returns {boolean} `true` if the token is a colon token.
581
647
  */
582
648
  function isColonToken(token) {
583
- return token.value === ":" && token.type === "Punctuator";
649
+ return token.value === ":" && token.type === "Punctuator";
584
650
  }
585
651
 
586
652
  /**
@@ -589,7 +655,7 @@ function isColonToken(token) {
589
655
  * @returns {boolean} `true` if the token is an opening parenthesis token.
590
656
  */
591
657
  function isOpeningParenToken(token) {
592
- return token.value === "(" && token.type === "Punctuator";
658
+ return token.value === "(" && token.type === "Punctuator";
593
659
  }
594
660
 
595
661
  /**
@@ -598,7 +664,7 @@ function isOpeningParenToken(token) {
598
664
  * @returns {boolean} `true` if the token is a closing parenthesis token.
599
665
  */
600
666
  function isClosingParenToken(token) {
601
- return token.value === ")" && token.type === "Punctuator";
667
+ return token.value === ")" && token.type === "Punctuator";
602
668
  }
603
669
 
604
670
  /**
@@ -607,7 +673,7 @@ function isClosingParenToken(token) {
607
673
  * @returns {boolean} `true` if the token is an opening square bracket token.
608
674
  */
609
675
  function isOpeningBracketToken(token) {
610
- return token.value === "[" && token.type === "Punctuator";
676
+ return token.value === "[" && token.type === "Punctuator";
611
677
  }
612
678
 
613
679
  /**
@@ -616,7 +682,7 @@ function isOpeningBracketToken(token) {
616
682
  * @returns {boolean} `true` if the token is a closing square bracket token.
617
683
  */
618
684
  function isClosingBracketToken(token) {
619
- return token.value === "]" && token.type === "Punctuator";
685
+ return token.value === "]" && token.type === "Punctuator";
620
686
  }
621
687
 
622
688
  /**
@@ -625,7 +691,7 @@ function isClosingBracketToken(token) {
625
691
  * @returns {boolean} `true` if the token is an opening brace token.
626
692
  */
627
693
  function isOpeningBraceToken(token) {
628
- return token.value === "{" && token.type === "Punctuator";
694
+ return token.value === "{" && token.type === "Punctuator";
629
695
  }
630
696
 
631
697
  /**
@@ -634,7 +700,7 @@ function isOpeningBraceToken(token) {
634
700
  * @returns {boolean} `true` if the token is a closing brace token.
635
701
  */
636
702
  function isClosingBraceToken(token) {
637
- return token.value === "}" && token.type === "Punctuator";
703
+ return token.value === "}" && token.type === "Punctuator";
638
704
  }
639
705
 
640
706
  /**
@@ -643,7 +709,11 @@ function isClosingBraceToken(token) {
643
709
  * @returns {boolean} `true` if the token is a comment token.
644
710
  */
645
711
  function isCommentToken(token) {
646
- return token.type === "Line" || token.type === "Block" || token.type === "Shebang";
712
+ return (
713
+ token.type === "Line" ||
714
+ token.type === "Block" ||
715
+ token.type === "Shebang"
716
+ );
647
717
  }
648
718
 
649
719
  /**
@@ -652,7 +722,7 @@ function isCommentToken(token) {
652
722
  * @returns {boolean} `true` if the token is a keyword token.
653
723
  */
654
724
  function isKeywordToken(token) {
655
- return token.type === "Keyword";
725
+ return token.type === "Keyword";
656
726
  }
657
727
 
658
728
  /**
@@ -662,19 +732,20 @@ function isKeywordToken(token) {
662
732
  * @returns {Token} `(` token.
663
733
  */
664
734
  function getOpeningParenOfParams(node, sourceCode) {
665
-
666
- // If the node is an arrow function and doesn't have parens, this returns the identifier of the first param.
667
- if (node.type === "ArrowFunctionExpression" && node.params.length === 1) {
668
- const argToken = sourceCode.getFirstToken(node.params[0]);
669
- const maybeParenToken = sourceCode.getTokenBefore(argToken);
670
-
671
- return isOpeningParenToken(maybeParenToken) ? maybeParenToken : argToken;
672
- }
673
-
674
- // Otherwise, returns paren.
675
- return node.id
676
- ? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
677
- : sourceCode.getFirstToken(node, isOpeningParenToken);
735
+ // If the node is an arrow function and doesn't have parens, this returns the identifier of the first param.
736
+ if (node.type === "ArrowFunctionExpression" && node.params.length === 1) {
737
+ const argToken = sourceCode.getFirstToken(node.params[0]);
738
+ const maybeParenToken = sourceCode.getTokenBefore(argToken);
739
+
740
+ return isOpeningParenToken(maybeParenToken)
741
+ ? maybeParenToken
742
+ : argToken;
743
+ }
744
+
745
+ // Otherwise, returns paren.
746
+ return node.id
747
+ ? sourceCode.getTokenAfter(node.id, isOpeningParenToken)
748
+ : sourceCode.getFirstToken(node, isOpeningParenToken);
678
749
  }
679
750
 
680
751
  /**
@@ -685,21 +756,22 @@ function getOpeningParenOfParams(node, sourceCode) {
685
756
  * @returns {boolean} the source code for the given node.
686
757
  */
687
758
  function equalTokens(left, right, sourceCode) {
688
- const tokensL = sourceCode.getTokens(left);
689
- const tokensR = sourceCode.getTokens(right);
690
-
691
- if (tokensL.length !== tokensR.length) {
692
- return false;
693
- }
694
- for (let i = 0; i < tokensL.length; ++i) {
695
- if (tokensL[i].type !== tokensR[i].type ||
696
- tokensL[i].value !== tokensR[i].value
697
- ) {
698
- return false;
699
- }
700
- }
701
-
702
- return true;
759
+ const tokensL = sourceCode.getTokens(left);
760
+ const tokensR = sourceCode.getTokens(right);
761
+
762
+ if (tokensL.length !== tokensR.length) {
763
+ return false;
764
+ }
765
+ for (let i = 0; i < tokensL.length; ++i) {
766
+ if (
767
+ tokensL[i].type !== tokensR[i].type ||
768
+ tokensL[i].value !== tokensR[i].value
769
+ ) {
770
+ return false;
771
+ }
772
+ }
773
+
774
+ return true;
703
775
  }
704
776
 
705
777
  /**
@@ -715,10 +787,10 @@ function equalTokens(left, right, sourceCode) {
715
787
  * @see https://tc39.es/ecma262/#prod-ShortCircuitExpression
716
788
  */
717
789
  function isLogicalExpression(node) {
718
- return (
719
- node.type === "LogicalExpression" &&
720
- (node.operator === "&&" || node.operator === "||")
721
- );
790
+ return (
791
+ node.type === "LogicalExpression" &&
792
+ (node.operator === "&&" || node.operator === "||")
793
+ );
722
794
  }
723
795
 
724
796
  /**
@@ -733,7 +805,7 @@ function isLogicalExpression(node) {
733
805
  * @returns {boolean} `true` if the node is `??`.
734
806
  */
735
807
  function isCoalesceExpression(node) {
736
- return node.type === "LogicalExpression" && node.operator === "??";
808
+ return node.type === "LogicalExpression" && node.operator === "??";
737
809
  }
738
810
 
739
811
  /**
@@ -743,10 +815,10 @@ function isCoalesceExpression(node) {
743
815
  * @returns {boolean} `true` if the two nodes are the pair of a logical expression and a coalesce expression.
744
816
  */
745
817
  function isMixedLogicalAndCoalesceExpressions(left, right) {
746
- return (
747
- (isLogicalExpression(left) && isCoalesceExpression(right)) ||
748
- (isCoalesceExpression(left) && isLogicalExpression(right))
749
- );
818
+ return (
819
+ (isLogicalExpression(left) && isCoalesceExpression(right)) ||
820
+ (isCoalesceExpression(left) && isLogicalExpression(right))
821
+ );
750
822
  }
751
823
 
752
824
  /**
@@ -755,7 +827,7 @@ function isMixedLogicalAndCoalesceExpressions(left, right) {
755
827
  * @returns {boolean} `true` if the operator is a logical assignment operator.
756
828
  */
757
829
  function isLogicalAssignmentOperator(operator) {
758
- return LOGICAL_ASSIGNMENT_OPERATORS.has(operator);
830
+ return LOGICAL_ASSIGNMENT_OPERATORS.has(operator);
759
831
  }
760
832
 
761
833
  /**
@@ -765,10 +837,10 @@ function isLogicalAssignmentOperator(operator) {
765
837
  * @returns {Token} The colon token of the node.
766
838
  */
767
839
  function getSwitchCaseColonToken(node, sourceCode) {
768
- if (node.test) {
769
- return sourceCode.getTokenAfter(node.test, isColonToken);
770
- }
771
- return sourceCode.getFirstToken(node, 1);
840
+ if (node.test) {
841
+ return sourceCode.getTokenAfter(node.test, isColonToken);
842
+ }
843
+ return sourceCode.getFirstToken(node, 1);
772
844
  }
773
845
 
774
846
  /**
@@ -782,12 +854,12 @@ function getSwitchCaseColonToken(node, sourceCode) {
782
854
  * @returns {string} The module export name.
783
855
  */
784
856
  function getModuleExportName(node) {
785
- if (node.type === "Identifier") {
786
- return node.name;
787
- }
857
+ if (node.type === "Identifier") {
858
+ return node.name;
859
+ }
788
860
 
789
- // string literal
790
- return node.value;
861
+ // string literal
862
+ return node.value;
791
863
  }
792
864
 
793
865
  /**
@@ -797,27 +869,26 @@ function getModuleExportName(node) {
797
869
  * `null` when it cannot be determined.
798
870
  */
799
871
  function getBooleanValue(node) {
800
- if (node.value === null) {
801
-
802
- /*
803
- * it might be a null literal or bigint/regex literal in unsupported environments .
804
- * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es5.md#regexpliteral
805
- * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es2020.md#bigintliteral
806
- */
807
-
808
- if (node.raw === "null") {
809
- return false;
810
- }
811
-
812
- // regex is always truthy
813
- if (typeof node.regex === "object") {
814
- return true;
815
- }
816
-
817
- return null;
818
- }
819
-
820
- return !!node.value;
872
+ if (node.value === null) {
873
+ /*
874
+ * it might be a null literal or bigint/regex literal in unsupported environments .
875
+ * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es5.md#regexpliteral
876
+ * https://github.com/estree/estree/blob/14df8a024956ea289bd55b9c2226a1d5b8a473ee/es2020.md#bigintliteral
877
+ */
878
+
879
+ if (node.raw === "null") {
880
+ return false;
881
+ }
882
+
883
+ // regex is always truthy
884
+ if (typeof node.regex === "object") {
885
+ return true;
886
+ }
887
+
888
+ return null;
889
+ }
890
+
891
+ return !!node.value;
821
892
  }
822
893
 
823
894
  /**
@@ -827,34 +898,37 @@ function getBooleanValue(node) {
827
898
  * @returns {boolean} true when condition short circuits whole condition
828
899
  */
829
900
  function isLogicalIdentity(node, operator) {
830
- switch (node.type) {
831
- case "Literal":
832
- return (operator === "||" && getBooleanValue(node) === true) ||
833
- (operator === "&&" && getBooleanValue(node) === false);
834
-
835
- case "UnaryExpression":
836
- return (operator === "&&" && node.operator === "void");
837
-
838
- case "LogicalExpression":
839
-
840
- /*
841
- * handles `a && false || b`
842
- * `false` is an identity element of `&&` but not `||`
843
- */
844
- return operator === node.operator &&
845
- (
846
- isLogicalIdentity(node.left, operator) ||
847
- isLogicalIdentity(node.right, operator)
848
- );
849
-
850
- case "AssignmentExpression":
851
- return ["||=", "&&="].includes(node.operator) &&
852
- operator === node.operator.slice(0, -1) &&
853
- isLogicalIdentity(node.right, operator);
854
-
855
- // no default
856
- }
857
- return false;
901
+ switch (node.type) {
902
+ case "Literal":
903
+ return (
904
+ (operator === "||" && getBooleanValue(node) === true) ||
905
+ (operator === "&&" && getBooleanValue(node) === false)
906
+ );
907
+
908
+ case "UnaryExpression":
909
+ return operator === "&&" && node.operator === "void";
910
+
911
+ case "LogicalExpression":
912
+ /*
913
+ * handles `a && false || b`
914
+ * `false` is an identity element of `&&` but not `||`
915
+ */
916
+ return (
917
+ operator === node.operator &&
918
+ (isLogicalIdentity(node.left, operator) ||
919
+ isLogicalIdentity(node.right, operator))
920
+ );
921
+
922
+ case "AssignmentExpression":
923
+ return (
924
+ ["||=", "&&="].includes(node.operator) &&
925
+ operator === node.operator.slice(0, -1) &&
926
+ isLogicalIdentity(node.right, operator)
927
+ );
928
+
929
+ // no default
930
+ }
931
+ return false;
858
932
  }
859
933
 
860
934
  /**
@@ -864,17 +938,16 @@ function isLogicalIdentity(node, operator) {
864
938
  * @returns {boolean} `true` if the identifier is a reference to a global variable.
865
939
  */
866
940
  function isReferenceToGlobalVariable(scope, node) {
867
- const reference = scope.references.find(ref => ref.identifier === node);
868
-
869
- return Boolean(
870
- reference &&
871
- reference.resolved &&
872
- reference.resolved.scope.type === "global" &&
873
- reference.resolved.defs.length === 0
874
- );
941
+ const reference = scope.references.find(ref => ref.identifier === node);
942
+
943
+ return Boolean(
944
+ reference &&
945
+ reference.resolved &&
946
+ reference.resolved.scope.type === "global" &&
947
+ reference.resolved.defs.length === 0,
948
+ );
875
949
  }
876
950
 
877
-
878
951
  /**
879
952
  * Checks if a node has a constant truthiness value.
880
953
  * @param {Scope} scope Scope in which the node appears.
@@ -887,123 +960,161 @@ function isReferenceToGlobalVariable(scope, node) {
887
960
  * @private
888
961
  */
889
962
  function isConstant(scope, node, inBooleanPosition) {
890
-
891
- // node.elements can return null values in the case of sparse arrays ex. [,]
892
- if (!node) {
893
- return true;
894
- }
895
- switch (node.type) {
896
- case "Literal":
897
- case "ArrowFunctionExpression":
898
- case "FunctionExpression":
899
- return true;
900
- case "ClassExpression":
901
- case "ObjectExpression":
902
-
903
- /**
904
- * In theory objects like:
905
- *
906
- * `{toString: () => a}`
907
- * `{valueOf: () => a}`
908
- *
909
- * Or a classes like:
910
- *
911
- * `class { static toString() { return a } }`
912
- * `class { static valueOf() { return a } }`
913
- *
914
- * Are not constant verifiably when `inBooleanPosition` is
915
- * false, but it's an edge case we've opted not to handle.
916
- */
917
- return true;
918
- case "TemplateLiteral":
919
- return (inBooleanPosition && node.quasis.some(quasi => quasi.value.cooked.length)) ||
920
- node.expressions.every(exp => isConstant(scope, exp, false));
921
-
922
- case "ArrayExpression": {
923
- if (!inBooleanPosition) {
924
- return node.elements.every(element => isConstant(scope, element, false));
925
- }
926
- return true;
927
- }
928
-
929
- case "UnaryExpression":
930
- if (
931
- node.operator === "void" ||
932
- node.operator === "typeof" && inBooleanPosition
933
- ) {
934
- return true;
935
- }
936
-
937
- if (node.operator === "!") {
938
- return isConstant(scope, node.argument, true);
939
- }
940
-
941
- return isConstant(scope, node.argument, false);
942
-
943
- case "BinaryExpression":
944
- return isConstant(scope, node.left, false) &&
945
- isConstant(scope, node.right, false) &&
946
- node.operator !== "in";
947
-
948
- case "LogicalExpression": {
949
- const isLeftConstant = isConstant(scope, node.left, inBooleanPosition);
950
- const isRightConstant = isConstant(scope, node.right, inBooleanPosition);
951
- const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator));
952
- const isRightShortCircuit = (inBooleanPosition && isRightConstant && isLogicalIdentity(node.right, node.operator));
953
-
954
- return (isLeftConstant && isRightConstant) ||
955
- isLeftShortCircuit ||
956
- isRightShortCircuit;
957
- }
958
- case "NewExpression":
959
- return inBooleanPosition;
960
- case "AssignmentExpression":
961
- if (node.operator === "=") {
962
- return isConstant(scope, node.right, inBooleanPosition);
963
- }
964
-
965
- if (["||=", "&&="].includes(node.operator) && inBooleanPosition) {
966
- return isLogicalIdentity(node.right, node.operator.slice(0, -1));
967
- }
968
-
969
- return false;
970
-
971
- case "SequenceExpression":
972
- return isConstant(scope, node.expressions[node.expressions.length - 1], inBooleanPosition);
973
- case "SpreadElement":
974
- return isConstant(scope, node.argument, inBooleanPosition);
975
- case "CallExpression":
976
- if (node.callee.type === "Identifier" && node.callee.name === "Boolean") {
977
- if (node.arguments.length === 0 || isConstant(scope, node.arguments[0], true)) {
978
- return isReferenceToGlobalVariable(scope, node.callee);
979
- }
980
- }
981
- return false;
982
- case "Identifier":
983
- return node.name === "undefined" && isReferenceToGlobalVariable(scope, node);
984
-
985
- // no default
986
- }
987
- return false;
963
+ // node.elements can return null values in the case of sparse arrays ex. [,]
964
+ if (!node) {
965
+ return true;
966
+ }
967
+ switch (node.type) {
968
+ case "Literal":
969
+ case "ArrowFunctionExpression":
970
+ case "FunctionExpression":
971
+ return true;
972
+ case "ClassExpression":
973
+ case "ObjectExpression":
974
+ /**
975
+ * In theory objects like:
976
+ *
977
+ * `{toString: () => a}`
978
+ * `{valueOf: () => a}`
979
+ *
980
+ * Or a classes like:
981
+ *
982
+ * `class { static toString() { return a } }`
983
+ * `class { static valueOf() { return a } }`
984
+ *
985
+ * Are not constant verifiably when `inBooleanPosition` is
986
+ * false, but it's an edge case we've opted not to handle.
987
+ */
988
+ return true;
989
+ case "TemplateLiteral":
990
+ return (
991
+ (inBooleanPosition &&
992
+ node.quasis.some(quasi => quasi.value.cooked.length)) ||
993
+ node.expressions.every(exp => isConstant(scope, exp, false))
994
+ );
995
+
996
+ case "ArrayExpression": {
997
+ if (!inBooleanPosition) {
998
+ return node.elements.every(element =>
999
+ isConstant(scope, element, false),
1000
+ );
1001
+ }
1002
+ return true;
1003
+ }
1004
+
1005
+ case "UnaryExpression":
1006
+ if (
1007
+ node.operator === "void" ||
1008
+ (node.operator === "typeof" && inBooleanPosition)
1009
+ ) {
1010
+ return true;
1011
+ }
1012
+
1013
+ if (node.operator === "!") {
1014
+ return isConstant(scope, node.argument, true);
1015
+ }
1016
+
1017
+ return isConstant(scope, node.argument, false);
1018
+
1019
+ case "BinaryExpression":
1020
+ return (
1021
+ isConstant(scope, node.left, false) &&
1022
+ isConstant(scope, node.right, false) &&
1023
+ node.operator !== "in"
1024
+ );
1025
+
1026
+ case "LogicalExpression": {
1027
+ const isLeftConstant = isConstant(
1028
+ scope,
1029
+ node.left,
1030
+ inBooleanPosition,
1031
+ );
1032
+ const isRightConstant = isConstant(
1033
+ scope,
1034
+ node.right,
1035
+ inBooleanPosition,
1036
+ );
1037
+ const isLeftShortCircuit =
1038
+ isLeftConstant && isLogicalIdentity(node.left, node.operator);
1039
+ const isRightShortCircuit =
1040
+ inBooleanPosition &&
1041
+ isRightConstant &&
1042
+ isLogicalIdentity(node.right, node.operator);
1043
+
1044
+ return (
1045
+ (isLeftConstant && isRightConstant) ||
1046
+ isLeftShortCircuit ||
1047
+ isRightShortCircuit
1048
+ );
1049
+ }
1050
+ case "NewExpression":
1051
+ return inBooleanPosition;
1052
+ case "AssignmentExpression":
1053
+ if (node.operator === "=") {
1054
+ return isConstant(scope, node.right, inBooleanPosition);
1055
+ }
1056
+
1057
+ if (["||=", "&&="].includes(node.operator) && inBooleanPosition) {
1058
+ return isLogicalIdentity(
1059
+ node.right,
1060
+ node.operator.slice(0, -1),
1061
+ );
1062
+ }
1063
+
1064
+ return false;
1065
+
1066
+ case "SequenceExpression":
1067
+ return isConstant(
1068
+ scope,
1069
+ node.expressions.at(-1),
1070
+ inBooleanPosition,
1071
+ );
1072
+ case "SpreadElement":
1073
+ return isConstant(scope, node.argument, inBooleanPosition);
1074
+ case "CallExpression":
1075
+ if (
1076
+ node.callee.type === "Identifier" &&
1077
+ node.callee.name === "Boolean"
1078
+ ) {
1079
+ if (
1080
+ node.arguments.length === 0 ||
1081
+ isConstant(scope, node.arguments[0], true)
1082
+ ) {
1083
+ return isReferenceToGlobalVariable(scope, node.callee);
1084
+ }
1085
+ }
1086
+ return false;
1087
+ case "Identifier":
1088
+ return (
1089
+ node.name === "undefined" &&
1090
+ isReferenceToGlobalVariable(scope, node)
1091
+ );
1092
+
1093
+ // no default
1094
+ }
1095
+ return false;
988
1096
  }
989
1097
 
990
1098
  /**
991
- * Checks whether a node is an ExpressionStatement at the top level of a file or function body.
1099
+ * Checks whether a node is an ExpressionStatement at the top level of a file, function body, or TypeScript module block.
992
1100
  * A top-level ExpressionStatement node is a directive if it contains a single unparenthesized
993
1101
  * string literal and if it occurs either as the first sibling or immediately after another
994
1102
  * directive.
995
1103
  * @param {ASTNode} node The node to check.
996
1104
  * @returns {boolean} Whether or not the node is an ExpressionStatement at the top level of a
997
- * file or function body.
1105
+ * file, function body, or TypeScript module block.
998
1106
  */
999
1107
  function isTopLevelExpressionStatement(node) {
1000
- if (node.type !== "ExpressionStatement") {
1001
- return false;
1002
- }
1003
- const parent = node.parent;
1004
-
1005
- return parent.type === "Program" || (parent.type === "BlockStatement" && isFunction(parent.parent));
1006
-
1108
+ if (node.type !== "ExpressionStatement") {
1109
+ return false;
1110
+ }
1111
+ const parent = node.parent;
1112
+
1113
+ return (
1114
+ parent.type === "Program" ||
1115
+ parent.type === "TSModuleBlock" ||
1116
+ (parent.type === "BlockStatement" && isFunction(parent.parent))
1117
+ );
1007
1118
  }
1008
1119
 
1009
1120
  /**
@@ -1012,7 +1123,10 @@ function isTopLevelExpressionStatement(node) {
1012
1123
  * @returns {boolean} `true` if the node is a part of directive prologue.
1013
1124
  */
1014
1125
  function isDirective(node) {
1015
- return node.type === "ExpressionStatement" && typeof node.directive === "string";
1126
+ return (
1127
+ node.type === "ExpressionStatement" &&
1128
+ typeof node.directive === "string"
1129
+ );
1016
1130
  }
1017
1131
 
1018
1132
  /**
@@ -1021,106 +1135,205 @@ function isDirective(node) {
1021
1135
  * @returns {boolean} Whether the node appears at the beginning of an ancestor ExpressionStatement node.
1022
1136
  */
1023
1137
  function isStartOfExpressionStatement(node) {
1024
- const start = node.range[0];
1025
- let ancestor = node;
1026
-
1027
- while ((ancestor = ancestor.parent) && ancestor.range[0] === start) {
1028
- if (ancestor.type === "ExpressionStatement") {
1029
- return true;
1030
- }
1031
- }
1032
- return false;
1138
+ const start = node.range[0];
1139
+ let ancestor = node;
1140
+
1141
+ while ((ancestor = ancestor.parent) && ancestor.range[0] === start) {
1142
+ if (ancestor.type === "ExpressionStatement") {
1143
+ return true;
1144
+ }
1145
+ }
1146
+ return false;
1033
1147
  }
1034
1148
 
1035
1149
  /**
1036
1150
  * Determines whether an opening parenthesis `(`, bracket `[` or backtick ``` ` ``` needs to be preceded by a semicolon.
1037
- * This opening parenthesis or bracket should be at the start of an `ExpressionStatement` or at the start of the body of an `ArrowFunctionExpression`.
1151
+ * This opening parenthesis or bracket should be at the start of an `ExpressionStatement`, a `MethodDefinition` or at
1152
+ * the start of the body of an `ArrowFunctionExpression`.
1038
1153
  * @type {(sourceCode: SourceCode, node: ASTNode) => boolean}
1039
1154
  * @param {SourceCode} sourceCode The source code object.
1040
1155
  * @param {ASTNode} node A node at the position where an opening parenthesis or bracket will be inserted.
1041
- * @returns {boolean} Whether a semicolon is required before the opening parenthesis or braket.
1156
+ * @returns {boolean} Whether a semicolon is required before the opening parenthesis or bracket.
1042
1157
  */
1043
1158
  let needsPrecedingSemicolon;
1044
1159
 
1045
1160
  {
1046
- const BREAK_OR_CONTINUE = new Set(["BreakStatement", "ContinueStatement"]);
1047
-
1048
- // Declaration types that must contain a string Literal node at the end.
1049
- const DECLARATIONS = new Set(["ExportAllDeclaration", "ExportNamedDeclaration", "ImportDeclaration"]);
1050
-
1051
- const IDENTIFIER_OR_KEYWORD = new Set(["Identifier", "Keyword"]);
1052
-
1053
- // Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types.
1054
- const NODE_TYPES_BY_KEYWORD = {
1055
- __proto__: null,
1056
- break: "BreakStatement",
1057
- continue: "ContinueStatement",
1058
- debugger: "DebuggerStatement",
1059
- do: "DoWhileStatement",
1060
- else: "IfStatement",
1061
- return: "ReturnStatement",
1062
- yield: "YieldExpression"
1063
- };
1064
-
1065
- /*
1066
- * Before an opening parenthesis, postfix `++` and `--` always trigger ASI;
1067
- * the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement.
1068
- */
1069
- const PUNCTUATORS = new Set([":", ";", "{", "=>", "++", "--"]);
1070
-
1071
- /*
1072
- * Statements that can contain an `ExpressionStatement` after a closing parenthesis.
1073
- * DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis.
1074
- */
1075
- const STATEMENTS = new Set([
1076
- "DoWhileStatement",
1077
- "ForInStatement",
1078
- "ForOfStatement",
1079
- "ForStatement",
1080
- "IfStatement",
1081
- "WhileStatement",
1082
- "WithStatement"
1083
- ]);
1084
-
1085
- needsPrecedingSemicolon =
1086
- function(sourceCode, node) {
1087
- const prevToken = sourceCode.getTokenBefore(node);
1088
-
1089
- if (!prevToken || prevToken.type === "Punctuator" && PUNCTUATORS.has(prevToken.value)) {
1090
- return false;
1091
- }
1092
-
1093
- const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]);
1094
-
1095
- if (isClosingParenToken(prevToken)) {
1096
- return !STATEMENTS.has(prevNode.type);
1097
- }
1098
-
1099
- if (isClosingBraceToken(prevToken)) {
1100
- return (
1101
- prevNode.type === "BlockStatement" && prevNode.parent.type === "FunctionExpression" ||
1102
- prevNode.type === "ClassBody" && prevNode.parent.type === "ClassExpression" ||
1103
- prevNode.type === "ObjectExpression"
1104
- );
1105
- }
1106
-
1107
- if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) {
1108
- if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) {
1109
- return false;
1110
- }
1111
-
1112
- const keyword = prevToken.value;
1113
- const nodeType = NODE_TYPES_BY_KEYWORD[keyword];
1114
-
1115
- return prevNode.type !== nodeType;
1116
- }
1117
-
1118
- if (prevToken.type === "String") {
1119
- return !DECLARATIONS.has(prevNode.parent.type);
1120
- }
1121
-
1122
- return true;
1123
- };
1161
+ const BREAK_OR_CONTINUE = new Set(["BreakStatement", "ContinueStatement"]);
1162
+
1163
+ // Declaration types that cannot be continued by a punctuator when ending with a string Literal that is a direct child.
1164
+ const DECLARATIONS = new Set([
1165
+ "ExportAllDeclaration",
1166
+ "ExportNamedDeclaration",
1167
+ "ImportDeclaration",
1168
+ ]);
1169
+
1170
+ const IDENTIFIER_OR_KEYWORD = new Set(["Identifier", "Keyword"]);
1171
+
1172
+ // Keywords that can immediately precede an ExpressionStatement node, mapped to the their node types.
1173
+ const NODE_TYPES_BY_KEYWORD = {
1174
+ __proto__: null,
1175
+ break: "BreakStatement",
1176
+ continue: "ContinueStatement",
1177
+ debugger: "DebuggerStatement",
1178
+ do: "DoWhileStatement",
1179
+ else: "IfStatement",
1180
+ return: "ReturnStatement",
1181
+ yield: "YieldExpression",
1182
+ };
1183
+
1184
+ /*
1185
+ * Before an opening parenthesis, postfix `++` and `--` always trigger ASI;
1186
+ * the tokens `:`, `;`, `{` and `=>` don't expect a semicolon, as that would count as an empty statement.
1187
+ */
1188
+ const PUNCTUATORS = new Set([":", ";", "{", "=>", "++", "--"]);
1189
+
1190
+ /*
1191
+ * Statements that can contain an `ExpressionStatement` after a closing parenthesis.
1192
+ * DoWhileStatement is an exception in that it always triggers ASI after the closing parenthesis.
1193
+ */
1194
+ const STATEMENTS = new Set([
1195
+ "DoWhileStatement",
1196
+ "ForInStatement",
1197
+ "ForOfStatement",
1198
+ "ForStatement",
1199
+ "IfStatement",
1200
+ "WhileStatement",
1201
+ "WithStatement",
1202
+ ]);
1203
+
1204
+ const TS_TYPE_NODE_TYPES = new Set([
1205
+ "TSAsExpression",
1206
+ "TSSatisfiesExpression",
1207
+ "TSTypeAliasDeclaration",
1208
+ "TSTypeAnnotation",
1209
+ ]);
1210
+
1211
+ /**
1212
+ * Determines whether a specified node is inside a TypeScript type context.
1213
+ * @param {ASTNode} node The node to check.
1214
+ * @returns {boolean} Whether the node is inside a TypeScript type context.
1215
+ */
1216
+ function isInType(node) {
1217
+ for (let currNode = node; ; ) {
1218
+ const { parent } = currNode;
1219
+ if (!parent) {
1220
+ break;
1221
+ }
1222
+ if (
1223
+ TS_TYPE_NODE_TYPES.has(parent.type) &&
1224
+ currNode === parent.typeAnnotation
1225
+ ) {
1226
+ return true;
1227
+ }
1228
+ currNode = parent;
1229
+ }
1230
+ return false;
1231
+ }
1232
+
1233
+ needsPrecedingSemicolon = function (sourceCode, node) {
1234
+ const prevToken = sourceCode.getTokenBefore(node);
1235
+
1236
+ if (
1237
+ !prevToken ||
1238
+ (prevToken.type === "Punctuator" &&
1239
+ PUNCTUATORS.has(prevToken.value))
1240
+ ) {
1241
+ return false;
1242
+ }
1243
+
1244
+ const prevNode = sourceCode.getNodeByRangeIndex(prevToken.range[0]);
1245
+
1246
+ if (
1247
+ prevNode.type === "TSDeclareFunction" ||
1248
+ prevNode.parent.type === "TSImportEqualsDeclaration" ||
1249
+ prevNode.parent.parent?.type === "TSImportEqualsDeclaration" ||
1250
+ TS_TYPE_NODE_TYPES.has(prevNode.type) ||
1251
+ isInType(prevNode)
1252
+ ) {
1253
+ return false;
1254
+ }
1255
+
1256
+ if (isClosingParenToken(prevToken)) {
1257
+ return !STATEMENTS.has(prevNode.type);
1258
+ }
1259
+
1260
+ if (isClosingBraceToken(prevToken)) {
1261
+ return (
1262
+ (prevNode.type === "BlockStatement" &&
1263
+ prevNode.parent.type === "FunctionExpression" &&
1264
+ prevNode.parent.parent.type !== "MethodDefinition") ||
1265
+ (prevNode.type === "ClassBody" &&
1266
+ prevNode.parent.type === "ClassExpression") ||
1267
+ prevNode.type === "ObjectExpression"
1268
+ );
1269
+ }
1270
+
1271
+ if (IDENTIFIER_OR_KEYWORD.has(prevToken.type)) {
1272
+ if (
1273
+ prevNode.parent.type === "VariableDeclarator" &&
1274
+ !prevNode.parent.init
1275
+ ) {
1276
+ return false;
1277
+ }
1278
+ if (BREAK_OR_CONTINUE.has(prevNode.parent.type)) {
1279
+ return false;
1280
+ }
1281
+
1282
+ const keyword = prevToken.value;
1283
+ const nodeType = NODE_TYPES_BY_KEYWORD[keyword];
1284
+
1285
+ return prevNode.type !== nodeType;
1286
+ }
1287
+
1288
+ if (prevToken.type === "String") {
1289
+ return !DECLARATIONS.has(prevNode.parent.type);
1290
+ }
1291
+
1292
+ return true;
1293
+ };
1294
+ }
1295
+
1296
+ /**
1297
+ * Checks if a node is used as an import attribute key, either in a static or dynamic import.
1298
+ * @param {ASTNode} node The node to check.
1299
+ * @returns {boolean} Whether the node is used as an import attribute key.
1300
+ */
1301
+ function isImportAttributeKey(node) {
1302
+ const { parent } = node;
1303
+
1304
+ // static import/re-export
1305
+ if (parent.type === "ImportAttribute" && parent.key === node) {
1306
+ return true;
1307
+ }
1308
+
1309
+ // dynamic import
1310
+ if (
1311
+ parent.type === "Property" &&
1312
+ !parent.computed &&
1313
+ (parent.key === node ||
1314
+ (parent.value === node && parent.shorthand && !parent.method)) &&
1315
+ parent.parent.type === "ObjectExpression"
1316
+ ) {
1317
+ const objectExpression = parent.parent;
1318
+ const objectExpressionParent = objectExpression.parent;
1319
+
1320
+ if (
1321
+ objectExpressionParent.type === "ImportExpression" &&
1322
+ objectExpressionParent.options === objectExpression
1323
+ ) {
1324
+ return true;
1325
+ }
1326
+
1327
+ // nested key
1328
+ if (
1329
+ objectExpressionParent.type === "Property" &&
1330
+ objectExpressionParent.value === objectExpression
1331
+ ) {
1332
+ return isImportAttributeKey(objectExpressionParent.key);
1333
+ }
1334
+ }
1335
+
1336
+ return false;
1124
1337
  }
1125
1338
 
1126
1339
  //------------------------------------------------------------------------------
@@ -1128,1155 +1341,1393 @@ let needsPrecedingSemicolon;
1128
1341
  //------------------------------------------------------------------------------
1129
1342
 
1130
1343
  module.exports = {
1131
- COMMENTS_IGNORE_PATTERN,
1132
- LINEBREAKS,
1133
- LINEBREAK_MATCHER: lineBreakPattern,
1134
- SHEBANG_MATCHER: shebangPattern,
1135
- STATEMENT_LIST_PARENTS,
1136
-
1137
- /**
1138
- * Determines whether two adjacent tokens are on the same line.
1139
- * @param {Object} left The left token object.
1140
- * @param {Object} right The right token object.
1141
- * @returns {boolean} Whether or not the tokens are on the same line.
1142
- * @public
1143
- */
1144
- isTokenOnSameLine(left, right) {
1145
- return left.loc.end.line === right.loc.start.line;
1146
- },
1147
-
1148
- isNullOrUndefined,
1149
- isCallee,
1150
- isES5Constructor,
1151
- getUpperFunction,
1152
- isFunction,
1153
- isLoop,
1154
- isInLoop,
1155
- isArrayFromMethod,
1156
- isParenthesised,
1157
- createGlobalLinebreakMatcher,
1158
- equalTokens,
1159
-
1160
- isArrowToken,
1161
- isClosingBraceToken,
1162
- isClosingBracketToken,
1163
- isClosingParenToken,
1164
- isColonToken,
1165
- isCommaToken,
1166
- isCommentToken,
1167
- isDotToken,
1168
- isQuestionDotToken,
1169
- isKeywordToken,
1170
- isNotClosingBraceToken: negate(isClosingBraceToken),
1171
- isNotClosingBracketToken: negate(isClosingBracketToken),
1172
- isNotClosingParenToken: negate(isClosingParenToken),
1173
- isNotColonToken: negate(isColonToken),
1174
- isNotCommaToken: negate(isCommaToken),
1175
- isNotDotToken: negate(isDotToken),
1176
- isNotQuestionDotToken: negate(isQuestionDotToken),
1177
- isNotOpeningBraceToken: negate(isOpeningBraceToken),
1178
- isNotOpeningBracketToken: negate(isOpeningBracketToken),
1179
- isNotOpeningParenToken: negate(isOpeningParenToken),
1180
- isNotSemicolonToken: negate(isSemicolonToken),
1181
- isOpeningBraceToken,
1182
- isOpeningBracketToken,
1183
- isOpeningParenToken,
1184
- isSemicolonToken,
1185
- isEqToken,
1186
-
1187
- /**
1188
- * Checks whether or not a given node is a string literal.
1189
- * @param {ASTNode} node A node to check.
1190
- * @returns {boolean} `true` if the node is a string literal.
1191
- */
1192
- isStringLiteral(node) {
1193
- return (
1194
- (node.type === "Literal" && typeof node.value === "string") ||
1195
- node.type === "TemplateLiteral"
1196
- );
1197
- },
1198
-
1199
- /**
1200
- * Checks whether a given node is a breakable statement or not.
1201
- * The node is breakable if the node is one of the following type:
1202
- *
1203
- * - DoWhileStatement
1204
- * - ForInStatement
1205
- * - ForOfStatement
1206
- * - ForStatement
1207
- * - SwitchStatement
1208
- * - WhileStatement
1209
- * @param {ASTNode} node A node to check.
1210
- * @returns {boolean} `true` if the node is breakable.
1211
- */
1212
- isBreakableStatement(node) {
1213
- return breakableTypePattern.test(node.type);
1214
- },
1215
-
1216
- /**
1217
- * Gets references which are non initializer and writable.
1218
- * @param {Reference[]} references An array of references.
1219
- * @returns {Reference[]} An array of only references which are non initializer and writable.
1220
- * @public
1221
- */
1222
- getModifyingReferences(references) {
1223
- return references.filter(isModifyingReference);
1224
- },
1225
-
1226
- /**
1227
- * Validate that a string passed in is surrounded by the specified character
1228
- * @param {string} val The text to check.
1229
- * @param {string} character The character to see if it's surrounded by.
1230
- * @returns {boolean} True if the text is surrounded by the character, false if not.
1231
- * @private
1232
- */
1233
- isSurroundedBy(val, character) {
1234
- return val[0] === character && val[val.length - 1] === character;
1235
- },
1236
-
1237
- /**
1238
- * Returns whether the provided node is an ESLint directive comment or not
1239
- * @param {Line|Block} node The comment token to be checked
1240
- * @returns {boolean} `true` if the node is an ESLint directive comment
1241
- */
1242
- isDirectiveComment(node) {
1243
- const comment = node.value.trim();
1244
-
1245
- return (
1246
- node.type === "Line" && comment.startsWith("eslint-") ||
1247
- node.type === "Block" && ESLINT_DIRECTIVE_PATTERN.test(comment)
1248
- );
1249
- },
1250
-
1251
- /**
1252
- * Gets the trailing statement of a given node.
1253
- *
1254
- * if (code)
1255
- * consequent;
1256
- *
1257
- * When taking this `IfStatement`, returns `consequent;` statement.
1258
- * @param {ASTNode} A node to get.
1259
- * @returns {ASTNode|null} The trailing statement's node.
1260
- */
1261
- getTrailingStatement: esutils.ast.trailingStatement,
1262
-
1263
- /**
1264
- * Finds the variable by a given name in a given scope and its upper scopes.
1265
- * @param {eslint-scope.Scope} initScope A scope to start find.
1266
- * @param {string} name A variable name to find.
1267
- * @returns {eslint-scope.Variable|null} A found variable or `null`.
1268
- */
1269
- getVariableByName(initScope, name) {
1270
- let scope = initScope;
1271
-
1272
- while (scope) {
1273
- const variable = scope.set.get(name);
1274
-
1275
- if (variable) {
1276
- return variable;
1277
- }
1278
-
1279
- scope = scope.upper;
1280
- }
1281
-
1282
- return null;
1283
- },
1284
-
1285
- /**
1286
- * Checks whether or not a given function node is the default `this` binding.
1287
- *
1288
- * First, this checks the node:
1289
- *
1290
- * - The given node is not in `PropertyDefinition#value` position.
1291
- * - The given node is not `StaticBlock`.
1292
- * - The function name does not start with uppercase. It's a convention to capitalize the names
1293
- * of constructor functions. This check is not performed if `capIsConstructor` is set to `false`.
1294
- * - The function does not have a JSDoc comment that has a @this tag.
1295
- *
1296
- * Next, this checks the location of the node.
1297
- * If the location is below, this judges `this` is valid.
1298
- *
1299
- * - The location is not on an object literal.
1300
- * - The location is not assigned to a variable which starts with an uppercase letter. Applies to anonymous
1301
- * functions only, as the name of the variable is considered to be the name of the function in this case.
1302
- * This check is not performed if `capIsConstructor` is set to `false`.
1303
- * - The location is not on an ES2015 class.
1304
- * - Its `bind`/`call`/`apply` method is not called directly.
1305
- * - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
1306
- * @param {ASTNode} node A function node to check. It also can be an implicit function, like `StaticBlock`
1307
- * or any expression that is `PropertyDefinition#value` node.
1308
- * @param {SourceCode} sourceCode A SourceCode instance to get comments.
1309
- * @param {boolean} [capIsConstructor = true] `false` disables the assumption that functions which name starts
1310
- * with an uppercase or are assigned to a variable which name starts with an uppercase are constructors.
1311
- * @returns {boolean} The function node is the default `this` binding.
1312
- */
1313
- isDefaultThisBinding(node, sourceCode, { capIsConstructor = true } = {}) {
1314
-
1315
- /*
1316
- * Class field initializers are implicit functions, but ESTree doesn't have the AST node of field initializers.
1317
- * Therefore, A expression node at `PropertyDefinition#value` is a function.
1318
- * In this case, `this` is always not default binding.
1319
- */
1320
- if (node.parent.type === "PropertyDefinition" && node.parent.value === node) {
1321
- return false;
1322
- }
1323
-
1324
- // Class static blocks are implicit functions. In this case, `this` is always not default binding.
1325
- if (node.type === "StaticBlock") {
1326
- return false;
1327
- }
1328
-
1329
- if (
1330
- (capIsConstructor && isES5Constructor(node)) ||
1331
- hasJSDocThisTag(node, sourceCode)
1332
- ) {
1333
- return false;
1334
- }
1335
- const isAnonymous = node.id === null;
1336
- let currentNode = node;
1337
-
1338
- while (currentNode) {
1339
- const parent = currentNode.parent;
1340
-
1341
- switch (parent.type) {
1342
-
1343
- /*
1344
- * Looks up the destination.
1345
- * e.g., obj.foo = nativeFoo || function foo() { ... };
1346
- */
1347
- case "LogicalExpression":
1348
- case "ConditionalExpression":
1349
- case "ChainExpression":
1350
- currentNode = parent;
1351
- break;
1352
-
1353
- /*
1354
- * If the upper function is IIFE, checks the destination of the return value.
1355
- * e.g.
1356
- * obj.foo = (function() {
1357
- * // setup...
1358
- * return function foo() { ... };
1359
- * })();
1360
- * obj.foo = (() =>
1361
- * function foo() { ... }
1362
- * )();
1363
- */
1364
- case "ReturnStatement": {
1365
- const func = getUpperFunction(parent);
1366
-
1367
- if (func === null || !isCallee(func)) {
1368
- return true;
1369
- }
1370
- currentNode = func.parent;
1371
- break;
1372
- }
1373
- case "ArrowFunctionExpression":
1374
- if (currentNode !== parent.body || !isCallee(parent)) {
1375
- return true;
1376
- }
1377
- currentNode = parent.parent;
1378
- break;
1379
-
1380
- /*
1381
- * e.g.
1382
- * var obj = { foo() { ... } };
1383
- * var obj = { foo: function() { ... } };
1384
- * class A { constructor() { ... } }
1385
- * class A { foo() { ... } }
1386
- * class A { get foo() { ... } }
1387
- * class A { set foo() { ... } }
1388
- * class A { static foo() { ... } }
1389
- * class A { foo = function() { ... } }
1390
- */
1391
- case "Property":
1392
- case "PropertyDefinition":
1393
- case "MethodDefinition":
1394
- return parent.value !== currentNode;
1395
-
1396
- /*
1397
- * e.g.
1398
- * obj.foo = function foo() { ... };
1399
- * Foo = function() { ... };
1400
- * [obj.foo = function foo() { ... }] = a;
1401
- * [Foo = function() { ... }] = a;
1402
- */
1403
- case "AssignmentExpression":
1404
- case "AssignmentPattern":
1405
- if (parent.left.type === "MemberExpression") {
1406
- return false;
1407
- }
1408
- if (
1409
- capIsConstructor &&
1410
- isAnonymous &&
1411
- parent.left.type === "Identifier" &&
1412
- startsWithUpperCase(parent.left.name)
1413
- ) {
1414
- return false;
1415
- }
1416
- return true;
1417
-
1418
- /*
1419
- * e.g.
1420
- * var Foo = function() { ... };
1421
- */
1422
- case "VariableDeclarator":
1423
- return !(
1424
- capIsConstructor &&
1425
- isAnonymous &&
1426
- parent.init === currentNode &&
1427
- parent.id.type === "Identifier" &&
1428
- startsWithUpperCase(parent.id.name)
1429
- );
1430
-
1431
- /*
1432
- * e.g.
1433
- * var foo = function foo() { ... }.bind(obj);
1434
- * (function foo() { ... }).call(obj);
1435
- * (function foo() { ... }).apply(obj, []);
1436
- */
1437
- case "MemberExpression":
1438
- if (
1439
- parent.object === currentNode &&
1440
- isSpecificMemberAccess(parent, null, bindOrCallOrApplyPattern)
1441
- ) {
1442
- const maybeCalleeNode = parent.parent.type === "ChainExpression"
1443
- ? parent.parent
1444
- : parent;
1445
-
1446
- return !(
1447
- isCallee(maybeCalleeNode) &&
1448
- maybeCalleeNode.parent.arguments.length >= 1 &&
1449
- !isNullOrUndefined(maybeCalleeNode.parent.arguments[0])
1450
- );
1451
- }
1452
- return true;
1453
-
1454
- /*
1455
- * e.g.
1456
- * Reflect.apply(function() {}, obj, []);
1457
- * Array.from([], function() {}, obj);
1458
- * list.forEach(function() {}, obj);
1459
- */
1460
- case "CallExpression":
1461
- if (isReflectApply(parent.callee)) {
1462
- return (
1463
- parent.arguments.length !== 3 ||
1464
- parent.arguments[0] !== currentNode ||
1465
- isNullOrUndefined(parent.arguments[1])
1466
- );
1467
- }
1468
- if (isArrayFromMethod(parent.callee)) {
1469
- return (
1470
- parent.arguments.length !== 3 ||
1471
- parent.arguments[1] !== currentNode ||
1472
- isNullOrUndefined(parent.arguments[2])
1473
- );
1474
- }
1475
- if (isMethodWhichHasThisArg(parent.callee)) {
1476
- return (
1477
- parent.arguments.length !== 2 ||
1478
- parent.arguments[0] !== currentNode ||
1479
- isNullOrUndefined(parent.arguments[1])
1480
- );
1481
- }
1482
- return true;
1483
-
1484
- // Otherwise `this` is default.
1485
- default:
1486
- return true;
1487
- }
1488
- }
1489
-
1490
- /* c8 ignore next */
1491
- return true;
1492
- },
1493
-
1494
- /**
1495
- * Get the precedence level based on the node type
1496
- * @param {ASTNode} node node to evaluate
1497
- * @returns {int} precedence level
1498
- * @private
1499
- */
1500
- getPrecedence(node) {
1501
- switch (node.type) {
1502
- case "SequenceExpression":
1503
- return 0;
1504
-
1505
- case "AssignmentExpression":
1506
- case "ArrowFunctionExpression":
1507
- case "YieldExpression":
1508
- return 1;
1509
-
1510
- case "ConditionalExpression":
1511
- return 3;
1512
-
1513
- case "LogicalExpression":
1514
- switch (node.operator) {
1515
- case "||":
1516
- case "??":
1517
- return 4;
1518
- case "&&":
1519
- return 5;
1520
-
1521
- // no default
1522
- }
1523
-
1524
- /* falls through */
1525
-
1526
- case "BinaryExpression":
1527
-
1528
- switch (node.operator) {
1529
- case "|":
1530
- return 6;
1531
- case "^":
1532
- return 7;
1533
- case "&":
1534
- return 8;
1535
- case "==":
1536
- case "!=":
1537
- case "===":
1538
- case "!==":
1539
- return 9;
1540
- case "<":
1541
- case "<=":
1542
- case ">":
1543
- case ">=":
1544
- case "in":
1545
- case "instanceof":
1546
- return 10;
1547
- case "<<":
1548
- case ">>":
1549
- case ">>>":
1550
- return 11;
1551
- case "+":
1552
- case "-":
1553
- return 12;
1554
- case "*":
1555
- case "/":
1556
- case "%":
1557
- return 13;
1558
- case "**":
1559
- return 15;
1560
-
1561
- // no default
1562
- }
1563
-
1564
- /* falls through */
1565
-
1566
- case "UnaryExpression":
1567
- case "AwaitExpression":
1568
- return 16;
1569
-
1570
- case "UpdateExpression":
1571
- return 17;
1572
-
1573
- case "CallExpression":
1574
- case "ChainExpression":
1575
- case "ImportExpression":
1576
- return 18;
1577
-
1578
- case "NewExpression":
1579
- return 19;
1580
-
1581
- default:
1582
- if (node.type in eslintVisitorKeys) {
1583
- return 20;
1584
- }
1585
-
1586
- /*
1587
- * if the node is not a standard node that we know about, then assume it has the lowest precedence
1588
- * this will mean that rules will wrap unknown nodes in parentheses where applicable instead of
1589
- * unwrapping them and potentially changing the meaning of the code or introducing a syntax error.
1590
- */
1591
- return -1;
1592
- }
1593
- },
1594
-
1595
- /**
1596
- * Checks whether the given node is an empty block node or not.
1597
- * @param {ASTNode|null} node The node to check.
1598
- * @returns {boolean} `true` if the node is an empty block.
1599
- */
1600
- isEmptyBlock(node) {
1601
- return Boolean(node && node.type === "BlockStatement" && node.body.length === 0);
1602
- },
1603
-
1604
- /**
1605
- * Checks whether the given node is an empty function node or not.
1606
- * @param {ASTNode|null} node The node to check.
1607
- * @returns {boolean} `true` if the node is an empty function.
1608
- */
1609
- isEmptyFunction(node) {
1610
- return isFunction(node) && module.exports.isEmptyBlock(node.body);
1611
- },
1612
-
1613
- /**
1614
- * Get directives from directive prologue of a Program or Function node.
1615
- * @param {ASTNode} node The node to check.
1616
- * @returns {ASTNode[]} The directives found in the directive prologue.
1617
- */
1618
- getDirectivePrologue(node) {
1619
- const directives = [];
1620
-
1621
- // Directive prologues only occur at the top of files or functions.
1622
- if (
1623
- node.type === "Program" ||
1624
- node.type === "FunctionDeclaration" ||
1625
- node.type === "FunctionExpression" ||
1626
-
1627
- /*
1628
- * Do not check arrow functions with implicit return.
1629
- * `() => "use strict";` returns the string `"use strict"`.
1630
- */
1631
- (node.type === "ArrowFunctionExpression" && node.body.type === "BlockStatement")
1632
- ) {
1633
- const statements = node.type === "Program" ? node.body : node.body.body;
1634
-
1635
- for (const statement of statements) {
1636
- if (
1637
- statement.type === "ExpressionStatement" &&
1638
- statement.expression.type === "Literal"
1639
- ) {
1640
- directives.push(statement);
1641
- } else {
1642
- break;
1643
- }
1644
- }
1645
- }
1646
-
1647
- return directives;
1648
- },
1649
-
1650
- /**
1651
- * Determines whether this node is a decimal integer literal. If a node is a decimal integer literal, a dot added
1652
- * after the node will be parsed as a decimal point, rather than a property-access dot.
1653
- * @param {ASTNode} node The node to check.
1654
- * @returns {boolean} `true` if this node is a decimal integer.
1655
- * @example
1656
- *
1657
- * 0 // true
1658
- * 5 // true
1659
- * 50 // true
1660
- * 5_000 // true
1661
- * 1_234_56 // true
1662
- * 08 // true
1663
- * 0192 // true
1664
- * 5. // false
1665
- * .5 // false
1666
- * 5.0 // false
1667
- * 5.00_00 // false
1668
- * 05 // false
1669
- * 0x5 // false
1670
- * 0b101 // false
1671
- * 0b11_01 // false
1672
- * 0o5 // false
1673
- * 5e0 // false
1674
- * 5e1_000 // false
1675
- * 5n // false
1676
- * 1_000n // false
1677
- * "5" // false
1678
- *
1679
- */
1680
- isDecimalInteger(node) {
1681
- return node.type === "Literal" && typeof node.value === "number" &&
1682
- DECIMAL_INTEGER_PATTERN.test(node.raw);
1683
- },
1684
-
1685
- /**
1686
- * Determines whether this token is a decimal integer numeric token.
1687
- * This is similar to isDecimalInteger(), but for tokens.
1688
- * @param {Token} token The token to check.
1689
- * @returns {boolean} `true` if this token is a decimal integer.
1690
- */
1691
- isDecimalIntegerNumericToken(token) {
1692
- return token.type === "Numeric" && DECIMAL_INTEGER_PATTERN.test(token.value);
1693
- },
1694
-
1695
- /**
1696
- * Gets the name and kind of the given function node.
1697
- *
1698
- * - `function foo() {}` .................... `function 'foo'`
1699
- * - `(function foo() {})` .................. `function 'foo'`
1700
- * - `(function() {})` ...................... `function`
1701
- * - `function* foo() {}` ................... `generator function 'foo'`
1702
- * - `(function* foo() {})` ................. `generator function 'foo'`
1703
- * - `(function*() {})` ..................... `generator function`
1704
- * - `() => {}` ............................. `arrow function`
1705
- * - `async () => {}` ....................... `async arrow function`
1706
- * - `({ foo: function foo() {} })` ......... `method 'foo'`
1707
- * - `({ foo: function() {} })` ............. `method 'foo'`
1708
- * - `({ ['foo']: function() {} })` ......... `method 'foo'`
1709
- * - `({ [foo]: function() {} })` ........... `method`
1710
- * - `({ foo() {} })` ....................... `method 'foo'`
1711
- * - `({ foo: function* foo() {} })` ........ `generator method 'foo'`
1712
- * - `({ foo: function*() {} })` ............ `generator method 'foo'`
1713
- * - `({ ['foo']: function*() {} })` ........ `generator method 'foo'`
1714
- * - `({ [foo]: function*() {} })` .......... `generator method`
1715
- * - `({ *foo() {} })` ...................... `generator method 'foo'`
1716
- * - `({ foo: async function foo() {} })` ... `async method 'foo'`
1717
- * - `({ foo: async function() {} })` ....... `async method 'foo'`
1718
- * - `({ ['foo']: async function() {} })` ... `async method 'foo'`
1719
- * - `({ [foo]: async function() {} })` ..... `async method`
1720
- * - `({ async foo() {} })` ................. `async method 'foo'`
1721
- * - `({ get foo() {} })` ................... `getter 'foo'`
1722
- * - `({ set foo(a) {} })` .................. `setter 'foo'`
1723
- * - `class A { constructor() {} }` ......... `constructor`
1724
- * - `class A { foo() {} }` ................. `method 'foo'`
1725
- * - `class A { *foo() {} }` ................ `generator method 'foo'`
1726
- * - `class A { async foo() {} }` ........... `async method 'foo'`
1727
- * - `class A { ['foo']() {} }` ............. `method 'foo'`
1728
- * - `class A { *['foo']() {} }` ............ `generator method 'foo'`
1729
- * - `class A { async ['foo']() {} }` ....... `async method 'foo'`
1730
- * - `class A { [foo]() {} }` ............... `method`
1731
- * - `class A { *[foo]() {} }` .............. `generator method`
1732
- * - `class A { async [foo]() {} }` ......... `async method`
1733
- * - `class A { get foo() {} }` ............. `getter 'foo'`
1734
- * - `class A { set foo(a) {} }` ............ `setter 'foo'`
1735
- * - `class A { static foo() {} }` .......... `static method 'foo'`
1736
- * - `class A { static *foo() {} }` ......... `static generator method 'foo'`
1737
- * - `class A { static async foo() {} }` .... `static async method 'foo'`
1738
- * - `class A { static get foo() {} }` ...... `static getter 'foo'`
1739
- * - `class A { static set foo(a) {} }` ..... `static setter 'foo'`
1740
- * - `class A { foo = () => {}; }` .......... `method 'foo'`
1741
- * - `class A { foo = function() {}; }` ..... `method 'foo'`
1742
- * - `class A { foo = function bar() {}; }` . `method 'foo'`
1743
- * - `class A { static foo = () => {}; }` ... `static method 'foo'`
1744
- * - `class A { '#foo' = () => {}; }` ....... `method '#foo'`
1745
- * - `class A { #foo = () => {}; }` ......... `private method #foo`
1746
- * - `class A { static #foo = () => {}; }` .. `static private method #foo`
1747
- * - `class A { '#foo'() {} }` .............. `method '#foo'`
1748
- * - `class A { #foo() {} }` ................ `private method #foo`
1749
- * - `class A { static #foo() {} }` ......... `static private method #foo`
1750
- * @param {ASTNode} node The function node to get.
1751
- * @returns {string} The name and kind of the function node.
1752
- */
1753
- getFunctionNameWithKind(node) {
1754
- const parent = node.parent;
1755
- const tokens = [];
1756
-
1757
- if (parent.type === "MethodDefinition" || parent.type === "PropertyDefinition") {
1758
-
1759
- // The proposal uses `static` word consistently before visibility words: https://github.com/tc39/proposal-static-class-features
1760
- if (parent.static) {
1761
- tokens.push("static");
1762
- }
1763
- if (!parent.computed && parent.key.type === "PrivateIdentifier") {
1764
- tokens.push("private");
1765
- }
1766
- }
1767
- if (node.async) {
1768
- tokens.push("async");
1769
- }
1770
- if (node.generator) {
1771
- tokens.push("generator");
1772
- }
1773
-
1774
- if (parent.type === "Property" || parent.type === "MethodDefinition") {
1775
- if (parent.kind === "constructor") {
1776
- return "constructor";
1777
- }
1778
- if (parent.kind === "get") {
1779
- tokens.push("getter");
1780
- } else if (parent.kind === "set") {
1781
- tokens.push("setter");
1782
- } else {
1783
- tokens.push("method");
1784
- }
1785
- } else if (parent.type === "PropertyDefinition") {
1786
- tokens.push("method");
1787
- } else {
1788
- if (node.type === "ArrowFunctionExpression") {
1789
- tokens.push("arrow");
1790
- }
1791
- tokens.push("function");
1792
- }
1793
-
1794
- if (parent.type === "Property" || parent.type === "MethodDefinition" || parent.type === "PropertyDefinition") {
1795
- if (!parent.computed && parent.key.type === "PrivateIdentifier") {
1796
- tokens.push(`#${parent.key.name}`);
1797
- } else {
1798
- const name = getStaticPropertyName(parent);
1799
-
1800
- if (name !== null) {
1801
- tokens.push(`'${name}'`);
1802
- } else if (node.id) {
1803
- tokens.push(`'${node.id.name}'`);
1804
- }
1805
- }
1806
- } else if (node.id) {
1807
- tokens.push(`'${node.id.name}'`);
1808
- }
1809
-
1810
- return tokens.join(" ");
1811
- },
1812
-
1813
- /**
1814
- * Gets the location of the given function node for reporting.
1815
- *
1816
- * - `function foo() {}`
1817
- * ^^^^^^^^^^^^
1818
- * - `(function foo() {})`
1819
- * ^^^^^^^^^^^^
1820
- * - `(function() {})`
1821
- * ^^^^^^^^
1822
- * - `function* foo() {}`
1823
- * ^^^^^^^^^^^^^
1824
- * - `(function* foo() {})`
1825
- * ^^^^^^^^^^^^^
1826
- * - `(function*() {})`
1827
- * ^^^^^^^^^
1828
- * - `() => {}`
1829
- * ^^
1830
- * - `async () => {}`
1831
- * ^^
1832
- * - `({ foo: function foo() {} })`
1833
- * ^^^^^^^^^^^^^^^^^
1834
- * - `({ foo: function() {} })`
1835
- * ^^^^^^^^^^^^^
1836
- * - `({ ['foo']: function() {} })`
1837
- * ^^^^^^^^^^^^^^^^^
1838
- * - `({ [foo]: function() {} })`
1839
- * ^^^^^^^^^^^^^^^
1840
- * - `({ foo() {} })`
1841
- * ^^^
1842
- * - `({ foo: function* foo() {} })`
1843
- * ^^^^^^^^^^^^^^^^^^
1844
- * - `({ foo: function*() {} })`
1845
- * ^^^^^^^^^^^^^^
1846
- * - `({ ['foo']: function*() {} })`
1847
- * ^^^^^^^^^^^^^^^^^^
1848
- * - `({ [foo]: function*() {} })`
1849
- * ^^^^^^^^^^^^^^^^
1850
- * - `({ *foo() {} })`
1851
- * ^^^^
1852
- * - `({ foo: async function foo() {} })`
1853
- * ^^^^^^^^^^^^^^^^^^^^^^^
1854
- * - `({ foo: async function() {} })`
1855
- * ^^^^^^^^^^^^^^^^^^^
1856
- * - `({ ['foo']: async function() {} })`
1857
- * ^^^^^^^^^^^^^^^^^^^^^^^
1858
- * - `({ [foo]: async function() {} })`
1859
- * ^^^^^^^^^^^^^^^^^^^^^
1860
- * - `({ async foo() {} })`
1861
- * ^^^^^^^^^
1862
- * - `({ get foo() {} })`
1863
- * ^^^^^^^
1864
- * - `({ set foo(a) {} })`
1865
- * ^^^^^^^
1866
- * - `class A { constructor() {} }`
1867
- * ^^^^^^^^^^^
1868
- * - `class A { foo() {} }`
1869
- * ^^^
1870
- * - `class A { *foo() {} }`
1871
- * ^^^^
1872
- * - `class A { async foo() {} }`
1873
- * ^^^^^^^^^
1874
- * - `class A { ['foo']() {} }`
1875
- * ^^^^^^^
1876
- * - `class A { *['foo']() {} }`
1877
- * ^^^^^^^^
1878
- * - `class A { async ['foo']() {} }`
1879
- * ^^^^^^^^^^^^^
1880
- * - `class A { [foo]() {} }`
1881
- * ^^^^^
1882
- * - `class A { *[foo]() {} }`
1883
- * ^^^^^^
1884
- * - `class A { async [foo]() {} }`
1885
- * ^^^^^^^^^^^
1886
- * - `class A { get foo() {} }`
1887
- * ^^^^^^^
1888
- * - `class A { set foo(a) {} }`
1889
- * ^^^^^^^
1890
- * - `class A { static foo() {} }`
1891
- * ^^^^^^^^^^
1892
- * - `class A { static *foo() {} }`
1893
- * ^^^^^^^^^^^
1894
- * - `class A { static async foo() {} }`
1895
- * ^^^^^^^^^^^^^^^^
1896
- * - `class A { static get foo() {} }`
1897
- * ^^^^^^^^^^^^^^
1898
- * - `class A { static set foo(a) {} }`
1899
- * ^^^^^^^^^^^^^^
1900
- * - `class A { foo = function() {} }`
1901
- * ^^^^^^^^^^^^^^
1902
- * - `class A { static foo = function() {} }`
1903
- * ^^^^^^^^^^^^^^^^^^^^^
1904
- * - `class A { foo = (a, b) => {} }`
1905
- * ^^^^^^
1906
- * @param {ASTNode} node The function node to get.
1907
- * @param {SourceCode} sourceCode The source code object to get tokens.
1908
- * @returns {string} The location of the function node for reporting.
1909
- */
1910
- getFunctionHeadLoc(node, sourceCode) {
1911
- const parent = node.parent;
1912
- let start = null;
1913
- let end = null;
1914
-
1915
- if (parent.type === "Property" || parent.type === "MethodDefinition" || parent.type === "PropertyDefinition") {
1916
- start = parent.loc.start;
1917
- end = getOpeningParenOfParams(node, sourceCode).loc.start;
1918
- } else if (node.type === "ArrowFunctionExpression") {
1919
- const arrowToken = sourceCode.getTokenBefore(node.body, isArrowToken);
1920
-
1921
- start = arrowToken.loc.start;
1922
- end = arrowToken.loc.end;
1923
- } else {
1924
- start = node.loc.start;
1925
- end = getOpeningParenOfParams(node, sourceCode).loc.start;
1926
- }
1927
-
1928
- return {
1929
- start: Object.assign({}, start),
1930
- end: Object.assign({}, end)
1931
- };
1932
- },
1933
-
1934
- /**
1935
- * Gets next location when the result is not out of bound, otherwise returns null.
1936
- *
1937
- * Assumptions:
1938
- *
1939
- * - The given location represents a valid location in the given source code.
1940
- * - Columns are 0-based.
1941
- * - Lines are 1-based.
1942
- * - Column immediately after the last character in a line (not incl. linebreaks) is considered to be a valid location.
1943
- * - If the source code ends with a linebreak, `sourceCode.lines` array will have an extra element (empty string) at the end.
1944
- * The start (column 0) of that extra line is considered to be a valid location.
1945
- *
1946
- * Examples of successive locations (line, column):
1947
- *
1948
- * code: foo
1949
- * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> null
1950
- *
1951
- * code: foo<LF>
1952
- * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
1953
- *
1954
- * code: foo<CR><LF>
1955
- * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
1956
- *
1957
- * code: a<LF>b
1958
- * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> null
1959
- *
1960
- * code: a<LF>b<LF>
1961
- * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
1962
- *
1963
- * code: a<CR><LF>b<CR><LF>
1964
- * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
1965
- *
1966
- * code: a<LF><LF>
1967
- * locations: (1, 0) -> (1, 1) -> (2, 0) -> (3, 0) -> null
1968
- *
1969
- * code: <LF>
1970
- * locations: (1, 0) -> (2, 0) -> null
1971
- *
1972
- * code:
1973
- * locations: (1, 0) -> null
1974
- * @param {SourceCode} sourceCode The sourceCode
1975
- * @param {{line: number, column: number}} location The location
1976
- * @returns {{line: number, column: number} | null} Next location
1977
- */
1978
- getNextLocation(sourceCode, { line, column }) {
1979
- if (column < sourceCode.lines[line - 1].length) {
1980
- return {
1981
- line,
1982
- column: column + 1
1983
- };
1984
- }
1985
-
1986
- if (line < sourceCode.lines.length) {
1987
- return {
1988
- line: line + 1,
1989
- column: 0
1990
- };
1991
- }
1992
-
1993
- return null;
1994
- },
1995
-
1996
- /**
1997
- * Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
1998
- * surrounding the node.
1999
- * @param {SourceCode} sourceCode The source code object
2000
- * @param {ASTNode} node An expression node
2001
- * @returns {string} The text representing the node, with all surrounding parentheses included
2002
- */
2003
- getParenthesisedText(sourceCode, node) {
2004
- let leftToken = sourceCode.getFirstToken(node);
2005
- let rightToken = sourceCode.getLastToken(node);
2006
-
2007
- while (
2008
- sourceCode.getTokenBefore(leftToken) &&
2009
- sourceCode.getTokenBefore(leftToken).type === "Punctuator" &&
2010
- sourceCode.getTokenBefore(leftToken).value === "(" &&
2011
- sourceCode.getTokenAfter(rightToken) &&
2012
- sourceCode.getTokenAfter(rightToken).type === "Punctuator" &&
2013
- sourceCode.getTokenAfter(rightToken).value === ")"
2014
- ) {
2015
- leftToken = sourceCode.getTokenBefore(leftToken);
2016
- rightToken = sourceCode.getTokenAfter(rightToken);
2017
- }
2018
-
2019
- return sourceCode.getText().slice(leftToken.range[0], rightToken.range[1]);
2020
- },
2021
-
2022
- /**
2023
- * Determine if a node has a possibility to be an Error object
2024
- * @param {ASTNode} node ASTNode to check
2025
- * @returns {boolean} True if there is a chance it contains an Error obj
2026
- */
2027
- couldBeError(node) {
2028
- switch (node.type) {
2029
- case "Identifier":
2030
- case "CallExpression":
2031
- case "NewExpression":
2032
- case "MemberExpression":
2033
- case "TaggedTemplateExpression":
2034
- case "YieldExpression":
2035
- case "AwaitExpression":
2036
- case "ChainExpression":
2037
- return true; // possibly an error object.
2038
-
2039
- case "AssignmentExpression":
2040
- if (["=", "&&="].includes(node.operator)) {
2041
- return module.exports.couldBeError(node.right);
2042
- }
2043
-
2044
- if (["||=", "??="].includes(node.operator)) {
2045
- return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right);
2046
- }
2047
-
2048
- /**
2049
- * All other assignment operators are mathematical assignment operators (arithmetic or bitwise).
2050
- * An assignment expression with a mathematical operator can either evaluate to a primitive value,
2051
- * or throw, depending on the operands. Thus, it cannot evaluate to an `Error` object.
2052
- */
2053
- return false;
2054
-
2055
- case "SequenceExpression": {
2056
- const exprs = node.expressions;
2057
-
2058
- return exprs.length !== 0 && module.exports.couldBeError(exprs[exprs.length - 1]);
2059
- }
2060
-
2061
- case "LogicalExpression":
2062
-
2063
- /*
2064
- * If the && operator short-circuits, the left side was falsy and therefore not an error, and if it
2065
- * doesn't short-circuit, it takes the value from the right side, so the right side must always be
2066
- * a plausible error. A future improvement could verify that the left side could be truthy by
2067
- * excluding falsy literals.
2068
- */
2069
- if (node.operator === "&&") {
2070
- return module.exports.couldBeError(node.right);
2071
- }
2072
-
2073
- return module.exports.couldBeError(node.left) || module.exports.couldBeError(node.right);
2074
-
2075
- case "ConditionalExpression":
2076
- return module.exports.couldBeError(node.consequent) || module.exports.couldBeError(node.alternate);
2077
-
2078
- default:
2079
- return false;
2080
- }
2081
- },
2082
-
2083
- /**
2084
- * Check if a given node is a numeric literal or not.
2085
- * @param {ASTNode} node The node to check.
2086
- * @returns {boolean} `true` if the node is a number or bigint literal.
2087
- */
2088
- isNumericLiteral(node) {
2089
- return (
2090
- node.type === "Literal" &&
2091
- (typeof node.value === "number" || Boolean(node.bigint))
2092
- );
2093
- },
2094
-
2095
- /**
2096
- * Determines whether two tokens can safely be placed next to each other without merging into a single token
2097
- * @param {Token|string} leftValue The left token. If this is a string, it will be tokenized and the last token will be used.
2098
- * @param {Token|string} rightValue The right token. If this is a string, it will be tokenized and the first token will be used.
2099
- * @returns {boolean} If the tokens cannot be safely placed next to each other, returns `false`. If the tokens can be placed
2100
- * next to each other, behavior is undefined (although it should return `true` in most cases).
2101
- */
2102
- canTokensBeAdjacent(leftValue, rightValue) {
2103
- const espreeOptions = {
2104
- ecmaVersion: espree.latestEcmaVersion,
2105
- comment: true,
2106
- range: true
2107
- };
2108
-
2109
- let leftToken;
2110
-
2111
- if (typeof leftValue === "string") {
2112
- let tokens;
2113
-
2114
- try {
2115
- tokens = espree.tokenize(leftValue, espreeOptions);
2116
- } catch {
2117
- return false;
2118
- }
2119
-
2120
- const comments = tokens.comments;
2121
-
2122
- leftToken = tokens[tokens.length - 1];
2123
- if (comments.length) {
2124
- const lastComment = comments[comments.length - 1];
2125
-
2126
- if (!leftToken || lastComment.range[0] > leftToken.range[0]) {
2127
- leftToken = lastComment;
2128
- }
2129
- }
2130
- } else {
2131
- leftToken = leftValue;
2132
- }
2133
-
2134
- /*
2135
- * If a hashbang comment was passed as a token object from SourceCode,
2136
- * its type will be "Shebang" because of the way ESLint itself handles hashbangs.
2137
- * If a hashbang comment was passed in a string and then tokenized in this function,
2138
- * its type will be "Hashbang" because of the way Espree tokenizes hashbangs.
2139
- */
2140
- if (leftToken.type === "Shebang" || leftToken.type === "Hashbang") {
2141
- return false;
2142
- }
2143
-
2144
- let rightToken;
2145
-
2146
- if (typeof rightValue === "string") {
2147
- let tokens;
2148
-
2149
- try {
2150
- tokens = espree.tokenize(rightValue, espreeOptions);
2151
- } catch {
2152
- return false;
2153
- }
2154
-
2155
- const comments = tokens.comments;
2156
-
2157
- rightToken = tokens[0];
2158
- if (comments.length) {
2159
- const firstComment = comments[0];
2160
-
2161
- if (!rightToken || firstComment.range[0] < rightToken.range[0]) {
2162
- rightToken = firstComment;
2163
- }
2164
- }
2165
- } else {
2166
- rightToken = rightValue;
2167
- }
2168
-
2169
- if (leftToken.type === "Punctuator" || rightToken.type === "Punctuator") {
2170
- if (leftToken.type === "Punctuator" && rightToken.type === "Punctuator") {
2171
- const PLUS_TOKENS = new Set(["+", "++"]);
2172
- const MINUS_TOKENS = new Set(["-", "--"]);
2173
-
2174
- return !(
2175
- PLUS_TOKENS.has(leftToken.value) && PLUS_TOKENS.has(rightToken.value) ||
2176
- MINUS_TOKENS.has(leftToken.value) && MINUS_TOKENS.has(rightToken.value)
2177
- );
2178
- }
2179
- if (leftToken.type === "Punctuator" && leftToken.value === "/") {
2180
- return !["Block", "Line", "RegularExpression"].includes(rightToken.type);
2181
- }
2182
- return true;
2183
- }
2184
-
2185
- if (
2186
- leftToken.type === "String" || rightToken.type === "String" ||
2187
- leftToken.type === "Template" || rightToken.type === "Template"
2188
- ) {
2189
- return true;
2190
- }
2191
-
2192
- if (leftToken.type !== "Numeric" && rightToken.type === "Numeric" && rightToken.value.startsWith(".")) {
2193
- return true;
2194
- }
2195
-
2196
- if (leftToken.type === "Block" || rightToken.type === "Block" || rightToken.type === "Line") {
2197
- return true;
2198
- }
2199
-
2200
- if (rightToken.type === "PrivateIdentifier") {
2201
- return true;
2202
- }
2203
-
2204
- return false;
2205
- },
2206
-
2207
- /**
2208
- * Get the `loc` object of a given name in a `/*globals` directive comment.
2209
- * @param {SourceCode} sourceCode The source code to convert index to loc.
2210
- * @param {Comment} comment The `/*globals` directive comment which include the name.
2211
- * @param {string} name The name to find.
2212
- * @returns {SourceLocation} The `loc` object.
2213
- */
2214
- getNameLocationInGlobalDirectiveComment(sourceCode, comment, name) {
2215
- const namePattern = new RegExp(`[\\s,]${escapeRegExp(name)}(?:$|[\\s,:])`, "gu");
2216
-
2217
- // To ignore the first text "global".
2218
- namePattern.lastIndex = comment.value.indexOf("global") + 6;
2219
-
2220
- // Search a given variable name.
2221
- const match = namePattern.exec(comment.value);
2222
-
2223
- // Convert the index to loc.
2224
- const start = sourceCode.getLocFromIndex(
2225
- comment.range[0] +
2226
- "/*".length +
2227
- (match ? match.index + 1 : 0)
2228
- );
2229
- const end = {
2230
- line: start.line,
2231
- column: start.column + (match ? name.length : 1)
2232
- };
2233
-
2234
- return { start, end };
2235
- },
2236
-
2237
- /**
2238
- * Determines whether the given raw string contains an octal escape sequence
2239
- * or a non-octal decimal escape sequence ("\8", "\9").
2240
- *
2241
- * "\1", "\2" ... "\7", "\8", "\9"
2242
- * "\00", "\01" ... "\07", "\08", "\09"
2243
- *
2244
- * "\0", when not followed by a digit, is not an octal escape sequence.
2245
- * @param {string} rawString A string in its raw representation.
2246
- * @returns {boolean} `true` if the string contains at least one octal escape sequence
2247
- * or at least one non-octal decimal escape sequence.
2248
- */
2249
- hasOctalOrNonOctalDecimalEscapeSequence(rawString) {
2250
- return OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN.test(rawString);
2251
- },
2252
-
2253
- /**
2254
- * Determines whether the given node is a template literal without expressions.
2255
- * @param {ASTNode} node Node to check.
2256
- * @returns {boolean} True if the node is a template literal without expressions.
2257
- */
2258
- isStaticTemplateLiteral(node) {
2259
- return node.type === "TemplateLiteral" && node.expressions.length === 0;
2260
- },
2261
-
2262
- isReferenceToGlobalVariable,
2263
- isLogicalExpression,
2264
- isCoalesceExpression,
2265
- isMixedLogicalAndCoalesceExpressions,
2266
- isNullLiteral,
2267
- getStaticStringValue,
2268
- getStaticPropertyName,
2269
- skipChainExpression,
2270
- isSpecificId,
2271
- isSpecificMemberAccess,
2272
- equalLiteralValue,
2273
- isSameReference,
2274
- isLogicalAssignmentOperator,
2275
- getSwitchCaseColonToken,
2276
- getModuleExportName,
2277
- isConstant,
2278
- isTopLevelExpressionStatement,
2279
- isDirective,
2280
- isStartOfExpressionStatement,
2281
- needsPrecedingSemicolon
1344
+ COMMENTS_IGNORE_PATTERN,
1345
+ LINEBREAKS,
1346
+ LINEBREAK_MATCHER: lineBreakPattern,
1347
+ SHEBANG_MATCHER: shebangPattern,
1348
+ STATEMENT_LIST_PARENTS,
1349
+ ECMASCRIPT_GLOBALS,
1350
+
1351
+ /**
1352
+ * Determines whether two adjacent tokens are on the same line.
1353
+ * @param {Object} left The left token object.
1354
+ * @param {Object} right The right token object.
1355
+ * @returns {boolean} Whether or not the tokens are on the same line.
1356
+ * @public
1357
+ */
1358
+ isTokenOnSameLine(left, right) {
1359
+ return left.loc.end.line === right.loc.start.line;
1360
+ },
1361
+
1362
+ isNullOrUndefined,
1363
+ isCallee,
1364
+ isES5Constructor,
1365
+ getUpperFunction,
1366
+ isFunction,
1367
+ isLoop,
1368
+ isInLoop,
1369
+ isArrayFromMethod,
1370
+ isParenthesised,
1371
+ createGlobalLinebreakMatcher,
1372
+ equalTokens,
1373
+
1374
+ isArrowToken,
1375
+ isClosingBraceToken,
1376
+ isClosingBracketToken,
1377
+ isClosingParenToken,
1378
+ isColonToken,
1379
+ isCommaToken,
1380
+ isCommentToken,
1381
+ isDotToken,
1382
+ isQuestionDotToken,
1383
+ isKeywordToken,
1384
+ isNotClosingBraceToken: negate(isClosingBraceToken),
1385
+ isNotClosingBracketToken: negate(isClosingBracketToken),
1386
+ isNotClosingParenToken: negate(isClosingParenToken),
1387
+ isNotColonToken: negate(isColonToken),
1388
+ isNotCommaToken: negate(isCommaToken),
1389
+ isNotDotToken: negate(isDotToken),
1390
+ isNotQuestionDotToken: negate(isQuestionDotToken),
1391
+ isNotOpeningBraceToken: negate(isOpeningBraceToken),
1392
+ isNotOpeningBracketToken: negate(isOpeningBracketToken),
1393
+ isNotOpeningParenToken: negate(isOpeningParenToken),
1394
+ isNotSemicolonToken: negate(isSemicolonToken),
1395
+ isOpeningBraceToken,
1396
+ isOpeningBracketToken,
1397
+ isOpeningParenToken,
1398
+ isSemicolonToken,
1399
+ isEqToken,
1400
+
1401
+ /**
1402
+ * Checks whether or not a given node is a string literal.
1403
+ * @param {ASTNode} node A node to check.
1404
+ * @returns {boolean} `true` if the node is a string literal.
1405
+ */
1406
+ isStringLiteral(node) {
1407
+ return (
1408
+ (node.type === "Literal" && typeof node.value === "string") ||
1409
+ node.type === "TemplateLiteral"
1410
+ );
1411
+ },
1412
+
1413
+ /**
1414
+ * Checks whether a given node is a breakable statement or not.
1415
+ * The node is breakable if the node is one of the following type:
1416
+ *
1417
+ * - DoWhileStatement
1418
+ * - ForInStatement
1419
+ * - ForOfStatement
1420
+ * - ForStatement
1421
+ * - SwitchStatement
1422
+ * - WhileStatement
1423
+ * @param {ASTNode} node A node to check.
1424
+ * @returns {boolean} `true` if the node is breakable.
1425
+ */
1426
+ isBreakableStatement(node) {
1427
+ return breakableTypePattern.test(node.type);
1428
+ },
1429
+
1430
+ /**
1431
+ * Gets references which are non initializer and writable.
1432
+ * @param {Reference[]} references An array of references.
1433
+ * @returns {Reference[]} An array of only references which are non initializer and writable.
1434
+ * @public
1435
+ */
1436
+ getModifyingReferences(references) {
1437
+ return references.filter(isModifyingReference);
1438
+ },
1439
+
1440
+ /**
1441
+ * Validate that a string passed in is surrounded by the specified character
1442
+ * @param {string} val The text to check.
1443
+ * @param {string} character The character to see if it's surrounded by.
1444
+ * @returns {boolean} True if the text is surrounded by the character, false if not.
1445
+ * @private
1446
+ */
1447
+ isSurroundedBy(val, character) {
1448
+ return val[0] === character && val.at(-1) === character;
1449
+ },
1450
+
1451
+ /**
1452
+ * Returns whether the provided node is an ESLint directive comment or not
1453
+ * @param {Line|Block} node The comment token to be checked
1454
+ * @returns {boolean} `true` if the node is an ESLint directive comment
1455
+ */
1456
+ isDirectiveComment(node) {
1457
+ const comment = node.value.trim();
1458
+
1459
+ return (
1460
+ (node.type === "Line" && comment.startsWith("eslint-")) ||
1461
+ (node.type === "Block" && ESLINT_DIRECTIVE_PATTERN.test(comment))
1462
+ );
1463
+ },
1464
+
1465
+ /**
1466
+ * Gets the trailing statement of a given node.
1467
+ *
1468
+ * if (code)
1469
+ * consequent;
1470
+ *
1471
+ * When taking this `IfStatement`, returns `consequent;` statement.
1472
+ * @param {ASTNode} A node to get.
1473
+ * @returns {ASTNode|null} The trailing statement's node.
1474
+ */
1475
+ getTrailingStatement: esutils.ast.trailingStatement,
1476
+
1477
+ /**
1478
+ * Finds the variable by a given name in a given scope and its upper scopes.
1479
+ * @param {eslint-scope.Scope} initScope A scope to start find.
1480
+ * @param {string} name A variable name to find.
1481
+ * @returns {eslint-scope.Variable|null} A found variable or `null`.
1482
+ */
1483
+ getVariableByName(initScope, name) {
1484
+ let scope = initScope;
1485
+
1486
+ while (scope) {
1487
+ const variable = scope.set.get(name);
1488
+
1489
+ if (variable) {
1490
+ return variable;
1491
+ }
1492
+
1493
+ scope = scope.upper;
1494
+ }
1495
+
1496
+ return null;
1497
+ },
1498
+
1499
+ /**
1500
+ * Checks whether or not a given function node is the default `this` binding.
1501
+ *
1502
+ * First, this checks the node:
1503
+ *
1504
+ * - The given node is not in `PropertyDefinition#value` position.
1505
+ * - The given node is not `StaticBlock`.
1506
+ * - The function name does not start with uppercase. It's a convention to capitalize the names
1507
+ * of constructor functions. This check is not performed if `capIsConstructor` is set to `false`.
1508
+ * - The function does not have a JSDoc comment that has a @this tag.
1509
+ *
1510
+ * Next, this checks the location of the node.
1511
+ * If the location is below, this judges `this` is valid.
1512
+ *
1513
+ * - The location is not on an object literal.
1514
+ * - The location is not assigned to a variable which starts with an uppercase letter. Applies to anonymous
1515
+ * functions only, as the name of the variable is considered to be the name of the function in this case.
1516
+ * This check is not performed if `capIsConstructor` is set to `false`.
1517
+ * - The location is not on an ES2015 class.
1518
+ * - Its `bind`/`call`/`apply` method is not called directly.
1519
+ * - The function is not a callback of array methods (such as `.forEach()`) if `thisArg` is given.
1520
+ * @param {ASTNode} node A function node to check. It also can be an implicit function, like `StaticBlock`
1521
+ * or any expression that is `PropertyDefinition#value` node.
1522
+ * @param {SourceCode} sourceCode A SourceCode instance to get comments.
1523
+ * @param {boolean} [capIsConstructor = true] `false` disables the assumption that functions which name starts
1524
+ * with an uppercase or are assigned to a variable which name starts with an uppercase are constructors.
1525
+ * @returns {boolean} The function node is the default `this` binding.
1526
+ */
1527
+ isDefaultThisBinding(node, sourceCode, { capIsConstructor = true } = {}) {
1528
+ /*
1529
+ * Class field initializers are implicit functions, but ESTree doesn't have the AST node of field initializers.
1530
+ * Therefore, A expression node at `PropertyDefinition#value` is a function.
1531
+ * In this case, `this` is always not default binding.
1532
+ */
1533
+ if (
1534
+ node.parent.type === "PropertyDefinition" &&
1535
+ node.parent.value === node
1536
+ ) {
1537
+ return false;
1538
+ }
1539
+
1540
+ // Class static blocks are implicit functions. In this case, `this` is always not default binding.
1541
+ if (node.type === "StaticBlock") {
1542
+ return false;
1543
+ }
1544
+
1545
+ // Check if the function has a parameter named `this`.
1546
+ if (
1547
+ (node.type === "FunctionDeclaration" ||
1548
+ node.type === "FunctionExpression") &&
1549
+ node.params.some(
1550
+ param => param.type === "Identifier" && param.name === "this",
1551
+ )
1552
+ ) {
1553
+ return false;
1554
+ }
1555
+
1556
+ if (
1557
+ (capIsConstructor && isES5Constructor(node)) ||
1558
+ hasJSDocThisTag(node, sourceCode)
1559
+ ) {
1560
+ return false;
1561
+ }
1562
+ const isAnonymous = node.id === null;
1563
+ let currentNode = node;
1564
+
1565
+ while (currentNode) {
1566
+ const parent = currentNode.parent;
1567
+
1568
+ switch (parent.type) {
1569
+ /*
1570
+ * Looks up the destination.
1571
+ * e.g., obj.foo = nativeFoo || function foo() { ... };
1572
+ */
1573
+ case "LogicalExpression":
1574
+ case "ConditionalExpression":
1575
+ case "ChainExpression":
1576
+ currentNode = parent;
1577
+ break;
1578
+
1579
+ /*
1580
+ * If the upper function is IIFE, checks the destination of the return value.
1581
+ * e.g.
1582
+ * obj.foo = (function() {
1583
+ * // setup...
1584
+ * return function foo() { ... };
1585
+ * })();
1586
+ * obj.foo = (() =>
1587
+ * function foo() { ... }
1588
+ * )();
1589
+ */
1590
+ case "ReturnStatement": {
1591
+ const func = getUpperFunction(parent);
1592
+
1593
+ if (func === null || !isCallee(func)) {
1594
+ return true;
1595
+ }
1596
+ currentNode = func.parent;
1597
+ break;
1598
+ }
1599
+ case "ArrowFunctionExpression":
1600
+ if (currentNode !== parent.body || !isCallee(parent)) {
1601
+ return true;
1602
+ }
1603
+ currentNode = parent.parent;
1604
+ break;
1605
+
1606
+ /*
1607
+ * e.g.
1608
+ * var obj = { foo() { ... } };
1609
+ * var obj = { foo: function() { ... } };
1610
+ * class A { constructor() { ... } }
1611
+ * class A { foo() { ... } }
1612
+ * class A { get foo() { ... } }
1613
+ * class A { set foo() { ... } }
1614
+ * class A { static foo() { ... } }
1615
+ * class A { foo = function() { ... } }
1616
+ */
1617
+ case "Property":
1618
+ case "PropertyDefinition":
1619
+ case "MethodDefinition":
1620
+ return parent.value !== currentNode;
1621
+
1622
+ /*
1623
+ * e.g.
1624
+ * obj.foo = function foo() { ... };
1625
+ * Foo = function() { ... };
1626
+ * [obj.foo = function foo() { ... }] = a;
1627
+ * [Foo = function() { ... }] = a;
1628
+ */
1629
+ case "AssignmentExpression":
1630
+ case "AssignmentPattern":
1631
+ if (parent.left.type === "MemberExpression") {
1632
+ return false;
1633
+ }
1634
+ if (
1635
+ capIsConstructor &&
1636
+ isAnonymous &&
1637
+ parent.left.type === "Identifier" &&
1638
+ startsWithUpperCase(parent.left.name)
1639
+ ) {
1640
+ return false;
1641
+ }
1642
+ return true;
1643
+
1644
+ /*
1645
+ * e.g.
1646
+ * var Foo = function() { ... };
1647
+ */
1648
+ case "VariableDeclarator":
1649
+ return !(
1650
+ capIsConstructor &&
1651
+ isAnonymous &&
1652
+ parent.init === currentNode &&
1653
+ parent.id.type === "Identifier" &&
1654
+ startsWithUpperCase(parent.id.name)
1655
+ );
1656
+
1657
+ /*
1658
+ * e.g.
1659
+ * var foo = function foo() { ... }.bind(obj);
1660
+ * (function foo() { ... }).call(obj);
1661
+ * (function foo() { ... }).apply(obj, []);
1662
+ */
1663
+ case "MemberExpression":
1664
+ if (
1665
+ parent.object === currentNode &&
1666
+ isSpecificMemberAccess(
1667
+ parent,
1668
+ null,
1669
+ bindOrCallOrApplyPattern,
1670
+ )
1671
+ ) {
1672
+ const maybeCalleeNode =
1673
+ parent.parent.type === "ChainExpression"
1674
+ ? parent.parent
1675
+ : parent;
1676
+
1677
+ return !(
1678
+ isCallee(maybeCalleeNode) &&
1679
+ maybeCalleeNode.parent.arguments.length >= 1 &&
1680
+ !isNullOrUndefined(
1681
+ maybeCalleeNode.parent.arguments[0],
1682
+ )
1683
+ );
1684
+ }
1685
+ return true;
1686
+
1687
+ /*
1688
+ * e.g.
1689
+ * Reflect.apply(function() {}, obj, []);
1690
+ * Array.from([], function() {}, obj);
1691
+ * list.forEach(function() {}, obj);
1692
+ */
1693
+ case "CallExpression":
1694
+ if (isReflectApply(parent.callee)) {
1695
+ return (
1696
+ parent.arguments.length !== 3 ||
1697
+ parent.arguments[0] !== currentNode ||
1698
+ isNullOrUndefined(parent.arguments[1])
1699
+ );
1700
+ }
1701
+ if (isArrayFromMethod(parent.callee)) {
1702
+ return (
1703
+ parent.arguments.length !== 3 ||
1704
+ parent.arguments[1] !== currentNode ||
1705
+ isNullOrUndefined(parent.arguments[2])
1706
+ );
1707
+ }
1708
+ if (isMethodWhichHasThisArg(parent.callee)) {
1709
+ return (
1710
+ parent.arguments.length !== 2 ||
1711
+ parent.arguments[0] !== currentNode ||
1712
+ isNullOrUndefined(parent.arguments[1])
1713
+ );
1714
+ }
1715
+ return true;
1716
+
1717
+ // Otherwise `this` is default.
1718
+ default:
1719
+ return true;
1720
+ }
1721
+ }
1722
+
1723
+ /* c8 ignore next */
1724
+ return true;
1725
+ },
1726
+
1727
+ /**
1728
+ * Get the precedence level based on the node type
1729
+ * @param {ASTNode} node node to evaluate
1730
+ * @returns {number} precedence level
1731
+ * @private
1732
+ */
1733
+ getPrecedence(node) {
1734
+ switch (node.type) {
1735
+ case "SequenceExpression":
1736
+ return 0;
1737
+
1738
+ case "AssignmentExpression":
1739
+ case "ArrowFunctionExpression":
1740
+ case "YieldExpression":
1741
+ return 1;
1742
+
1743
+ case "ConditionalExpression":
1744
+ return 3;
1745
+
1746
+ case "LogicalExpression":
1747
+ switch (node.operator) {
1748
+ case "||":
1749
+ case "??":
1750
+ return 4;
1751
+ case "&&":
1752
+ return 5;
1753
+
1754
+ // no default
1755
+ }
1756
+
1757
+ /* falls through */
1758
+
1759
+ case "BinaryExpression":
1760
+ switch (node.operator) {
1761
+ case "|":
1762
+ return 6;
1763
+ case "^":
1764
+ return 7;
1765
+ case "&":
1766
+ return 8;
1767
+ case "==":
1768
+ case "!=":
1769
+ case "===":
1770
+ case "!==":
1771
+ return 9;
1772
+ case "<":
1773
+ case "<=":
1774
+ case ">":
1775
+ case ">=":
1776
+ case "in":
1777
+ case "instanceof":
1778
+ return 10;
1779
+ case "<<":
1780
+ case ">>":
1781
+ case ">>>":
1782
+ return 11;
1783
+ case "+":
1784
+ case "-":
1785
+ return 12;
1786
+ case "*":
1787
+ case "/":
1788
+ case "%":
1789
+ return 13;
1790
+ case "**":
1791
+ return 15;
1792
+
1793
+ // no default
1794
+ }
1795
+
1796
+ /* falls through */
1797
+
1798
+ case "UnaryExpression":
1799
+ case "AwaitExpression":
1800
+ return 16;
1801
+
1802
+ case "UpdateExpression":
1803
+ return 17;
1804
+
1805
+ case "CallExpression":
1806
+ case "ChainExpression":
1807
+ case "ImportExpression":
1808
+ return 18;
1809
+
1810
+ case "NewExpression":
1811
+ return 19;
1812
+
1813
+ default:
1814
+ if (node.type in eslintVisitorKeys) {
1815
+ return 20;
1816
+ }
1817
+
1818
+ /*
1819
+ * if the node is not a standard node that we know about, then assume it has the lowest precedence
1820
+ * this will mean that rules will wrap unknown nodes in parentheses where applicable instead of
1821
+ * unwrapping them and potentially changing the meaning of the code or introducing a syntax error.
1822
+ */
1823
+ return -1;
1824
+ }
1825
+ },
1826
+
1827
+ /**
1828
+ * Checks whether the given node is an empty block node or not.
1829
+ * @param {ASTNode|null} node The node to check.
1830
+ * @returns {boolean} `true` if the node is an empty block.
1831
+ */
1832
+ isEmptyBlock(node) {
1833
+ return Boolean(
1834
+ node && node.type === "BlockStatement" && node.body.length === 0,
1835
+ );
1836
+ },
1837
+
1838
+ /**
1839
+ * Checks whether the given node is an empty function node or not.
1840
+ * @param {ASTNode|null} node The node to check.
1841
+ * @returns {boolean} `true` if the node is an empty function.
1842
+ */
1843
+ isEmptyFunction(node) {
1844
+ return isFunction(node) && module.exports.isEmptyBlock(node.body);
1845
+ },
1846
+
1847
+ /**
1848
+ * Get directives from directive prologue of a Program or Function node.
1849
+ * @param {ASTNode} node The node to check.
1850
+ * @returns {ASTNode[]} The directives found in the directive prologue.
1851
+ */
1852
+ getDirectivePrologue(node) {
1853
+ const directives = [];
1854
+
1855
+ // Directive prologues only occur at the top of files or functions.
1856
+ if (
1857
+ node.type === "Program" ||
1858
+ node.type === "FunctionDeclaration" ||
1859
+ node.type === "FunctionExpression" ||
1860
+ /*
1861
+ * Do not check arrow functions with implicit return.
1862
+ * `() => "use strict";` returns the string `"use strict"`.
1863
+ */
1864
+ (node.type === "ArrowFunctionExpression" &&
1865
+ node.body.type === "BlockStatement")
1866
+ ) {
1867
+ const statements =
1868
+ node.type === "Program" ? node.body : node.body.body;
1869
+
1870
+ for (const statement of statements) {
1871
+ if (
1872
+ statement.type === "ExpressionStatement" &&
1873
+ statement.expression.type === "Literal"
1874
+ ) {
1875
+ directives.push(statement);
1876
+ } else {
1877
+ break;
1878
+ }
1879
+ }
1880
+ }
1881
+
1882
+ return directives;
1883
+ },
1884
+
1885
+ /**
1886
+ * Determines whether this node is a decimal integer literal. If a node is a decimal integer literal, a dot added
1887
+ * after the node will be parsed as a decimal point, rather than a property-access dot.
1888
+ * @param {ASTNode} node The node to check.
1889
+ * @returns {boolean} `true` if this node is a decimal integer.
1890
+ * @example
1891
+ *
1892
+ * 0 // true
1893
+ * 5 // true
1894
+ * 50 // true
1895
+ * 5_000 // true
1896
+ * 1_234_56 // true
1897
+ * 08 // true
1898
+ * 0192 // true
1899
+ * 5. // false
1900
+ * .5 // false
1901
+ * 5.0 // false
1902
+ * 5.00_00 // false
1903
+ * 05 // false
1904
+ * 0x5 // false
1905
+ * 0b101 // false
1906
+ * 0b11_01 // false
1907
+ * 0o5 // false
1908
+ * 5e0 // false
1909
+ * 5e1_000 // false
1910
+ * 5n // false
1911
+ * 1_000n // false
1912
+ * "5" // false
1913
+ *
1914
+ */
1915
+ isDecimalInteger(node) {
1916
+ return (
1917
+ node.type === "Literal" &&
1918
+ typeof node.value === "number" &&
1919
+ DECIMAL_INTEGER_PATTERN.test(node.raw)
1920
+ );
1921
+ },
1922
+
1923
+ /**
1924
+ * Determines whether this token is a decimal integer numeric token.
1925
+ * This is similar to isDecimalInteger(), but for tokens.
1926
+ * @param {Token} token The token to check.
1927
+ * @returns {boolean} `true` if this token is a decimal integer.
1928
+ */
1929
+ isDecimalIntegerNumericToken(token) {
1930
+ return (
1931
+ token.type === "Numeric" &&
1932
+ DECIMAL_INTEGER_PATTERN.test(token.value)
1933
+ );
1934
+ },
1935
+
1936
+ /**
1937
+ * Gets the name and kind of the given function node.
1938
+ *
1939
+ * - `function foo() {}` .................... `function 'foo'`
1940
+ * - `(function foo() {})` .................. `function 'foo'`
1941
+ * - `(function() {})` ...................... `function`
1942
+ * - `function* foo() {}` ................... `generator function 'foo'`
1943
+ * - `(function* foo() {})` ................. `generator function 'foo'`
1944
+ * - `(function*() {})` ..................... `generator function`
1945
+ * - `() => {}` ............................. `arrow function`
1946
+ * - `async () => {}` ....................... `async arrow function`
1947
+ * - `({ foo: function foo() {} })` ......... `method 'foo'`
1948
+ * - `({ foo: function() {} })` ............. `method 'foo'`
1949
+ * - `({ ['foo']: function() {} })` ......... `method 'foo'`
1950
+ * - `({ [foo]: function() {} })` ........... `method`
1951
+ * - `({ foo() {} })` ....................... `method 'foo'`
1952
+ * - `({ foo: function* foo() {} })` ........ `generator method 'foo'`
1953
+ * - `({ foo: function*() {} })` ............ `generator method 'foo'`
1954
+ * - `({ ['foo']: function*() {} })` ........ `generator method 'foo'`
1955
+ * - `({ [foo]: function*() {} })` .......... `generator method`
1956
+ * - `({ *foo() {} })` ...................... `generator method 'foo'`
1957
+ * - `({ foo: async function foo() {} })` ... `async method 'foo'`
1958
+ * - `({ foo: async function() {} })` ....... `async method 'foo'`
1959
+ * - `({ ['foo']: async function() {} })` ... `async method 'foo'`
1960
+ * - `({ [foo]: async function() {} })` ..... `async method`
1961
+ * - `({ async foo() {} })` ................. `async method 'foo'`
1962
+ * - `({ get foo() {} })` ................... `getter 'foo'`
1963
+ * - `({ set foo(a) {} })` .................. `setter 'foo'`
1964
+ * - `class A { constructor() {} }` ......... `constructor`
1965
+ * - `class A { foo() {} }` ................. `method 'foo'`
1966
+ * - `class A { *foo() {} }` ................ `generator method 'foo'`
1967
+ * - `class A { async foo() {} }` ........... `async method 'foo'`
1968
+ * - `class A { ['foo']() {} }` ............. `method 'foo'`
1969
+ * - `class A { *['foo']() {} }` ............ `generator method 'foo'`
1970
+ * - `class A { async ['foo']() {} }` ....... `async method 'foo'`
1971
+ * - `class A { [foo]() {} }` ............... `method`
1972
+ * - `class A { *[foo]() {} }` .............. `generator method`
1973
+ * - `class A { async [foo]() {} }` ......... `async method`
1974
+ * - `class A { get foo() {} }` ............. `getter 'foo'`
1975
+ * - `class A { set foo(a) {} }` ............ `setter 'foo'`
1976
+ * - `class A { static foo() {} }` .......... `static method 'foo'`
1977
+ * - `class A { static *foo() {} }` ......... `static generator method 'foo'`
1978
+ * - `class A { static async foo() {} }` .... `static async method 'foo'`
1979
+ * - `class A { static get foo() {} }` ...... `static getter 'foo'`
1980
+ * - `class A { static set foo(a) {} }` ..... `static setter 'foo'`
1981
+ * - `class A { foo = () => {}; }` .......... `method 'foo'`
1982
+ * - `class A { foo = function() {}; }` ..... `method 'foo'`
1983
+ * - `class A { foo = function bar() {}; }` . `method 'foo'`
1984
+ * - `class A { static foo = () => {}; }` ... `static method 'foo'`
1985
+ * - `class A { '#foo' = () => {}; }` ....... `method '#foo'`
1986
+ * - `class A { #foo = () => {}; }` ......... `private method #foo`
1987
+ * - `class A { static #foo = () => {}; }` .. `static private method #foo`
1988
+ * - `class A { '#foo'() {} }` .............. `method '#foo'`
1989
+ * - `class A { #foo() {} }` ................ `private method #foo`
1990
+ * - `class A { static #foo() {} }` ......... `static private method #foo`
1991
+ * @param {ASTNode} node The function node to get.
1992
+ * @returns {string} The name and kind of the function node.
1993
+ */
1994
+ getFunctionNameWithKind(node) {
1995
+ const parent = node.parent;
1996
+ const tokens = [];
1997
+
1998
+ if (
1999
+ parent.type === "MethodDefinition" ||
2000
+ parent.type === "PropertyDefinition" ||
2001
+ node.type === "TSPropertySignature" ||
2002
+ node.type === "TSMethodSignature"
2003
+ ) {
2004
+ // The proposal uses `static` word consistently before visibility words: https://github.com/tc39/proposal-static-class-features
2005
+ if (parent.static) {
2006
+ tokens.push("static");
2007
+ }
2008
+ if (!parent.computed && parent.key?.type === "PrivateIdentifier") {
2009
+ tokens.push("private");
2010
+ }
2011
+ }
2012
+ if (node.async) {
2013
+ tokens.push("async");
2014
+ }
2015
+ if (node.generator) {
2016
+ tokens.push("generator");
2017
+ }
2018
+
2019
+ if (parent.type === "Property" || parent.type === "MethodDefinition") {
2020
+ if (parent.kind === "constructor") {
2021
+ return "constructor";
2022
+ }
2023
+ if (parent.kind === "get") {
2024
+ tokens.push("getter");
2025
+ } else if (parent.kind === "set") {
2026
+ tokens.push("setter");
2027
+ } else {
2028
+ tokens.push("method");
2029
+ }
2030
+ } else if (node.type === "TSMethodSignature") {
2031
+ if (node.kind === "get") {
2032
+ tokens.push("getter");
2033
+ } else if (node.kind === "set") {
2034
+ tokens.push("setter");
2035
+ } else {
2036
+ tokens.push("method");
2037
+ }
2038
+ } else if (parent.type === "PropertyDefinition") {
2039
+ tokens.push("method");
2040
+ } else {
2041
+ if (node.type === "ArrowFunctionExpression") {
2042
+ tokens.push("arrow");
2043
+ }
2044
+ tokens.push("function");
2045
+ }
2046
+
2047
+ if (
2048
+ parent.type === "Property" ||
2049
+ parent.type === "MethodDefinition" ||
2050
+ parent.type === "PropertyDefinition"
2051
+ ) {
2052
+ if (!parent.computed && parent.key.type === "PrivateIdentifier") {
2053
+ tokens.push(`#${parent.key.name}`);
2054
+ } else {
2055
+ const name = getStaticPropertyName(parent);
2056
+
2057
+ if (name !== null) {
2058
+ tokens.push(`'${name}'`);
2059
+ } else if (node.id) {
2060
+ tokens.push(`'${node.id.name}'`);
2061
+ }
2062
+ }
2063
+ } else if (node.type === "TSMethodSignature") {
2064
+ tokens.push(`'${getStaticPropertyName(node)}'`);
2065
+ } else if (node.id) {
2066
+ tokens.push(`'${node.id.name}'`);
2067
+ }
2068
+
2069
+ return tokens.join(" ");
2070
+ },
2071
+
2072
+ /**
2073
+ * Gets the location of the given function node for reporting.
2074
+ *
2075
+ * - `function foo() {}`
2076
+ * ^^^^^^^^^^^^
2077
+ * - `(function foo() {})`
2078
+ * ^^^^^^^^^^^^
2079
+ * - `(function() {})`
2080
+ * ^^^^^^^^
2081
+ * - `function* foo() {}`
2082
+ * ^^^^^^^^^^^^^
2083
+ * - `(function* foo() {})`
2084
+ * ^^^^^^^^^^^^^
2085
+ * - `(function*() {})`
2086
+ * ^^^^^^^^^
2087
+ * - `() => {}`
2088
+ * ^^
2089
+ * - `async () => {}`
2090
+ * ^^
2091
+ * - `({ foo: function foo() {} })`
2092
+ * ^^^^^^^^^^^^^^^^^
2093
+ * - `({ foo: function() {} })`
2094
+ * ^^^^^^^^^^^^^
2095
+ * - `({ ['foo']: function() {} })`
2096
+ * ^^^^^^^^^^^^^^^^^
2097
+ * - `({ [foo]: function() {} })`
2098
+ * ^^^^^^^^^^^^^^^
2099
+ * - `({ foo() {} })`
2100
+ * ^^^
2101
+ * - `({ foo: function* foo() {} })`
2102
+ * ^^^^^^^^^^^^^^^^^^
2103
+ * - `({ foo: function*() {} })`
2104
+ * ^^^^^^^^^^^^^^
2105
+ * - `({ ['foo']: function*() {} })`
2106
+ * ^^^^^^^^^^^^^^^^^^
2107
+ * - `({ [foo]: function*() {} })`
2108
+ * ^^^^^^^^^^^^^^^^
2109
+ * - `({ *foo() {} })`
2110
+ * ^^^^
2111
+ * - `({ foo: async function foo() {} })`
2112
+ * ^^^^^^^^^^^^^^^^^^^^^^^
2113
+ * - `({ foo: async function() {} })`
2114
+ * ^^^^^^^^^^^^^^^^^^^
2115
+ * - `({ ['foo']: async function() {} })`
2116
+ * ^^^^^^^^^^^^^^^^^^^^^^^
2117
+ * - `({ [foo]: async function() {} })`
2118
+ * ^^^^^^^^^^^^^^^^^^^^^
2119
+ * - `({ async foo() {} })`
2120
+ * ^^^^^^^^^
2121
+ * - `({ get foo() {} })`
2122
+ * ^^^^^^^
2123
+ * - `({ set foo(a) {} })`
2124
+ * ^^^^^^^
2125
+ * - `class A { constructor() {} }`
2126
+ * ^^^^^^^^^^^
2127
+ * - `class A { foo() {} }`
2128
+ * ^^^
2129
+ * - `class A { *foo() {} }`
2130
+ * ^^^^
2131
+ * - `class A { async foo() {} }`
2132
+ * ^^^^^^^^^
2133
+ * - `class A { ['foo']() {} }`
2134
+ * ^^^^^^^
2135
+ * - `class A { *['foo']() {} }`
2136
+ * ^^^^^^^^
2137
+ * - `class A { async ['foo']() {} }`
2138
+ * ^^^^^^^^^^^^^
2139
+ * - `class A { [foo]() {} }`
2140
+ * ^^^^^
2141
+ * - `class A { *[foo]() {} }`
2142
+ * ^^^^^^
2143
+ * - `class A { async [foo]() {} }`
2144
+ * ^^^^^^^^^^^
2145
+ * - `class A { get foo() {} }`
2146
+ * ^^^^^^^
2147
+ * - `class A { set foo(a) {} }`
2148
+ * ^^^^^^^
2149
+ * - `class A { static foo() {} }`
2150
+ * ^^^^^^^^^^
2151
+ * - `class A { static *foo() {} }`
2152
+ * ^^^^^^^^^^^
2153
+ * - `class A { static async foo() {} }`
2154
+ * ^^^^^^^^^^^^^^^^
2155
+ * - `class A { static get foo() {} }`
2156
+ * ^^^^^^^^^^^^^^
2157
+ * - `class A { static set foo(a) {} }`
2158
+ * ^^^^^^^^^^^^^^
2159
+ * - `class A { foo = function() {} }`
2160
+ * ^^^^^^^^^^^^^^
2161
+ * - `class A { static foo = function() {} }`
2162
+ * ^^^^^^^^^^^^^^^^^^^^^
2163
+ * - `class A { foo = (a, b) => {} }`
2164
+ * ^^^^^^
2165
+ * @param {ASTNode} node The function node to get.
2166
+ * @param {SourceCode} sourceCode The source code object to get tokens.
2167
+ * @returns {string} The location of the function node for reporting.
2168
+ */
2169
+ getFunctionHeadLoc(node, sourceCode) {
2170
+ const parent = node.parent;
2171
+ let start;
2172
+ let end;
2173
+
2174
+ if (
2175
+ parent.type === "Property" ||
2176
+ parent.type === "MethodDefinition" ||
2177
+ parent.type === "PropertyDefinition" ||
2178
+ parent.type === "TSPropertySignature" ||
2179
+ parent.type === "TSMethodSignature"
2180
+ ) {
2181
+ start = parent.loc.start;
2182
+ end = getOpeningParenOfParams(node, sourceCode).loc.start;
2183
+ } else if (node.type === "ArrowFunctionExpression") {
2184
+ const arrowToken = sourceCode.getTokenBefore(
2185
+ node.body,
2186
+ isArrowToken,
2187
+ );
2188
+
2189
+ start = arrowToken.loc.start;
2190
+ end = arrowToken.loc.end;
2191
+ } else {
2192
+ start = node.loc.start;
2193
+ end = getOpeningParenOfParams(node, sourceCode).loc.start;
2194
+ }
2195
+
2196
+ return {
2197
+ start: Object.assign({}, start),
2198
+ end: Object.assign({}, end),
2199
+ };
2200
+ },
2201
+
2202
+ /**
2203
+ * Gets next location when the result is not out of bound, otherwise returns null.
2204
+ *
2205
+ * Assumptions:
2206
+ *
2207
+ * - The given location represents a valid location in the given source code.
2208
+ * - Columns are 0-based.
2209
+ * - Lines are 1-based.
2210
+ * - Column immediately after the last character in a line (not incl. linebreaks) is considered to be a valid location.
2211
+ * - If the source code ends with a linebreak, `sourceCode.lines` array will have an extra element (empty string) at the end.
2212
+ * The start (column 0) of that extra line is considered to be a valid location.
2213
+ *
2214
+ * Examples of successive locations (line, column):
2215
+ *
2216
+ * code: foo
2217
+ * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> null
2218
+ *
2219
+ * code: foo<LF>
2220
+ * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
2221
+ *
2222
+ * code: foo<CR><LF>
2223
+ * locations: (1, 0) -> (1, 1) -> (1, 2) -> (1, 3) -> (2, 0) -> null
2224
+ *
2225
+ * code: a<LF>b
2226
+ * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> null
2227
+ *
2228
+ * code: a<LF>b<LF>
2229
+ * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
2230
+ *
2231
+ * code: a<CR><LF>b<CR><LF>
2232
+ * locations: (1, 0) -> (1, 1) -> (2, 0) -> (2, 1) -> (3, 0) -> null
2233
+ *
2234
+ * code: a<LF><LF>
2235
+ * locations: (1, 0) -> (1, 1) -> (2, 0) -> (3, 0) -> null
2236
+ *
2237
+ * code: <LF>
2238
+ * locations: (1, 0) -> (2, 0) -> null
2239
+ *
2240
+ * code:
2241
+ * locations: (1, 0) -> null
2242
+ * @param {SourceCode} sourceCode The sourceCode
2243
+ * @param {{line: number, column: number}} location The location
2244
+ * @returns {{line: number, column: number} | null} Next location
2245
+ */
2246
+ getNextLocation(sourceCode, { line, column }) {
2247
+ if (column < sourceCode.lines[line - 1].length) {
2248
+ return {
2249
+ line,
2250
+ column: column + 1,
2251
+ };
2252
+ }
2253
+
2254
+ if (line < sourceCode.lines.length) {
2255
+ return {
2256
+ line: line + 1,
2257
+ column: 0,
2258
+ };
2259
+ }
2260
+
2261
+ return null;
2262
+ },
2263
+
2264
+ /**
2265
+ * Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
2266
+ * surrounding the node.
2267
+ * @param {SourceCode} sourceCode The source code object
2268
+ * @param {ASTNode} node An expression node
2269
+ * @returns {string} The text representing the node, with all surrounding parentheses included
2270
+ */
2271
+ getParenthesisedText(sourceCode, node) {
2272
+ let leftToken = sourceCode.getFirstToken(node);
2273
+ let rightToken = sourceCode.getLastToken(node);
2274
+
2275
+ while (
2276
+ sourceCode.getTokenBefore(leftToken) &&
2277
+ sourceCode.getTokenBefore(leftToken).type === "Punctuator" &&
2278
+ sourceCode.getTokenBefore(leftToken).value === "(" &&
2279
+ sourceCode.getTokenAfter(rightToken) &&
2280
+ sourceCode.getTokenAfter(rightToken).type === "Punctuator" &&
2281
+ sourceCode.getTokenAfter(rightToken).value === ")"
2282
+ ) {
2283
+ leftToken = sourceCode.getTokenBefore(leftToken);
2284
+ rightToken = sourceCode.getTokenAfter(rightToken);
2285
+ }
2286
+
2287
+ return sourceCode
2288
+ .getText()
2289
+ .slice(leftToken.range[0], rightToken.range[1]);
2290
+ },
2291
+
2292
+ /**
2293
+ * Determine if a node has a possibility to be an Error object
2294
+ * @param {ASTNode} node ASTNode to check
2295
+ * @returns {boolean} True if there is a chance it contains an Error obj
2296
+ */
2297
+ couldBeError(node) {
2298
+ switch (node.type) {
2299
+ case "Identifier":
2300
+ case "CallExpression":
2301
+ case "NewExpression":
2302
+ case "MemberExpression":
2303
+ case "TaggedTemplateExpression":
2304
+ case "YieldExpression":
2305
+ case "AwaitExpression":
2306
+ case "ChainExpression":
2307
+ return true; // possibly an error object.
2308
+
2309
+ case "AssignmentExpression":
2310
+ if (["=", "&&="].includes(node.operator)) {
2311
+ return module.exports.couldBeError(node.right);
2312
+ }
2313
+
2314
+ if (["||=", "??="].includes(node.operator)) {
2315
+ return (
2316
+ module.exports.couldBeError(node.left) ||
2317
+ module.exports.couldBeError(node.right)
2318
+ );
2319
+ }
2320
+
2321
+ /**
2322
+ * All other assignment operators are mathematical assignment operators (arithmetic or bitwise).
2323
+ * An assignment expression with a mathematical operator can either evaluate to a primitive value,
2324
+ * or throw, depending on the operands. Thus, it cannot evaluate to an `Error` object.
2325
+ */
2326
+ return false;
2327
+
2328
+ case "SequenceExpression": {
2329
+ const exprs = node.expressions;
2330
+
2331
+ return (
2332
+ exprs.length !== 0 &&
2333
+ module.exports.couldBeError(exprs.at(-1))
2334
+ );
2335
+ }
2336
+
2337
+ case "LogicalExpression":
2338
+ /*
2339
+ * If the && operator short-circuits, the left side was falsy and therefore not an error, and if it
2340
+ * doesn't short-circuit, it takes the value from the right side, so the right side must always be
2341
+ * a plausible error. A future improvement could verify that the left side could be truthy by
2342
+ * excluding falsy literals.
2343
+ */
2344
+ if (node.operator === "&&") {
2345
+ return module.exports.couldBeError(node.right);
2346
+ }
2347
+
2348
+ return (
2349
+ module.exports.couldBeError(node.left) ||
2350
+ module.exports.couldBeError(node.right)
2351
+ );
2352
+
2353
+ case "ConditionalExpression":
2354
+ return (
2355
+ module.exports.couldBeError(node.consequent) ||
2356
+ module.exports.couldBeError(node.alternate)
2357
+ );
2358
+
2359
+ default:
2360
+ return false;
2361
+ }
2362
+ },
2363
+
2364
+ /**
2365
+ * Check if a given node is a numeric literal or not.
2366
+ * @param {ASTNode} node The node to check.
2367
+ * @returns {boolean} `true` if the node is a number or bigint literal.
2368
+ */
2369
+ isNumericLiteral(node) {
2370
+ return (
2371
+ node.type === "Literal" &&
2372
+ (typeof node.value === "number" || Boolean(node.bigint))
2373
+ );
2374
+ },
2375
+
2376
+ /**
2377
+ * Determines whether two tokens can safely be placed next to each other without merging into a single token
2378
+ * @param {Token|string} leftValue The left token. If this is a string, it will be tokenized and the last token will be used.
2379
+ * @param {Token|string} rightValue The right token. If this is a string, it will be tokenized and the first token will be used.
2380
+ * @returns {boolean} If the tokens cannot be safely placed next to each other, returns `false`. If the tokens can be placed
2381
+ * next to each other, behavior is undefined (although it should return `true` in most cases).
2382
+ */
2383
+ canTokensBeAdjacent(leftValue, rightValue) {
2384
+ const espreeOptions = {
2385
+ ecmaVersion: espree.latestEcmaVersion,
2386
+ comment: true,
2387
+ range: true,
2388
+ };
2389
+
2390
+ let leftToken;
2391
+
2392
+ if (typeof leftValue === "string") {
2393
+ let tokens;
2394
+
2395
+ try {
2396
+ tokens = espree.tokenize(leftValue, espreeOptions);
2397
+ } catch {
2398
+ return false;
2399
+ }
2400
+
2401
+ const comments = tokens.comments;
2402
+
2403
+ leftToken = tokens.at(-1);
2404
+ if (comments.length) {
2405
+ const lastComment = comments.at(-1);
2406
+
2407
+ if (!leftToken || lastComment.range[0] > leftToken.range[0]) {
2408
+ leftToken = lastComment;
2409
+ }
2410
+ }
2411
+ } else {
2412
+ leftToken = leftValue;
2413
+ }
2414
+
2415
+ /*
2416
+ * If a hashbang comment was passed as a token object from SourceCode,
2417
+ * its type will be "Shebang" because of the way ESLint itself handles hashbangs.
2418
+ * If a hashbang comment was passed in a string and then tokenized in this function,
2419
+ * its type will be "Hashbang" because of the way Espree tokenizes hashbangs.
2420
+ */
2421
+ if (leftToken.type === "Shebang" || leftToken.type === "Hashbang") {
2422
+ return false;
2423
+ }
2424
+
2425
+ let rightToken;
2426
+
2427
+ if (typeof rightValue === "string") {
2428
+ let tokens;
2429
+
2430
+ try {
2431
+ tokens = espree.tokenize(rightValue, espreeOptions);
2432
+ } catch {
2433
+ return false;
2434
+ }
2435
+
2436
+ const comments = tokens.comments;
2437
+
2438
+ rightToken = tokens[0];
2439
+ if (comments.length) {
2440
+ const firstComment = comments[0];
2441
+
2442
+ if (
2443
+ !rightToken ||
2444
+ firstComment.range[0] < rightToken.range[0]
2445
+ ) {
2446
+ rightToken = firstComment;
2447
+ }
2448
+ }
2449
+ } else {
2450
+ rightToken = rightValue;
2451
+ }
2452
+
2453
+ if (
2454
+ leftToken.type === "Punctuator" ||
2455
+ rightToken.type === "Punctuator"
2456
+ ) {
2457
+ if (
2458
+ leftToken.type === "Punctuator" &&
2459
+ rightToken.type === "Punctuator"
2460
+ ) {
2461
+ const PLUS_TOKENS = new Set(["+", "++"]);
2462
+ const MINUS_TOKENS = new Set(["-", "--"]);
2463
+
2464
+ return !(
2465
+ (PLUS_TOKENS.has(leftToken.value) &&
2466
+ PLUS_TOKENS.has(rightToken.value)) ||
2467
+ (MINUS_TOKENS.has(leftToken.value) &&
2468
+ MINUS_TOKENS.has(rightToken.value))
2469
+ );
2470
+ }
2471
+ if (leftToken.type === "Punctuator" && leftToken.value === "/") {
2472
+ return !["Block", "Line", "RegularExpression"].includes(
2473
+ rightToken.type,
2474
+ );
2475
+ }
2476
+ return true;
2477
+ }
2478
+
2479
+ if (
2480
+ leftToken.type === "String" ||
2481
+ rightToken.type === "String" ||
2482
+ leftToken.type === "Template" ||
2483
+ rightToken.type === "Template"
2484
+ ) {
2485
+ return true;
2486
+ }
2487
+
2488
+ if (
2489
+ leftToken.type !== "Numeric" &&
2490
+ rightToken.type === "Numeric" &&
2491
+ rightToken.value.startsWith(".")
2492
+ ) {
2493
+ return true;
2494
+ }
2495
+
2496
+ if (
2497
+ leftToken.type === "Block" ||
2498
+ rightToken.type === "Block" ||
2499
+ rightToken.type === "Line"
2500
+ ) {
2501
+ return true;
2502
+ }
2503
+
2504
+ if (rightToken.type === "PrivateIdentifier") {
2505
+ return true;
2506
+ }
2507
+
2508
+ return false;
2509
+ },
2510
+
2511
+ /**
2512
+ * Get the `loc` object of a given name in a `/*globals` directive comment.
2513
+ * @param {SourceCode} sourceCode The source code to convert index to loc.
2514
+ * @param {Comment} comment The `/*globals` directive comment which include the name.
2515
+ * @param {string} name The name to find.
2516
+ * @returns {SourceLocation} The `loc` object.
2517
+ */
2518
+ getNameLocationInGlobalDirectiveComment(sourceCode, comment, name) {
2519
+ const namePattern = new RegExp(
2520
+ `[\\s,]${escapeRegExp(name)}(?:$|[\\s,:])`,
2521
+ "gu",
2522
+ );
2523
+
2524
+ // To ignore the first text "global".
2525
+ namePattern.lastIndex = comment.value.indexOf("global") + 6;
2526
+
2527
+ // Search a given variable name.
2528
+ const match = namePattern.exec(comment.value);
2529
+
2530
+ // Convert the index to loc.
2531
+ const start = sourceCode.getLocFromIndex(
2532
+ comment.range[0] + "/*".length + (match ? match.index + 1 : 0),
2533
+ );
2534
+ const end = {
2535
+ line: start.line,
2536
+ column: start.column + (match ? name.length : 1),
2537
+ };
2538
+
2539
+ return { start, end };
2540
+ },
2541
+
2542
+ /**
2543
+ * Determines whether the given raw string contains an octal escape sequence
2544
+ * or a non-octal decimal escape sequence ("\8", "\9").
2545
+ *
2546
+ * "\1", "\2" ... "\7", "\8", "\9"
2547
+ * "\00", "\01" ... "\07", "\08", "\09"
2548
+ *
2549
+ * "\0", when not followed by a digit, is not an octal escape sequence.
2550
+ * @param {string} rawString A string in its raw representation.
2551
+ * @returns {boolean} `true` if the string contains at least one octal escape sequence
2552
+ * or at least one non-octal decimal escape sequence.
2553
+ */
2554
+ hasOctalOrNonOctalDecimalEscapeSequence(rawString) {
2555
+ return OCTAL_OR_NON_OCTAL_DECIMAL_ESCAPE_PATTERN.test(rawString);
2556
+ },
2557
+
2558
+ /**
2559
+ * Determines whether the given node is a template literal without expressions.
2560
+ * @param {ASTNode} node Node to check.
2561
+ * @returns {boolean} True if the node is a template literal without expressions.
2562
+ */
2563
+ isStaticTemplateLiteral(node) {
2564
+ return node.type === "TemplateLiteral" && node.expressions.length === 0;
2565
+ },
2566
+
2567
+ /**
2568
+ * Determines whether the existing curly braces around the single statement are necessary to preserve the semantics of the code.
2569
+ * The braces, which make the given block body, are necessary in either of the following situations:
2570
+ *
2571
+ * 1. The statement is a lexical declaration.
2572
+ * 2. Without the braces, an `if` within the statement would become associated with an `else` after the closing brace:
2573
+ *
2574
+ * if (a) {
2575
+ * if (b)
2576
+ * foo();
2577
+ * }
2578
+ * else
2579
+ * bar();
2580
+ *
2581
+ * if (a)
2582
+ * while (b)
2583
+ * while (c) {
2584
+ * while (d)
2585
+ * if (e)
2586
+ * while(f)
2587
+ * foo();
2588
+ * }
2589
+ * else
2590
+ * bar();
2591
+ * @param {ASTNode} node `BlockStatement` body with exactly one statement directly inside. The statement can have its own nested statements.
2592
+ * @param {SourceCode} sourceCode The source code
2593
+ * @returns {boolean} `true` if the braces are necessary - removing them (replacing the given `BlockStatement` body with its single statement content)
2594
+ * would change the semantics of the code or produce a syntax error.
2595
+ */
2596
+ areBracesNecessary(node, sourceCode) {
2597
+ /**
2598
+ * Determines if the given node is a lexical declaration (let, const, using, await using, function, or class)
2599
+ * @param {ASTNode} nodeToCheck The node to check
2600
+ * @returns {boolean} True if the node is a lexical declaration
2601
+ * @private
2602
+ */
2603
+ function isLexicalDeclaration(nodeToCheck) {
2604
+ if (nodeToCheck.type === "VariableDeclaration") {
2605
+ return LEXICAL_DECLARATION_KINDS.has(nodeToCheck.kind);
2606
+ }
2607
+
2608
+ return (
2609
+ nodeToCheck.type === "FunctionDeclaration" ||
2610
+ nodeToCheck.type === "ClassDeclaration"
2611
+ );
2612
+ }
2613
+
2614
+ /**
2615
+ * Checks if the given token is an `else` token or not.
2616
+ * @param {Token} token The token to check.
2617
+ * @returns {boolean} `true` if the token is an `else` token.
2618
+ */
2619
+ function isElseKeywordToken(token) {
2620
+ return token.value === "else" && token.type === "Keyword";
2621
+ }
2622
+
2623
+ /**
2624
+ * Determines whether the given node has an `else` keyword token as the first token after.
2625
+ * @param {ASTNode} nodeToCheck The node to check.
2626
+ * @returns {boolean} `true` if the node is followed by an `else` keyword token.
2627
+ */
2628
+ function isFollowedByElseKeyword(nodeToCheck) {
2629
+ const nextToken = sourceCode.getTokenAfter(nodeToCheck);
2630
+
2631
+ return Boolean(nextToken) && isElseKeywordToken(nextToken);
2632
+ }
2633
+
2634
+ /**
2635
+ * Determines whether the code represented by the given node contains an `if` statement
2636
+ * that would become associated with an `else` keyword directly appended to that code.
2637
+ *
2638
+ * Examples where it returns `true`:
2639
+ *
2640
+ * if (a)
2641
+ * foo();
2642
+ *
2643
+ * if (a) {
2644
+ * foo();
2645
+ * }
2646
+ *
2647
+ * if (a)
2648
+ * foo();
2649
+ * else if (b)
2650
+ * bar();
2651
+ *
2652
+ * while (a)
2653
+ * if (b)
2654
+ * if(c)
2655
+ * foo();
2656
+ * else
2657
+ * bar();
2658
+ *
2659
+ * Examples where it returns `false`:
2660
+ *
2661
+ * if (a)
2662
+ * foo();
2663
+ * else
2664
+ * bar();
2665
+ *
2666
+ * while (a) {
2667
+ * if (b)
2668
+ * if(c)
2669
+ * foo();
2670
+ * else
2671
+ * bar();
2672
+ * }
2673
+ *
2674
+ * while (a)
2675
+ * if (b) {
2676
+ * if(c)
2677
+ * foo();
2678
+ * }
2679
+ * else
2680
+ * bar();
2681
+ * @param {ASTNode} nodeToCheck Node representing the code to check.
2682
+ * @returns {boolean} `true` if an `if` statement within the code would become associated with an `else` appended to that code.
2683
+ */
2684
+ function hasUnsafeIf(nodeToCheck) {
2685
+ switch (nodeToCheck.type) {
2686
+ case "IfStatement":
2687
+ if (!nodeToCheck.alternate) {
2688
+ return true;
2689
+ }
2690
+ return hasUnsafeIf(nodeToCheck.alternate);
2691
+ case "ForStatement":
2692
+ case "ForInStatement":
2693
+ case "ForOfStatement":
2694
+ case "LabeledStatement":
2695
+ case "WithStatement":
2696
+ case "WhileStatement":
2697
+ return hasUnsafeIf(nodeToCheck.body);
2698
+ default:
2699
+ return false;
2700
+ }
2701
+ }
2702
+
2703
+ const statement = node.body[0];
2704
+
2705
+ return (
2706
+ isLexicalDeclaration(statement) ||
2707
+ (hasUnsafeIf(statement) && isFollowedByElseKeyword(node))
2708
+ );
2709
+ },
2710
+
2711
+ isReferenceToGlobalVariable,
2712
+ isLogicalExpression,
2713
+ isCoalesceExpression,
2714
+ isMixedLogicalAndCoalesceExpressions,
2715
+ isNullLiteral,
2716
+ getStaticStringValue,
2717
+ getStaticPropertyName,
2718
+ skipChainExpression,
2719
+ isSpecificId,
2720
+ isSpecificMemberAccess,
2721
+ equalLiteralValue,
2722
+ isSameReference,
2723
+ isLogicalAssignmentOperator,
2724
+ getSwitchCaseColonToken,
2725
+ getModuleExportName,
2726
+ isConstant,
2727
+ isTopLevelExpressionStatement,
2728
+ isDirective,
2729
+ isStartOfExpressionStatement,
2730
+ needsPrecedingSemicolon,
2731
+ isImportAttributeKey,
2732
+ getOpeningParenOfParams,
2282
2733
  };