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
@@ -16,390 +16,435 @@ const FixTracker = require("./utils/fix-tracker");
16
16
  // Rule Definition
17
17
  //------------------------------------------------------------------------------
18
18
 
19
- /** @type {import('../shared/types').Rule} */
19
+ /** @type {import('../types').Rule.RuleModule} */
20
20
  module.exports = {
21
- meta: {
22
- type: "suggestion",
23
-
24
- docs: {
25
- description: "Disallow `else` blocks after `return` statements in `if` statements",
26
- recommended: false,
27
- url: "https://eslint.org/docs/latest/rules/no-else-return"
28
- },
29
-
30
- schema: [{
31
- type: "object",
32
- properties: {
33
- allowElseIf: {
34
- type: "boolean",
35
- default: true
36
- }
37
- },
38
- additionalProperties: false
39
- }],
40
-
41
- fixable: "code",
42
-
43
- messages: {
44
- unexpected: "Unnecessary 'else' after 'return'."
45
- }
46
- },
47
-
48
- create(context) {
49
-
50
- const sourceCode = context.sourceCode;
51
-
52
- //--------------------------------------------------------------------------
53
- // Helpers
54
- //--------------------------------------------------------------------------
55
-
56
- /**
57
- * Checks whether the given names can be safely used to declare block-scoped variables
58
- * in the given scope. Name collisions can produce redeclaration syntax errors,
59
- * or silently change references and modify behavior of the original code.
60
- *
61
- * This is not a generic function. In particular, it is assumed that the scope is a function scope or
62
- * a function's inner scope, and that the names can be valid identifiers in the given scope.
63
- * @param {string[]} names Array of variable names.
64
- * @param {eslint-scope.Scope} scope Function scope or a function's inner scope.
65
- * @returns {boolean} True if all names can be safely declared, false otherwise.
66
- */
67
- function isSafeToDeclare(names, scope) {
68
-
69
- if (names.length === 0) {
70
- return true;
71
- }
72
-
73
- const functionScope = scope.variableScope;
74
-
75
- /*
76
- * If this is a function scope, scope.variables will contain parameters, implicit variables such as "arguments",
77
- * all function-scoped variables ('var'), and block-scoped variables defined in the scope.
78
- * If this is an inner scope, scope.variables will contain block-scoped variables defined in the scope.
79
- *
80
- * Redeclaring any of these would cause a syntax error, except for the implicit variables.
81
- */
82
- const declaredVariables = scope.variables.filter(({ defs }) => defs.length > 0);
83
-
84
- if (declaredVariables.some(({ name }) => names.includes(name))) {
85
- return false;
86
- }
87
-
88
- // Redeclaring a catch variable would also cause a syntax error.
89
- if (scope !== functionScope && scope.upper.type === "catch") {
90
- if (scope.upper.variables.some(({ name }) => names.includes(name))) {
91
- return false;
92
- }
93
- }
94
-
95
- /*
96
- * Redeclaring an implicit variable, such as "arguments", would not cause a syntax error.
97
- * However, if the variable was used, declaring a new one with the same name would change references
98
- * and modify behavior.
99
- */
100
- const usedImplicitVariables = scope.variables.filter(({ defs, references }) =>
101
- defs.length === 0 && references.length > 0);
102
-
103
- if (usedImplicitVariables.some(({ name }) => names.includes(name))) {
104
- return false;
105
- }
106
-
107
- /*
108
- * Declaring a variable with a name that was already used to reference a variable from an upper scope
109
- * would change references and modify behavior.
110
- */
111
- if (scope.through.some(t => names.includes(t.identifier.name))) {
112
- return false;
113
- }
114
-
115
- /*
116
- * If the scope is an inner scope (not the function scope), an uninitialized `var` variable declared inside
117
- * the scope node (directly or in one of its descendants) is neither declared nor 'through' in the scope.
118
- *
119
- * For example, this would be a syntax error "Identifier 'a' has already been declared":
120
- * function foo() { if (bar) { let a; if (baz) { var a; } } }
121
- */
122
- if (scope !== functionScope) {
123
- const scopeNodeRange = scope.block.range;
124
- const variablesToCheck = functionScope.variables.filter(({ name }) => names.includes(name));
125
-
126
- if (variablesToCheck.some(v => v.defs.some(({ node: { range } }) =>
127
- scopeNodeRange[0] <= range[0] && range[1] <= scopeNodeRange[1]))) {
128
- return false;
129
- }
130
- }
131
-
132
- return true;
133
- }
134
-
135
-
136
- /**
137
- * Checks whether the removal of `else` and its braces is safe from variable name collisions.
138
- * @param {Node} node The 'else' node.
139
- * @param {eslint-scope.Scope} scope The scope in which the node and the whole 'if' statement is.
140
- * @returns {boolean} True if it is safe, false otherwise.
141
- */
142
- function isSafeFromNameCollisions(node, scope) {
143
-
144
- if (node.type === "FunctionDeclaration") {
145
-
146
- // Conditional function declaration. Scope and hoisting are unpredictable, different engines work differently.
147
- return false;
148
- }
149
-
150
- if (node.type !== "BlockStatement") {
151
- return true;
152
- }
153
-
154
- const elseBlockScope = scope.childScopes.find(({ block }) => block === node);
155
-
156
- if (!elseBlockScope) {
157
-
158
- // ecmaVersion < 6, `else` block statement cannot have its own scope, no possible collisions.
159
- return true;
160
- }
161
-
162
- /*
163
- * elseBlockScope is supposed to merge into its upper scope. elseBlockScope.variables array contains
164
- * only block-scoped variables (such as let and const variables or class and function declarations)
165
- * defined directly in the elseBlockScope. These are exactly the only names that could cause collisions.
166
- */
167
- const namesToCheck = elseBlockScope.variables.map(({ name }) => name);
168
-
169
- return isSafeToDeclare(namesToCheck, scope);
170
- }
171
-
172
- /**
173
- * Display the context report if rule is violated
174
- * @param {Node} elseNode The 'else' node
175
- * @returns {void}
176
- */
177
- function displayReport(elseNode) {
178
- const currentScope = sourceCode.getScope(elseNode.parent);
179
-
180
- context.report({
181
- node: elseNode,
182
- messageId: "unexpected",
183
- fix(fixer) {
184
-
185
- if (!isSafeFromNameCollisions(elseNode, currentScope)) {
186
- return null;
187
- }
188
-
189
- const startToken = sourceCode.getFirstToken(elseNode);
190
- const elseToken = sourceCode.getTokenBefore(startToken);
191
- const source = sourceCode.getText(elseNode);
192
- const lastIfToken = sourceCode.getTokenBefore(elseToken);
193
- let fixedSource, firstTokenOfElseBlock;
194
-
195
- if (startToken.type === "Punctuator" && startToken.value === "{") {
196
- firstTokenOfElseBlock = sourceCode.getTokenAfter(startToken);
197
- } else {
198
- firstTokenOfElseBlock = startToken;
199
- }
200
-
201
- /*
202
- * If the if block does not have curly braces and does not end in a semicolon
203
- * and the else block starts with (, [, /, +, ` or -, then it is not
204
- * safe to remove the else keyword, because ASI will not add a semicolon
205
- * after the if block
206
- */
207
- const ifBlockMaybeUnsafe = elseNode.parent.consequent.type !== "BlockStatement" && lastIfToken.value !== ";";
208
- const elseBlockUnsafe = /^[([/+`-]/u.test(firstTokenOfElseBlock.value);
209
-
210
- if (ifBlockMaybeUnsafe && elseBlockUnsafe) {
211
- return null;
212
- }
213
-
214
- const endToken = sourceCode.getLastToken(elseNode);
215
- const lastTokenOfElseBlock = sourceCode.getTokenBefore(endToken);
216
-
217
- if (lastTokenOfElseBlock.value !== ";") {
218
- const nextToken = sourceCode.getTokenAfter(endToken);
219
-
220
- const nextTokenUnsafe = nextToken && /^[([/+`-]/u.test(nextToken.value);
221
- const nextTokenOnSameLine = nextToken && nextToken.loc.start.line === lastTokenOfElseBlock.loc.start.line;
222
-
223
- /*
224
- * If the else block contents does not end in a semicolon,
225
- * and the else block starts with (, [, /, +, ` or -, then it is not
226
- * safe to remove the else block, because ASI will not add a semicolon
227
- * after the remaining else block contents
228
- */
229
- if (nextTokenUnsafe || (nextTokenOnSameLine && nextToken.value !== "}")) {
230
- return null;
231
- }
232
- }
233
-
234
- if (startToken.type === "Punctuator" && startToken.value === "{") {
235
- fixedSource = source.slice(1, -1);
236
- } else {
237
- fixedSource = source;
238
- }
239
-
240
- /*
241
- * Extend the replacement range to include the entire
242
- * function to avoid conflicting with no-useless-return.
243
- * https://github.com/eslint/eslint/issues/8026
244
- *
245
- * Also, to avoid name collisions between two else blocks.
246
- */
247
- return new FixTracker(fixer, sourceCode)
248
- .retainEnclosingFunction(elseNode)
249
- .replaceTextRange([elseToken.range[0], elseNode.range[1]], fixedSource);
250
- }
251
- });
252
- }
253
-
254
- /**
255
- * Check to see if the node is a ReturnStatement
256
- * @param {Node} node The node being evaluated
257
- * @returns {boolean} True if node is a return
258
- */
259
- function checkForReturn(node) {
260
- return node.type === "ReturnStatement";
261
- }
262
-
263
- /**
264
- * Naive return checking, does not iterate through the whole
265
- * BlockStatement because we make the assumption that the ReturnStatement
266
- * will be the last node in the body of the BlockStatement.
267
- * @param {Node} node The consequent/alternate node
268
- * @returns {boolean} True if it has a return
269
- */
270
- function naiveHasReturn(node) {
271
- if (node.type === "BlockStatement") {
272
- const body = node.body,
273
- lastChildNode = body[body.length - 1];
274
-
275
- return lastChildNode && checkForReturn(lastChildNode);
276
- }
277
- return checkForReturn(node);
278
- }
279
-
280
- /**
281
- * Check to see if the node is valid for evaluation,
282
- * meaning it has an else.
283
- * @param {Node} node The node being evaluated
284
- * @returns {boolean} True if the node is valid
285
- */
286
- function hasElse(node) {
287
- return node.alternate && node.consequent;
288
- }
289
-
290
- /**
291
- * If the consequent is an IfStatement, check to see if it has an else
292
- * and both its consequent and alternate path return, meaning this is
293
- * a nested case of rule violation. If-Else not considered currently.
294
- * @param {Node} node The consequent node
295
- * @returns {boolean} True if this is a nested rule violation
296
- */
297
- function checkForIf(node) {
298
- return node.type === "IfStatement" && hasElse(node) &&
299
- naiveHasReturn(node.alternate) && naiveHasReturn(node.consequent);
300
- }
301
-
302
- /**
303
- * Check the consequent/body node to make sure it is not
304
- * a ReturnStatement or an IfStatement that returns on both
305
- * code paths.
306
- * @param {Node} node The consequent or body node
307
- * @returns {boolean} `true` if it is a Return/If node that always returns.
308
- */
309
- function checkForReturnOrIf(node) {
310
- return checkForReturn(node) || checkForIf(node);
311
- }
312
-
313
-
314
- /**
315
- * Check whether a node returns in every codepath.
316
- * @param {Node} node The node to be checked
317
- * @returns {boolean} `true` if it returns on every codepath.
318
- */
319
- function alwaysReturns(node) {
320
- if (node.type === "BlockStatement") {
321
-
322
- // If we have a BlockStatement, check each consequent body node.
323
- return node.body.some(checkForReturnOrIf);
324
- }
325
-
326
- /*
327
- * If not a block statement, make sure the consequent isn't a
328
- * ReturnStatement or an IfStatement with returns on both paths.
329
- */
330
- return checkForReturnOrIf(node);
331
- }
332
-
333
-
334
- /**
335
- * Check the if statement, but don't catch else-if blocks.
336
- * @returns {void}
337
- * @param {Node} node The node for the if statement to check
338
- * @private
339
- */
340
- function checkIfWithoutElse(node) {
341
- const parent = node.parent;
342
-
343
- /*
344
- * Fixing this would require splitting one statement into two, so no error should
345
- * be reported if this node is in a position where only one statement is allowed.
346
- */
347
- if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
348
- return;
349
- }
350
-
351
- const consequents = [];
352
- let alternate;
353
-
354
- for (let currentNode = node; currentNode.type === "IfStatement"; currentNode = currentNode.alternate) {
355
- if (!currentNode.alternate) {
356
- return;
357
- }
358
- consequents.push(currentNode.consequent);
359
- alternate = currentNode.alternate;
360
- }
361
-
362
- if (consequents.every(alwaysReturns)) {
363
- displayReport(alternate);
364
- }
365
- }
366
-
367
- /**
368
- * Check the if statement
369
- * @returns {void}
370
- * @param {Node} node The node for the if statement to check
371
- * @private
372
- */
373
- function checkIfWithElse(node) {
374
- const parent = node.parent;
375
-
376
-
377
- /*
378
- * Fixing this would require splitting one statement into two, so no error should
379
- * be reported if this node is in a position where only one statement is allowed.
380
- */
381
- if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
382
- return;
383
- }
384
-
385
- const alternate = node.alternate;
386
-
387
- if (alternate && alwaysReturns(node.consequent)) {
388
- displayReport(alternate);
389
- }
390
- }
391
-
392
- const allowElseIf = !(context.options[0] && context.options[0].allowElseIf === false);
393
-
394
- //--------------------------------------------------------------------------
395
- // Public API
396
- //--------------------------------------------------------------------------
397
-
398
- return {
399
-
400
- "IfStatement:exit": allowElseIf ? checkIfWithoutElse : checkIfWithElse
401
-
402
- };
403
-
404
- }
21
+ meta: {
22
+ type: "suggestion",
23
+
24
+ defaultOptions: [{ allowElseIf: true }],
25
+
26
+ docs: {
27
+ description:
28
+ "Disallow `else` blocks after `return` statements in `if` statements",
29
+ recommended: false,
30
+ frozen: true,
31
+ url: "https://eslint.org/docs/latest/rules/no-else-return",
32
+ },
33
+
34
+ schema: [
35
+ {
36
+ type: "object",
37
+ properties: {
38
+ allowElseIf: {
39
+ type: "boolean",
40
+ },
41
+ },
42
+ additionalProperties: false,
43
+ },
44
+ ],
45
+
46
+ fixable: "code",
47
+
48
+ messages: {
49
+ unexpected: "Unnecessary 'else' after 'return'.",
50
+ },
51
+ },
52
+
53
+ create(context) {
54
+ const [{ allowElseIf }] = context.options;
55
+ const sourceCode = context.sourceCode;
56
+
57
+ //--------------------------------------------------------------------------
58
+ // Helpers
59
+ //--------------------------------------------------------------------------
60
+
61
+ /**
62
+ * Checks whether the given names can be safely used to declare block-scoped variables
63
+ * in the given scope. Name collisions can produce redeclaration syntax errors,
64
+ * or silently change references and modify behavior of the original code.
65
+ *
66
+ * This is not a generic function. In particular, it is assumed that the scope is a function scope or
67
+ * a function's inner scope, and that the names can be valid identifiers in the given scope.
68
+ * @param {string[]} names Array of variable names.
69
+ * @param {eslint-scope.Scope} scope Function scope or a function's inner scope.
70
+ * @returns {boolean} True if all names can be safely declared, false otherwise.
71
+ */
72
+ function isSafeToDeclare(names, scope) {
73
+ if (names.length === 0) {
74
+ return true;
75
+ }
76
+
77
+ const functionScope = scope.variableScope;
78
+
79
+ /*
80
+ * If this is a function scope, scope.variables will contain parameters, implicit variables such as "arguments",
81
+ * all function-scoped variables ('var'), and block-scoped variables defined in the scope.
82
+ * If this is an inner scope, scope.variables will contain block-scoped variables defined in the scope.
83
+ *
84
+ * Redeclaring any of these would cause a syntax error, except for the implicit variables.
85
+ */
86
+ const declaredVariables = scope.variables.filter(
87
+ ({ defs }) => defs.length > 0,
88
+ );
89
+
90
+ if (declaredVariables.some(({ name }) => names.includes(name))) {
91
+ return false;
92
+ }
93
+
94
+ // Redeclaring a catch variable would also cause a syntax error.
95
+ if (scope !== functionScope && scope.upper.type === "catch") {
96
+ if (
97
+ scope.upper.variables.some(({ name }) =>
98
+ names.includes(name),
99
+ )
100
+ ) {
101
+ return false;
102
+ }
103
+ }
104
+
105
+ /*
106
+ * Redeclaring an implicit variable, such as "arguments", would not cause a syntax error.
107
+ * However, if the variable was used, declaring a new one with the same name would change references
108
+ * and modify behavior.
109
+ */
110
+ const usedImplicitVariables = scope.variables.filter(
111
+ ({ defs, references }) =>
112
+ defs.length === 0 && references.length > 0,
113
+ );
114
+
115
+ if (
116
+ usedImplicitVariables.some(({ name }) => names.includes(name))
117
+ ) {
118
+ return false;
119
+ }
120
+
121
+ /*
122
+ * Declaring a variable with a name that was already used to reference a variable from an upper scope
123
+ * would change references and modify behavior.
124
+ */
125
+ if (scope.through.some(t => names.includes(t.identifier.name))) {
126
+ return false;
127
+ }
128
+
129
+ /*
130
+ * If the scope is an inner scope (not the function scope), an uninitialized `var` variable declared inside
131
+ * the scope node (directly or in one of its descendants) is neither declared nor 'through' in the scope.
132
+ *
133
+ * For example, this would be a syntax error "Identifier 'a' has already been declared":
134
+ * function foo() { if (bar) { let a; if (baz) { var a; } } }
135
+ */
136
+ if (scope !== functionScope) {
137
+ const scopeNodeRange = scope.block.range;
138
+ const variablesToCheck = functionScope.variables.filter(
139
+ ({ name }) => names.includes(name),
140
+ );
141
+
142
+ if (
143
+ variablesToCheck.some(v =>
144
+ v.defs.some(
145
+ ({ node: { range } }) =>
146
+ scopeNodeRange[0] <= range[0] &&
147
+ range[1] <= scopeNodeRange[1],
148
+ ),
149
+ )
150
+ ) {
151
+ return false;
152
+ }
153
+ }
154
+
155
+ return true;
156
+ }
157
+
158
+ /**
159
+ * Checks whether the removal of `else` and its braces is safe from variable name collisions.
160
+ * @param {Node} node The 'else' node.
161
+ * @param {eslint-scope.Scope} scope The scope in which the node and the whole 'if' statement is.
162
+ * @returns {boolean} True if it is safe, false otherwise.
163
+ */
164
+ function isSafeFromNameCollisions(node, scope) {
165
+ if (node.type === "FunctionDeclaration") {
166
+ // Conditional function declaration. Scope and hoisting are unpredictable, different engines work differently.
167
+ return false;
168
+ }
169
+
170
+ if (node.type !== "BlockStatement") {
171
+ return true;
172
+ }
173
+
174
+ const elseBlockScope = scope.childScopes.find(
175
+ ({ block }) => block === node,
176
+ );
177
+
178
+ if (!elseBlockScope) {
179
+ // ecmaVersion < 6, `else` block statement cannot have its own scope, no possible collisions.
180
+ return true;
181
+ }
182
+
183
+ /*
184
+ * elseBlockScope is supposed to merge into its upper scope. elseBlockScope.variables array contains
185
+ * only block-scoped variables (such as let and const variables or class and function declarations)
186
+ * defined directly in the elseBlockScope. These are exactly the only names that could cause collisions.
187
+ */
188
+ const namesToCheck = elseBlockScope.variables.map(
189
+ ({ name }) => name,
190
+ );
191
+
192
+ return isSafeToDeclare(namesToCheck, scope);
193
+ }
194
+
195
+ /**
196
+ * Display the context report if rule is violated
197
+ * @param {Node} elseNode The 'else' node
198
+ * @returns {void}
199
+ */
200
+ function displayReport(elseNode) {
201
+ const currentScope = sourceCode.getScope(elseNode.parent);
202
+
203
+ context.report({
204
+ node: elseNode,
205
+ messageId: "unexpected",
206
+ fix(fixer) {
207
+ if (!isSafeFromNameCollisions(elseNode, currentScope)) {
208
+ return null;
209
+ }
210
+
211
+ const startToken = sourceCode.getFirstToken(elseNode);
212
+ const elseToken = sourceCode.getTokenBefore(startToken);
213
+ const source = sourceCode.getText(elseNode);
214
+ const lastIfToken = sourceCode.getTokenBefore(elseToken);
215
+ let fixedSource, firstTokenOfElseBlock;
216
+
217
+ if (
218
+ startToken.type === "Punctuator" &&
219
+ startToken.value === "{"
220
+ ) {
221
+ firstTokenOfElseBlock =
222
+ sourceCode.getTokenAfter(startToken);
223
+ } else {
224
+ firstTokenOfElseBlock = startToken;
225
+ }
226
+
227
+ /*
228
+ * If the if block does not have curly braces and does not end in a semicolon
229
+ * and the else block starts with (, [, /, +, ` or -, then it is not
230
+ * safe to remove the else keyword, because ASI will not add a semicolon
231
+ * after the if block
232
+ */
233
+ const ifBlockMaybeUnsafe =
234
+ elseNode.parent.consequent.type !== "BlockStatement" &&
235
+ lastIfToken.value !== ";";
236
+ const elseBlockUnsafe = /^[([/+`-]/u.test(
237
+ firstTokenOfElseBlock.value,
238
+ );
239
+
240
+ if (ifBlockMaybeUnsafe && elseBlockUnsafe) {
241
+ return null;
242
+ }
243
+
244
+ const endToken = sourceCode.getLastToken(elseNode);
245
+ const lastTokenOfElseBlock =
246
+ sourceCode.getTokenBefore(endToken);
247
+
248
+ if (lastTokenOfElseBlock.value !== ";") {
249
+ const nextToken = sourceCode.getTokenAfter(endToken);
250
+
251
+ const nextTokenUnsafe =
252
+ nextToken && /^[([/+`-]/u.test(nextToken.value);
253
+ const nextTokenOnSameLine =
254
+ nextToken &&
255
+ nextToken.loc.start.line ===
256
+ lastTokenOfElseBlock.loc.start.line;
257
+
258
+ /*
259
+ * If the else block contents does not end in a semicolon,
260
+ * and the else block starts with (, [, /, +, ` or -, then it is not
261
+ * safe to remove the else block, because ASI will not add a semicolon
262
+ * after the remaining else block contents
263
+ */
264
+ if (
265
+ nextTokenUnsafe ||
266
+ (nextTokenOnSameLine && nextToken.value !== "}")
267
+ ) {
268
+ return null;
269
+ }
270
+ }
271
+
272
+ if (
273
+ startToken.type === "Punctuator" &&
274
+ startToken.value === "{"
275
+ ) {
276
+ fixedSource = source.slice(1, -1);
277
+ } else {
278
+ fixedSource = source;
279
+ }
280
+
281
+ /*
282
+ * Extend the replacement range to include the entire
283
+ * function to avoid conflicting with no-useless-return.
284
+ * https://github.com/eslint/eslint/issues/8026
285
+ *
286
+ * Also, to avoid name collisions between two else blocks.
287
+ */
288
+ return new FixTracker(fixer, sourceCode)
289
+ .retainEnclosingFunction(elseNode)
290
+ .replaceTextRange(
291
+ [elseToken.range[0], elseNode.range[1]],
292
+ fixedSource,
293
+ );
294
+ },
295
+ });
296
+ }
297
+
298
+ /**
299
+ * Check to see if the node is a ReturnStatement
300
+ * @param {Node} node The node being evaluated
301
+ * @returns {boolean} True if node is a return
302
+ */
303
+ function checkForReturn(node) {
304
+ return node.type === "ReturnStatement";
305
+ }
306
+
307
+ /**
308
+ * Naive return checking, does not iterate through the whole
309
+ * BlockStatement because we make the assumption that the ReturnStatement
310
+ * will be the last node in the body of the BlockStatement.
311
+ * @param {Node} node The consequent/alternate node
312
+ * @returns {boolean} True if it has a return
313
+ */
314
+ function naiveHasReturn(node) {
315
+ if (node.type === "BlockStatement") {
316
+ const body = node.body,
317
+ lastChildNode = body.at(-1);
318
+
319
+ return lastChildNode && checkForReturn(lastChildNode);
320
+ }
321
+ return checkForReturn(node);
322
+ }
323
+
324
+ /**
325
+ * Check to see if the node is valid for evaluation,
326
+ * meaning it has an else.
327
+ * @param {Node} node The node being evaluated
328
+ * @returns {boolean} True if the node is valid
329
+ */
330
+ function hasElse(node) {
331
+ return node.alternate && node.consequent;
332
+ }
333
+
334
+ /**
335
+ * If the consequent is an IfStatement, check to see if it has an else
336
+ * and both its consequent and alternate path return, meaning this is
337
+ * a nested case of rule violation. If-Else not considered currently.
338
+ * @param {Node} node The consequent node
339
+ * @returns {boolean} True if this is a nested rule violation
340
+ */
341
+ function checkForIf(node) {
342
+ return (
343
+ node.type === "IfStatement" &&
344
+ hasElse(node) &&
345
+ naiveHasReturn(node.alternate) &&
346
+ naiveHasReturn(node.consequent)
347
+ );
348
+ }
349
+
350
+ /**
351
+ * Check the consequent/body node to make sure it is not
352
+ * a ReturnStatement or an IfStatement that returns on both
353
+ * code paths.
354
+ * @param {Node} node The consequent or body node
355
+ * @returns {boolean} `true` if it is a Return/If node that always returns.
356
+ */
357
+ function checkForReturnOrIf(node) {
358
+ return checkForReturn(node) || checkForIf(node);
359
+ }
360
+
361
+ /**
362
+ * Check whether a node returns in every codepath.
363
+ * @param {Node} node The node to be checked
364
+ * @returns {boolean} `true` if it returns on every codepath.
365
+ */
366
+ function alwaysReturns(node) {
367
+ if (node.type === "BlockStatement") {
368
+ // If we have a BlockStatement, check each consequent body node.
369
+ return node.body.some(checkForReturnOrIf);
370
+ }
371
+
372
+ /*
373
+ * If not a block statement, make sure the consequent isn't a
374
+ * ReturnStatement or an IfStatement with returns on both paths.
375
+ */
376
+ return checkForReturnOrIf(node);
377
+ }
378
+
379
+ /**
380
+ * Check the if statement, but don't catch else-if blocks.
381
+ * @returns {void}
382
+ * @param {Node} node The node for the if statement to check
383
+ * @private
384
+ */
385
+ function checkIfWithoutElse(node) {
386
+ const parent = node.parent;
387
+
388
+ /*
389
+ * Fixing this would require splitting one statement into two, so no error should
390
+ * be reported if this node is in a position where only one statement is allowed.
391
+ */
392
+ if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
393
+ return;
394
+ }
395
+
396
+ const consequents = [];
397
+ let alternate;
398
+
399
+ for (
400
+ let currentNode = node;
401
+ currentNode.type === "IfStatement";
402
+ currentNode = currentNode.alternate
403
+ ) {
404
+ if (!currentNode.alternate) {
405
+ return;
406
+ }
407
+ consequents.push(currentNode.consequent);
408
+ alternate = currentNode.alternate;
409
+ }
410
+
411
+ if (consequents.every(alwaysReturns)) {
412
+ displayReport(alternate);
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Check the if statement
418
+ * @returns {void}
419
+ * @param {Node} node The node for the if statement to check
420
+ * @private
421
+ */
422
+ function checkIfWithElse(node) {
423
+ const parent = node.parent;
424
+
425
+ /*
426
+ * Fixing this would require splitting one statement into two, so no error should
427
+ * be reported if this node is in a position where only one statement is allowed.
428
+ */
429
+ if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
430
+ return;
431
+ }
432
+
433
+ const alternate = node.alternate;
434
+
435
+ if (alternate && alwaysReturns(node.consequent)) {
436
+ displayReport(alternate);
437
+ }
438
+ }
439
+
440
+ //--------------------------------------------------------------------------
441
+ // Public API
442
+ //--------------------------------------------------------------------------
443
+
444
+ return {
445
+ "IfStatement:exit": allowElseIf
446
+ ? checkIfWithoutElse
447
+ : checkIfWithElse,
448
+ };
449
+ },
405
450
  };