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
@@ -17,394 +17,834 @@ const astUtils = require("./utils/ast-utils");
17
17
  const ignore = require("ignore");
18
18
 
19
19
  const arrayOfStringsOrObjects = {
20
- type: "array",
21
- items: {
22
- anyOf: [
23
- { type: "string" },
24
- {
25
- type: "object",
26
- properties: {
27
- name: { type: "string" },
28
- message: {
29
- type: "string",
30
- minLength: 1
31
- },
32
- importNames: {
33
- type: "array",
34
- items: {
35
- type: "string"
36
- }
37
- }
38
- },
39
- additionalProperties: false,
40
- required: ["name"]
41
- }
42
- ]
43
- },
44
- uniqueItems: true
20
+ type: "array",
21
+ items: {
22
+ anyOf: [
23
+ { type: "string" },
24
+ {
25
+ type: "object",
26
+ properties: {
27
+ name: { type: "string" },
28
+ message: {
29
+ type: "string",
30
+ minLength: 1,
31
+ },
32
+ importNames: {
33
+ type: "array",
34
+ items: {
35
+ type: "string",
36
+ },
37
+ },
38
+ allowImportNames: {
39
+ type: "array",
40
+ items: {
41
+ type: "string",
42
+ },
43
+ },
44
+ allowTypeImports: {
45
+ type: "boolean",
46
+ description:
47
+ "Whether to allow type-only imports for a path.",
48
+ },
49
+ },
50
+ additionalProperties: false,
51
+ required: ["name"],
52
+ not: { required: ["importNames", "allowImportNames"] },
53
+ },
54
+ ],
55
+ },
56
+ uniqueItems: true,
45
57
  };
46
58
 
47
59
  const arrayOfStringsOrObjectPatterns = {
48
- anyOf: [
49
- {
50
- type: "array",
51
- items: {
52
- type: "string"
53
- },
54
- uniqueItems: true
55
- },
56
- {
57
- type: "array",
58
- items: {
59
- type: "object",
60
- properties: {
61
- importNames: {
62
- type: "array",
63
- items: {
64
- type: "string"
65
- },
66
- minItems: 1,
67
- uniqueItems: true
68
- },
69
- group: {
70
- type: "array",
71
- items: {
72
- type: "string"
73
- },
74
- minItems: 1,
75
- uniqueItems: true
76
- },
77
- importNamePattern: {
78
- type: "string"
79
- },
80
- message: {
81
- type: "string",
82
- minLength: 1
83
- },
84
- caseSensitive: {
85
- type: "boolean"
86
- }
87
- },
88
- additionalProperties: false,
89
- required: ["group"]
90
- },
91
- uniqueItems: true
92
- }
93
- ]
60
+ anyOf: [
61
+ {
62
+ type: "array",
63
+ items: {
64
+ type: "string",
65
+ },
66
+ uniqueItems: true,
67
+ },
68
+ {
69
+ type: "array",
70
+ items: {
71
+ type: "object",
72
+ properties: {
73
+ importNames: {
74
+ type: "array",
75
+ items: {
76
+ type: "string",
77
+ },
78
+ minItems: 1,
79
+ uniqueItems: true,
80
+ },
81
+ allowImportNames: {
82
+ type: "array",
83
+ items: {
84
+ type: "string",
85
+ },
86
+ minItems: 1,
87
+ uniqueItems: true,
88
+ },
89
+ group: {
90
+ type: "array",
91
+ items: {
92
+ type: "string",
93
+ },
94
+ minItems: 1,
95
+ uniqueItems: true,
96
+ },
97
+ regex: {
98
+ type: "string",
99
+ },
100
+ importNamePattern: {
101
+ type: "string",
102
+ },
103
+ allowImportNamePattern: {
104
+ type: "string",
105
+ },
106
+ message: {
107
+ type: "string",
108
+ minLength: 1,
109
+ },
110
+ caseSensitive: {
111
+ type: "boolean",
112
+ },
113
+ allowTypeImports: {
114
+ type: "boolean",
115
+ description:
116
+ "Whether to allow type-only imports for a pattern.",
117
+ },
118
+ },
119
+ additionalProperties: false,
120
+ not: {
121
+ anyOf: [
122
+ { required: ["importNames", "allowImportNames"] },
123
+ {
124
+ required: [
125
+ "importNamePattern",
126
+ "allowImportNamePattern",
127
+ ],
128
+ },
129
+ { required: ["importNames", "allowImportNamePattern"] },
130
+ { required: ["importNamePattern", "allowImportNames"] },
131
+ {
132
+ required: [
133
+ "allowImportNames",
134
+ "allowImportNamePattern",
135
+ ],
136
+ },
137
+ ],
138
+ },
139
+ oneOf: [{ required: ["group"] }, { required: ["regex"] }],
140
+ },
141
+ uniqueItems: true,
142
+ },
143
+ ],
94
144
  };
95
145
 
96
- /** @type {import('../shared/types').Rule} */
146
+ /** @type {import('../types').Rule.RuleModule} */
97
147
  module.exports = {
98
- meta: {
99
- type: "suggestion",
100
-
101
- docs: {
102
- description: "Disallow specified modules when loaded by `import`",
103
- recommended: false,
104
- url: "https://eslint.org/docs/latest/rules/no-restricted-imports"
105
- },
106
-
107
- messages: {
108
- path: "'{{importSource}}' import is restricted from being used.",
109
- // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
110
- pathWithCustomMessage: "'{{importSource}}' import is restricted from being used. {{customMessage}}",
111
-
112
- patterns: "'{{importSource}}' import is restricted from being used by a pattern.",
113
- // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
114
- patternWithCustomMessage: "'{{importSource}}' import is restricted from being used by a pattern. {{customMessage}}",
115
-
116
- patternAndImportName: "'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern.",
117
- // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
118
- patternAndImportNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
119
-
120
- patternAndEverything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern.",
121
-
122
- patternAndEverythingWithRegexImportName: "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used.",
123
- // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
124
- patternAndEverythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
125
- // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
126
- patternAndEverythingWithRegexImportNameAndCustomMessage: "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used. {{customMessage}}",
127
-
128
- everything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.",
129
- // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
130
- everythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted. {{customMessage}}",
131
-
132
- importName: "'{{importName}}' import from '{{importSource}}' is restricted.",
133
- // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
134
- importNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}"
135
- },
136
-
137
- schema: {
138
- anyOf: [
139
- arrayOfStringsOrObjects,
140
- {
141
- type: "array",
142
- items: [{
143
- type: "object",
144
- properties: {
145
- paths: arrayOfStringsOrObjects,
146
- patterns: arrayOfStringsOrObjectPatterns
147
- },
148
- additionalProperties: false
149
- }],
150
- additionalItems: false
151
- }
152
- ]
153
- }
154
- },
155
-
156
- create(context) {
157
- const sourceCode = context.sourceCode;
158
- const options = Array.isArray(context.options) ? context.options : [];
159
- const isPathAndPatternsObject =
160
- typeof options[0] === "object" &&
161
- (Object.prototype.hasOwnProperty.call(options[0], "paths") || Object.prototype.hasOwnProperty.call(options[0], "patterns"));
162
-
163
- const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
164
- const restrictedPathMessages = restrictedPaths.reduce((memo, importSource) => {
165
- if (typeof importSource === "string") {
166
- memo[importSource] = { message: null };
167
- } else {
168
- memo[importSource.name] = {
169
- message: importSource.message,
170
- importNames: importSource.importNames
171
- };
172
- }
173
- return memo;
174
- }, {});
175
-
176
- // Handle patterns too, either as strings or groups
177
- let restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
178
-
179
- // standardize to array of objects if we have an array of strings
180
- if (restrictedPatterns.length > 0 && typeof restrictedPatterns[0] === "string") {
181
- restrictedPatterns = [{ group: restrictedPatterns }];
182
- }
183
-
184
- // relative paths are supported for this rule
185
- const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive, importNames, importNamePattern }) => ({
186
- matcher: ignore({ allowRelativePaths: true, ignorecase: !caseSensitive }).add(group),
187
- customMessage: message,
188
- importNames,
189
- importNamePattern
190
- }));
191
-
192
- // if no imports are restricted we don't need to check
193
- if (Object.keys(restrictedPaths).length === 0 && restrictedPatternGroups.length === 0) {
194
- return {};
195
- }
196
-
197
- /**
198
- * Report a restricted path.
199
- * @param {string} importSource path of the import
200
- * @param {Map<string,Object[]>} importNames Map of import names that are being imported
201
- * @param {node} node representing the restricted path reference
202
- * @returns {void}
203
- * @private
204
- */
205
- function checkRestrictedPathAndReport(importSource, importNames, node) {
206
- if (!Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) {
207
- return;
208
- }
209
-
210
- const customMessage = restrictedPathMessages[importSource].message;
211
- const restrictedImportNames = restrictedPathMessages[importSource].importNames;
212
-
213
- if (restrictedImportNames) {
214
- if (importNames.has("*")) {
215
- const specifierData = importNames.get("*")[0];
216
-
217
- context.report({
218
- node,
219
- messageId: customMessage ? "everythingWithCustomMessage" : "everything",
220
- loc: specifierData.loc,
221
- data: {
222
- importSource,
223
- importNames: restrictedImportNames,
224
- customMessage
225
- }
226
- });
227
- }
228
-
229
- restrictedImportNames.forEach(importName => {
230
- if (importNames.has(importName)) {
231
- const specifiers = importNames.get(importName);
232
-
233
- specifiers.forEach(specifier => {
234
- context.report({
235
- node,
236
- messageId: customMessage ? "importNameWithCustomMessage" : "importName",
237
- loc: specifier.loc,
238
- data: {
239
- importSource,
240
- customMessage,
241
- importName
242
- }
243
- });
244
- });
245
- }
246
- });
247
- } else {
248
- context.report({
249
- node,
250
- messageId: customMessage ? "pathWithCustomMessage" : "path",
251
- data: {
252
- importSource,
253
- customMessage
254
- }
255
- });
256
- }
257
- }
258
-
259
- /**
260
- * Report a restricted path specifically for patterns.
261
- * @param {node} node representing the restricted path reference
262
- * @param {Object} group contains an Ignore instance for paths, the customMessage to show on failure,
263
- * and any restricted import names that have been specified in the config
264
- * @param {Map<string,Object[]>} importNames Map of import names that are being imported
265
- * @returns {void}
266
- * @private
267
- */
268
- function reportPathForPatterns(node, group, importNames) {
269
- const importSource = node.source.value.trim();
270
-
271
- const customMessage = group.customMessage;
272
- const restrictedImportNames = group.importNames;
273
- const restrictedImportNamePattern = group.importNamePattern ? new RegExp(group.importNamePattern, "u") : null;
274
-
275
- /*
276
- * If we are not restricting to any specific import names and just the pattern itself,
277
- * report the error and move on
278
- */
279
- if (!restrictedImportNames && !restrictedImportNamePattern) {
280
- context.report({
281
- node,
282
- messageId: customMessage ? "patternWithCustomMessage" : "patterns",
283
- data: {
284
- importSource,
285
- customMessage
286
- }
287
- });
288
- return;
289
- }
290
-
291
- importNames.forEach((specifiers, importName) => {
292
- if (importName === "*") {
293
- const [specifier] = specifiers;
294
-
295
- if (restrictedImportNames) {
296
- context.report({
297
- node,
298
- messageId: customMessage ? "patternAndEverythingWithCustomMessage" : "patternAndEverything",
299
- loc: specifier.loc,
300
- data: {
301
- importSource,
302
- importNames: restrictedImportNames,
303
- customMessage
304
- }
305
- });
306
- } else {
307
- context.report({
308
- node,
309
- messageId: customMessage ? "patternAndEverythingWithRegexImportNameAndCustomMessage" : "patternAndEverythingWithRegexImportName",
310
- loc: specifier.loc,
311
- data: {
312
- importSource,
313
- importNames: restrictedImportNamePattern,
314
- customMessage
315
- }
316
- });
317
- }
318
-
319
- return;
320
- }
321
-
322
- if (
323
- (restrictedImportNames && restrictedImportNames.includes(importName)) ||
324
- (restrictedImportNamePattern && restrictedImportNamePattern.test(importName))
325
- ) {
326
- specifiers.forEach(specifier => {
327
- context.report({
328
- node,
329
- messageId: customMessage ? "patternAndImportNameWithCustomMessage" : "patternAndImportName",
330
- loc: specifier.loc,
331
- data: {
332
- importSource,
333
- customMessage,
334
- importName
335
- }
336
- });
337
- });
338
- }
339
- });
340
- }
341
-
342
- /**
343
- * Check if the given importSource is restricted by a pattern.
344
- * @param {string} importSource path of the import
345
- * @param {Object} group contains a Ignore instance for paths, and the customMessage to show if it fails
346
- * @returns {boolean} whether the variable is a restricted pattern or not
347
- * @private
348
- */
349
- function isRestrictedPattern(importSource, group) {
350
- return group.matcher.ignores(importSource);
351
- }
352
-
353
- /**
354
- * Checks a node to see if any problems should be reported.
355
- * @param {ASTNode} node The node to check.
356
- * @returns {void}
357
- * @private
358
- */
359
- function checkNode(node) {
360
- const importSource = node.source.value.trim();
361
- const importNames = new Map();
362
-
363
- if (node.type === "ExportAllDeclaration") {
364
- const starToken = sourceCode.getFirstToken(node, 1);
365
-
366
- importNames.set("*", [{ loc: starToken.loc }]);
367
- } else if (node.specifiers) {
368
- for (const specifier of node.specifiers) {
369
- let name;
370
- const specifierData = { loc: specifier.loc };
371
-
372
- if (specifier.type === "ImportDefaultSpecifier") {
373
- name = "default";
374
- } else if (specifier.type === "ImportNamespaceSpecifier") {
375
- name = "*";
376
- } else if (specifier.imported) {
377
- name = astUtils.getModuleExportName(specifier.imported);
378
- } else if (specifier.local) {
379
- name = astUtils.getModuleExportName(specifier.local);
380
- }
381
-
382
- if (typeof name === "string") {
383
- if (importNames.has(name)) {
384
- importNames.get(name).push(specifierData);
385
- } else {
386
- importNames.set(name, [specifierData]);
387
- }
388
- }
389
- }
390
- }
391
-
392
- checkRestrictedPathAndReport(importSource, importNames, node);
393
- restrictedPatternGroups.forEach(group => {
394
- if (isRestrictedPattern(importSource, group)) {
395
- reportPathForPatterns(node, group, importNames);
396
- }
397
- });
398
- }
399
-
400
- return {
401
- ImportDeclaration: checkNode,
402
- ExportNamedDeclaration(node) {
403
- if (node.source) {
404
- checkNode(node);
405
- }
406
- },
407
- ExportAllDeclaration: checkNode
408
- };
409
- }
148
+ meta: {
149
+ type: "suggestion",
150
+ dialects: ["typescript", "javascript"],
151
+ language: "javascript",
152
+
153
+ docs: {
154
+ description: "Disallow specified modules when loaded by `import`",
155
+ recommended: false,
156
+ url: "https://eslint.org/docs/latest/rules/no-restricted-imports",
157
+ },
158
+
159
+ messages: {
160
+ path: "'{{importSource}}' import is restricted from being used.",
161
+ pathWithCustomMessage:
162
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
163
+ "'{{importSource}}' import is restricted from being used. {{customMessage}}",
164
+
165
+ patterns:
166
+ "'{{importSource}}' import is restricted from being used by a pattern.",
167
+ patternWithCustomMessage:
168
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
169
+ "'{{importSource}}' import is restricted from being used by a pattern. {{customMessage}}",
170
+
171
+ patternAndImportName:
172
+ "'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern.",
173
+ patternAndImportNameWithCustomMessage:
174
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
175
+ "'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
176
+
177
+ patternAndEverything:
178
+ "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern.",
179
+
180
+ patternAndEverythingWithRegexImportName:
181
+ "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used.",
182
+ patternAndEverythingWithCustomMessage:
183
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
184
+ "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
185
+ patternAndEverythingWithRegexImportNameAndCustomMessage:
186
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
187
+ "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used. {{customMessage}}",
188
+
189
+ everything:
190
+ "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.",
191
+ everythingWithCustomMessage:
192
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
193
+ "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted. {{customMessage}}",
194
+
195
+ importName:
196
+ "'{{importName}}' import from '{{importSource}}' is restricted.",
197
+ importNameWithCustomMessage:
198
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
199
+ "'{{importName}}' import from '{{importSource}}' is restricted. {{customMessage}}",
200
+
201
+ allowedImportName:
202
+ "'{{importName}}' import from '{{importSource}}' is restricted because only '{{allowedImportNames}}' import(s) is/are allowed.",
203
+ allowedImportNameWithCustomMessage:
204
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
205
+ "'{{importName}}' import from '{{importSource}}' is restricted because only '{{allowedImportNames}}' import(s) is/are allowed. {{customMessage}}",
206
+
207
+ everythingWithAllowImportNames:
208
+ "* import is invalid because only '{{allowedImportNames}}' from '{{importSource}}' is/are allowed.",
209
+ everythingWithAllowImportNamesAndCustomMessage:
210
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
211
+ "* import is invalid because only '{{allowedImportNames}}' from '{{importSource}}' is/are allowed. {{customMessage}}",
212
+
213
+ allowedImportNamePattern:
214
+ "'{{importName}}' import from '{{importSource}}' is restricted because only imports that match the pattern '{{allowedImportNamePattern}}' are allowed from '{{importSource}}'.",
215
+ allowedImportNamePatternWithCustomMessage:
216
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
217
+ "'{{importName}}' import from '{{importSource}}' is restricted because only imports that match the pattern '{{allowedImportNamePattern}}' are allowed from '{{importSource}}'. {{customMessage}}",
218
+
219
+ everythingWithAllowedImportNamePattern:
220
+ "* import is invalid because only imports that match the pattern '{{allowedImportNamePattern}}' from '{{importSource}}' are allowed.",
221
+ everythingWithAllowedImportNamePatternWithCustomMessage:
222
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
223
+ "* import is invalid because only imports that match the pattern '{{allowedImportNamePattern}}' from '{{importSource}}' are allowed. {{customMessage}}",
224
+ },
225
+
226
+ schema: {
227
+ anyOf: [
228
+ arrayOfStringsOrObjects,
229
+ {
230
+ type: "array",
231
+ items: [
232
+ {
233
+ type: "object",
234
+ properties: {
235
+ paths: arrayOfStringsOrObjects,
236
+ patterns: arrayOfStringsOrObjectPatterns,
237
+ },
238
+ additionalProperties: false,
239
+ },
240
+ ],
241
+ additionalItems: false,
242
+ },
243
+ ],
244
+ },
245
+ },
246
+
247
+ create(context) {
248
+ const sourceCode = context.sourceCode;
249
+ const options = Array.isArray(context.options) ? context.options : [];
250
+ const isPathAndPatternsObject =
251
+ typeof options[0] === "object" &&
252
+ (Object.hasOwn(options[0], "paths") ||
253
+ Object.hasOwn(options[0], "patterns"));
254
+
255
+ const restrictedPaths =
256
+ (isPathAndPatternsObject ? options[0].paths : context.options) ||
257
+ [];
258
+ const groupedRestrictedPaths = restrictedPaths.reduce(
259
+ (memo, importSource) => {
260
+ const path =
261
+ typeof importSource === "string"
262
+ ? importSource
263
+ : importSource.name;
264
+
265
+ if (!memo[path]) {
266
+ memo[path] = [];
267
+ }
268
+
269
+ if (typeof importSource === "string") {
270
+ memo[path].push({});
271
+ } else {
272
+ memo[path].push({
273
+ message: importSource.message,
274
+ importNames: importSource.importNames,
275
+ allowImportNames: importSource.allowImportNames,
276
+ allowTypeImports: importSource.allowTypeImports,
277
+ });
278
+ }
279
+ return memo;
280
+ },
281
+ Object.create(null),
282
+ );
283
+
284
+ // Handle patterns too, either as strings or groups
285
+ let restrictedPatterns =
286
+ (isPathAndPatternsObject ? options[0].patterns : []) || [];
287
+
288
+ // standardize to array of objects if we have an array of strings
289
+ if (
290
+ restrictedPatterns.length > 0 &&
291
+ typeof restrictedPatterns[0] === "string"
292
+ ) {
293
+ restrictedPatterns = [{ group: restrictedPatterns }];
294
+ }
295
+
296
+ // relative paths are supported for this rule
297
+ const restrictedPatternGroups = restrictedPatterns.map(
298
+ ({
299
+ group,
300
+ regex,
301
+ message,
302
+ caseSensitive,
303
+ importNames,
304
+ importNamePattern,
305
+ allowImportNames,
306
+ allowImportNamePattern,
307
+ allowTypeImports,
308
+ }) => ({
309
+ ...(group
310
+ ? {
311
+ matcher: ignore({
312
+ allowRelativePaths: true,
313
+ ignorecase: !caseSensitive,
314
+ }).add(group),
315
+ }
316
+ : {}),
317
+ ...(typeof regex === "string"
318
+ ? {
319
+ regexMatcher: new RegExp(
320
+ regex,
321
+ caseSensitive ? "u" : "iu",
322
+ ),
323
+ }
324
+ : {}),
325
+ customMessage: message,
326
+ importNames,
327
+ importNamePattern,
328
+ allowImportNames,
329
+ allowImportNamePattern,
330
+ allowTypeImports,
331
+ }),
332
+ );
333
+
334
+ // if no imports are restricted we don't need to check
335
+ if (
336
+ Object.keys(restrictedPaths).length === 0 &&
337
+ restrictedPatternGroups.length === 0
338
+ ) {
339
+ return {};
340
+ }
341
+
342
+ /**
343
+ * Check if the node is a type-only import
344
+ * @param {ASTNode} node The node to check
345
+ * @returns {boolean} Whether the node is a type-only import
346
+ */
347
+ function isTypeOnlyImport(node) {
348
+ return (
349
+ node.importKind === "type" ||
350
+ (node.specifiers?.length > 0 &&
351
+ node.specifiers.every(
352
+ specifier => specifier.importKind === "type",
353
+ ))
354
+ );
355
+ }
356
+
357
+ /**
358
+ * Check if a specifier is type-only
359
+ * @param {ASTNode} specifier The specifier to check
360
+ * @returns {boolean} Whether the specifier is type-only
361
+ */
362
+ function isTypeOnlySpecifier(specifier) {
363
+ return (
364
+ specifier.importKind === "type" ||
365
+ specifier.exportKind === "type"
366
+ );
367
+ }
368
+
369
+ /**
370
+ * Check if the node is a type-only export
371
+ * @param {ASTNode} node The node to check
372
+ * @returns {boolean} Whether the node is a type-only export
373
+ */
374
+ function isTypeOnlyExport(node) {
375
+ return (
376
+ node.exportKind === "type" ||
377
+ (node.specifiers?.length > 0 &&
378
+ node.specifiers.every(
379
+ specifier => specifier.exportKind === "type",
380
+ ))
381
+ );
382
+ }
383
+
384
+ /**
385
+ * Report a restricted path.
386
+ * @param {string} importSource path of the import
387
+ * @param {Map<string,Object[]>} importNames Map of import names that are being imported
388
+ * @param {node} node representing the restricted path reference
389
+ * @returns {void}
390
+ * @private
391
+ */
392
+ function checkRestrictedPathAndReport(importSource, importNames, node) {
393
+ if (!Object.hasOwn(groupedRestrictedPaths, importSource)) {
394
+ return;
395
+ }
396
+
397
+ groupedRestrictedPaths[importSource].forEach(
398
+ restrictedPathEntry => {
399
+ const customMessage = restrictedPathEntry.message;
400
+ const restrictedImportNames =
401
+ restrictedPathEntry.importNames;
402
+ const allowedImportNames =
403
+ restrictedPathEntry.allowImportNames;
404
+ const allowTypeImports =
405
+ restrictedPathEntry.allowTypeImports;
406
+
407
+ // Skip if this is a type-only import and it's allowed for this specific entry
408
+ if (
409
+ allowTypeImports &&
410
+ (node.type === "ImportDeclaration" ||
411
+ node.type === "TSImportEqualsDeclaration") &&
412
+ isTypeOnlyImport(node)
413
+ ) {
414
+ return;
415
+ }
416
+
417
+ // Skip if this is a type-only export and it's allowed for this specific entry
418
+ if (
419
+ allowTypeImports &&
420
+ (node.type === "ExportNamedDeclaration" ||
421
+ node.type === "ExportAllDeclaration") &&
422
+ isTypeOnlyExport(node)
423
+ ) {
424
+ return;
425
+ }
426
+
427
+ if (!restrictedImportNames && !allowedImportNames) {
428
+ context.report({
429
+ node,
430
+ messageId: customMessage
431
+ ? "pathWithCustomMessage"
432
+ : "path",
433
+ data: {
434
+ importSource,
435
+ customMessage,
436
+ },
437
+ });
438
+
439
+ return;
440
+ }
441
+
442
+ importNames.forEach((specifiers, importName) => {
443
+ if (importName === "*") {
444
+ const [specifier] = specifiers;
445
+
446
+ if (restrictedImportNames) {
447
+ context.report({
448
+ node,
449
+ messageId: customMessage
450
+ ? "everythingWithCustomMessage"
451
+ : "everything",
452
+ loc: specifier.loc,
453
+ data: {
454
+ importSource,
455
+ importNames: restrictedImportNames,
456
+ customMessage,
457
+ },
458
+ });
459
+ } else if (allowedImportNames) {
460
+ context.report({
461
+ node,
462
+ messageId: customMessage
463
+ ? "everythingWithAllowImportNamesAndCustomMessage"
464
+ : "everythingWithAllowImportNames",
465
+ loc: specifier.loc,
466
+ data: {
467
+ importSource,
468
+ allowedImportNames,
469
+ customMessage,
470
+ },
471
+ });
472
+ }
473
+
474
+ return;
475
+ }
476
+
477
+ if (
478
+ restrictedImportNames &&
479
+ restrictedImportNames.includes(importName)
480
+ ) {
481
+ specifiers.forEach(specifier => {
482
+ // Skip if this is a type-only import specifier and type imports are allowed
483
+ if (
484
+ allowTypeImports &&
485
+ isTypeOnlySpecifier(specifier.specifier)
486
+ ) {
487
+ return;
488
+ }
489
+
490
+ context.report({
491
+ node,
492
+ messageId: customMessage
493
+ ? "importNameWithCustomMessage"
494
+ : "importName",
495
+ loc: specifier.loc,
496
+ data: {
497
+ importSource,
498
+ customMessage,
499
+ importName,
500
+ },
501
+ });
502
+ });
503
+ }
504
+
505
+ if (
506
+ allowedImportNames &&
507
+ !allowedImportNames.includes(importName)
508
+ ) {
509
+ specifiers.forEach(specifier => {
510
+ // Skip if this is a type-only import specifier and type imports are allowed
511
+ if (
512
+ allowTypeImports &&
513
+ isTypeOnlySpecifier(specifier.specifier)
514
+ ) {
515
+ return;
516
+ }
517
+
518
+ context.report({
519
+ node,
520
+ loc: specifier.loc,
521
+ messageId: customMessage
522
+ ? "allowedImportNameWithCustomMessage"
523
+ : "allowedImportName",
524
+ data: {
525
+ importSource,
526
+ customMessage,
527
+ importName,
528
+ allowedImportNames,
529
+ },
530
+ });
531
+ });
532
+ }
533
+ });
534
+ },
535
+ );
536
+ }
537
+
538
+ /**
539
+ * Report a restricted path specifically for patterns.
540
+ * @param {node} node representing the restricted path reference
541
+ * @param {Object} group contains an Ignore instance for paths, the customMessage to show on failure,
542
+ * and any restricted import names that have been specified in the config
543
+ * @param {Map<string,Object[]>} importNames Map of import names that are being imported
544
+ * @param {string} importSource the import source string
545
+ * @returns {void}
546
+ * @private
547
+ */
548
+ function reportPathForPatterns(node, group, importNames, importSource) {
549
+ // Skip if this is a type-only import and it's allowed
550
+ if (
551
+ group.allowTypeImports &&
552
+ (node.type === "ImportDeclaration" ||
553
+ node.type === "TSImportEqualsDeclaration") &&
554
+ isTypeOnlyImport(node)
555
+ ) {
556
+ return;
557
+ }
558
+
559
+ // Skip if this is a type-only export and it's allowed
560
+ if (
561
+ group.allowTypeImports &&
562
+ (node.type === "ExportNamedDeclaration" ||
563
+ node.type === "ExportAllDeclaration") &&
564
+ isTypeOnlyExport(node)
565
+ ) {
566
+ return;
567
+ }
568
+
569
+ const customMessage = group.customMessage;
570
+ const restrictedImportNames = group.importNames;
571
+ const restrictedImportNamePattern = group.importNamePattern
572
+ ? new RegExp(group.importNamePattern, "u")
573
+ : null;
574
+ const allowedImportNames = group.allowImportNames;
575
+ const allowedImportNamePattern = group.allowImportNamePattern
576
+ ? new RegExp(group.allowImportNamePattern, "u")
577
+ : null;
578
+
579
+ /**
580
+ * If we are not restricting to any specific import names and just the pattern itself,
581
+ * report the error and move on
582
+ */
583
+ if (
584
+ !restrictedImportNames &&
585
+ !allowedImportNames &&
586
+ !restrictedImportNamePattern &&
587
+ !allowedImportNamePattern
588
+ ) {
589
+ context.report({
590
+ node,
591
+ messageId: customMessage
592
+ ? "patternWithCustomMessage"
593
+ : "patterns",
594
+ data: {
595
+ importSource,
596
+ customMessage,
597
+ },
598
+ });
599
+ return;
600
+ }
601
+
602
+ importNames.forEach((specifiers, importName) => {
603
+ if (importName === "*") {
604
+ const [specifier] = specifiers;
605
+
606
+ if (restrictedImportNames) {
607
+ context.report({
608
+ node,
609
+ messageId: customMessage
610
+ ? "patternAndEverythingWithCustomMessage"
611
+ : "patternAndEverything",
612
+ loc: specifier.loc,
613
+ data: {
614
+ importSource,
615
+ importNames: restrictedImportNames,
616
+ customMessage,
617
+ },
618
+ });
619
+ } else if (allowedImportNames) {
620
+ context.report({
621
+ node,
622
+ messageId: customMessage
623
+ ? "everythingWithAllowImportNamesAndCustomMessage"
624
+ : "everythingWithAllowImportNames",
625
+ loc: specifier.loc,
626
+ data: {
627
+ importSource,
628
+ allowedImportNames,
629
+ customMessage,
630
+ },
631
+ });
632
+ } else if (allowedImportNamePattern) {
633
+ context.report({
634
+ node,
635
+ messageId: customMessage
636
+ ? "everythingWithAllowedImportNamePatternWithCustomMessage"
637
+ : "everythingWithAllowedImportNamePattern",
638
+ loc: specifier.loc,
639
+ data: {
640
+ importSource,
641
+ allowedImportNamePattern,
642
+ customMessage,
643
+ },
644
+ });
645
+ } else {
646
+ context.report({
647
+ node,
648
+ messageId: customMessage
649
+ ? "patternAndEverythingWithRegexImportNameAndCustomMessage"
650
+ : "patternAndEverythingWithRegexImportName",
651
+ loc: specifier.loc,
652
+ data: {
653
+ importSource,
654
+ importNames: restrictedImportNamePattern,
655
+ customMessage,
656
+ },
657
+ });
658
+ }
659
+
660
+ return;
661
+ }
662
+
663
+ if (
664
+ (restrictedImportNames &&
665
+ restrictedImportNames.includes(importName)) ||
666
+ (restrictedImportNamePattern &&
667
+ restrictedImportNamePattern.test(importName))
668
+ ) {
669
+ specifiers.forEach(specifier => {
670
+ // Skip if this is a type-only import specifier and type imports are allowed
671
+ if (
672
+ group.allowTypeImports &&
673
+ isTypeOnlySpecifier(specifier.specifier)
674
+ ) {
675
+ return;
676
+ }
677
+
678
+ context.report({
679
+ node,
680
+ messageId: customMessage
681
+ ? "patternAndImportNameWithCustomMessage"
682
+ : "patternAndImportName",
683
+ loc: specifier.loc,
684
+ data: {
685
+ importSource,
686
+ customMessage,
687
+ importName,
688
+ },
689
+ });
690
+ });
691
+ }
692
+
693
+ if (
694
+ allowedImportNames &&
695
+ !allowedImportNames.includes(importName)
696
+ ) {
697
+ specifiers.forEach(specifier => {
698
+ // Skip if this is a type-only import specifier and type imports are allowed
699
+ if (
700
+ group.allowTypeImports &&
701
+ isTypeOnlySpecifier(specifier.specifier)
702
+ ) {
703
+ return;
704
+ }
705
+
706
+ context.report({
707
+ node,
708
+ messageId: customMessage
709
+ ? "allowedImportNameWithCustomMessage"
710
+ : "allowedImportName",
711
+ loc: specifier.loc,
712
+ data: {
713
+ importSource,
714
+ customMessage,
715
+ importName,
716
+ allowedImportNames,
717
+ },
718
+ });
719
+ });
720
+ } else if (
721
+ allowedImportNamePattern &&
722
+ !allowedImportNamePattern.test(importName)
723
+ ) {
724
+ specifiers.forEach(specifier => {
725
+ // Skip if this is a type-only import specifier and type imports are allowed
726
+ if (
727
+ group.allowTypeImports &&
728
+ isTypeOnlySpecifier(specifier.specifier)
729
+ ) {
730
+ return;
731
+ }
732
+
733
+ context.report({
734
+ node,
735
+ messageId: customMessage
736
+ ? "allowedImportNamePatternWithCustomMessage"
737
+ : "allowedImportNamePattern",
738
+ loc: specifier.loc,
739
+ data: {
740
+ importSource,
741
+ customMessage,
742
+ importName,
743
+ allowedImportNamePattern,
744
+ },
745
+ });
746
+ });
747
+ }
748
+ });
749
+ }
750
+
751
+ /**
752
+ * Check if the given importSource is restricted by a pattern.
753
+ * @param {string} importSource path of the import
754
+ * @param {Object} group contains a Ignore instance for paths, and the customMessage to show if it fails
755
+ * @returns {boolean} whether the variable is a restricted pattern or not
756
+ * @private
757
+ */
758
+ function isRestrictedPattern(importSource, group) {
759
+ return group.regexMatcher
760
+ ? group.regexMatcher.test(importSource)
761
+ : group.matcher.ignores(importSource);
762
+ }
763
+
764
+ /**
765
+ * Checks a node to see if any problems should be reported.
766
+ * @param {ASTNode} node The node to check.
767
+ * @returns {void}
768
+ * @private
769
+ */
770
+ function checkNode(node) {
771
+ const importSource = node.source.value.trim();
772
+ const importNames = new Map();
773
+
774
+ if (node.type === "ExportAllDeclaration") {
775
+ const starToken = sourceCode.getFirstToken(node, 1);
776
+
777
+ importNames.set("*", [{ loc: starToken.loc }]);
778
+ } else if (node.specifiers) {
779
+ for (const specifier of node.specifiers) {
780
+ let name;
781
+ const specifierData = { loc: specifier.loc, specifier };
782
+
783
+ if (specifier.type === "ImportDefaultSpecifier") {
784
+ name = "default";
785
+ } else if (specifier.type === "ImportNamespaceSpecifier") {
786
+ name = "*";
787
+ } else if (specifier.imported) {
788
+ name = astUtils.getModuleExportName(specifier.imported);
789
+ } else if (specifier.local) {
790
+ name = astUtils.getModuleExportName(specifier.local);
791
+ }
792
+
793
+ if (typeof name === "string") {
794
+ if (importNames.has(name)) {
795
+ importNames.get(name).push(specifierData);
796
+ } else {
797
+ importNames.set(name, [specifierData]);
798
+ }
799
+ }
800
+ }
801
+ }
802
+
803
+ checkRestrictedPathAndReport(importSource, importNames, node);
804
+ restrictedPatternGroups.forEach(group => {
805
+ if (isRestrictedPattern(importSource, group)) {
806
+ reportPathForPatterns(
807
+ node,
808
+ group,
809
+ importNames,
810
+ importSource,
811
+ );
812
+ }
813
+ });
814
+ }
815
+
816
+ return {
817
+ ImportDeclaration: checkNode,
818
+ ExportNamedDeclaration(node) {
819
+ if (node.source) {
820
+ checkNode(node);
821
+ }
822
+ },
823
+ ExportAllDeclaration: checkNode,
824
+ // Add support for TypeScript import equals declarations
825
+ TSImportEqualsDeclaration(node) {
826
+ if (node.moduleReference.type === "TSExternalModuleReference") {
827
+ const importSource = node.moduleReference.expression.value;
828
+ const importNames = new Map();
829
+
830
+ // Use existing logic with the actual node
831
+ checkRestrictedPathAndReport(
832
+ importSource,
833
+ importNames,
834
+ node,
835
+ );
836
+ restrictedPatternGroups.forEach(group => {
837
+ if (isRestrictedPattern(importSource, group)) {
838
+ reportPathForPatterns(
839
+ node,
840
+ group,
841
+ importNames,
842
+ importSource,
843
+ );
844
+ }
845
+ });
846
+ }
847
+ },
848
+ };
849
+ },
410
850
  };