eslint-config-un 1.0.0-beta.1 → 1.0.0-beta.2

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 (244) hide show
  1. package/README.md +97 -39
  2. package/dist/config-un/cache.mjs +133 -0
  3. package/dist/config-un/config-utils.mjs +76 -0
  4. package/dist/config-un/config.mjs +467 -0
  5. package/dist/config-un/fast-import.d.mts +14 -0
  6. package/dist/config-un/fast-import.mjs +35 -0
  7. package/dist/config-un/is-module-loaded.mjs +21 -0
  8. package/dist/config-un/resolve-config-async-data.mjs +198 -0
  9. package/dist/config-un/shared.d.mts +250 -0
  10. package/dist/config-un/shared.mjs +23 -0
  11. package/dist/configs/angular.d.mts +151 -0
  12. package/dist/{angular.mjs → configs/angular.mjs} +7 -5
  13. package/dist/configs/antfu.d.mts +8 -0
  14. package/dist/{antfu.mjs → configs/antfu.mjs} +3 -3
  15. package/dist/configs/astro.d.mts +20 -0
  16. package/dist/{astro.mjs → configs/astro.mjs} +6 -4
  17. package/dist/configs/ava.d.mts +26 -0
  18. package/dist/{ava.mjs → configs/ava.mjs} +4 -4
  19. package/dist/configs/better-tailwind.d.mts +67 -0
  20. package/dist/{better-tailwind.mjs → configs/better-tailwind.mjs} +3 -3
  21. package/dist/configs/boundaries.d.mts +18 -0
  22. package/dist/{boundaries.mjs → configs/boundaries.mjs} +3 -3
  23. package/dist/configs/case-police.d.mts +8 -0
  24. package/dist/{case-police.mjs → configs/case-police.mjs} +3 -3
  25. package/dist/configs/check-file.d.mts +31 -0
  26. package/dist/configs/check-file.mjs +22 -0
  27. package/dist/configs/command.d.mts +8 -0
  28. package/dist/{command.mjs → configs/command.mjs} +3 -3
  29. package/dist/configs/compat.d.mts +24 -0
  30. package/dist/{compat.mjs → configs/compat.mjs} +3 -3
  31. package/dist/configs/cspell.d.mts +13 -0
  32. package/dist/{cspell.mjs → configs/cspell.mjs} +3 -3
  33. package/dist/configs/css-in-js.d.mts +49 -0
  34. package/dist/{css-in-js.mjs → configs/css-in-js.mjs} +3 -3
  35. package/dist/configs/css.d.mts +40 -0
  36. package/dist/{css.mjs → configs/css.mjs} +5 -4
  37. package/dist/configs/cypress.d.mts +9 -0
  38. package/dist/{cypress.mjs → configs/cypress.mjs} +4 -4
  39. package/dist/configs/de-morgan.d.mts +8 -0
  40. package/dist/{de-morgan.mjs → configs/de-morgan.mjs} +3 -3
  41. package/dist/configs/depend.d.mts +13 -0
  42. package/dist/{depend.mjs → configs/depend.mjs} +3 -3
  43. package/dist/configs/docusaurus.d.mts +8 -0
  44. package/dist/{docusaurus.mjs → configs/docusaurus.mjs} +3 -3
  45. package/dist/configs/ember.d.mts +25 -0
  46. package/dist/{ember.mjs → configs/ember.mjs} +4 -4
  47. package/dist/configs/erasable-syntax-only.d.mts +19 -0
  48. package/dist/{erasable-syntax-only.mjs → configs/erasable-syntax-only.mjs} +3 -3
  49. package/dist/configs/es.d.mts +59 -0
  50. package/dist/{es.mjs → configs/es.mjs} +3 -3
  51. package/dist/configs/eslint-comments.d.mts +8 -0
  52. package/dist/{eslint-comments.mjs → configs/eslint-comments.mjs} +3 -3
  53. package/dist/configs/eslint-plugin.d.mts +34 -0
  54. package/dist/{eslint-plugin.mjs → configs/eslint-plugin.mjs} +4 -4
  55. package/dist/configs/expect-type.d.mts +13 -0
  56. package/dist/{expect-type.mjs → configs/expect-type.mjs} +3 -3
  57. package/dist/configs/extra/cli.d.mts +14 -0
  58. package/dist/{cli.mjs → configs/extra/cli.mjs} +3 -3
  59. package/dist/configs/extra/cloudfront-functions.d.mts +14 -0
  60. package/dist/{cloudfront-functions.mjs → configs/extra/cloudfront-functions.mjs} +4 -4
  61. package/dist/configs/extra/no-stylistic-rules.d.mts +782 -0
  62. package/dist/configs/extra/no-stylistic-rules.mjs +758 -0
  63. package/dist/configs/fast-import.d.mts +27 -0
  64. package/dist/{fast-import.mjs → configs/fast-import.mjs} +3 -3
  65. package/dist/configs/file-progress.d.mts +29 -0
  66. package/dist/{file-progress.mjs → configs/file-progress.mjs} +4 -3
  67. package/dist/configs/formatjs.d.mts +67 -0
  68. package/dist/{formatjs.mjs → configs/formatjs.mjs} +3 -3
  69. package/dist/configs/graphql.d.mts +46 -0
  70. package/dist/{graphql.mjs → configs/graphql.mjs} +6 -4
  71. package/dist/configs/header.d.mts +33 -0
  72. package/dist/{header.mjs → configs/header.mjs} +3 -3
  73. package/dist/configs/headers.d.mts +38 -0
  74. package/dist/{headers.mjs → configs/headers.mjs} +3 -3
  75. package/dist/configs/html.d.mts +43 -0
  76. package/dist/{html.mjs → configs/html.mjs} +4 -4
  77. package/dist/configs/import-zod.d.mts +8 -0
  78. package/dist/{import-zod.mjs → configs/import-zod.mjs} +3 -3
  79. package/dist/configs/import.d.mts +62 -0
  80. package/dist/{import.mjs → configs/import.mjs} +5 -4
  81. package/dist/configs/index.d.mts +1116 -0
  82. package/dist/configs/index.mjs +3 -0
  83. package/dist/configs/jest-dom.d.mts +8 -0
  84. package/dist/{jest-dom.mjs → configs/jest-dom.mjs} +4 -4
  85. package/dist/configs/jest.d.mts +125 -0
  86. package/dist/{jest.mjs → configs/jest.mjs} +6 -5
  87. package/dist/configs/js-inline.d.mts +81 -0
  88. package/dist/{js-inline.mjs → configs/js-inline.mjs} +5 -4
  89. package/dist/configs/js.d.mts +14 -0
  90. package/dist/{js.mjs → configs/js.mjs} +3 -3
  91. package/dist/configs/jsdoc.d.mts +160 -0
  92. package/dist/{jsdoc.mjs → configs/jsdoc.mjs} +3 -3
  93. package/dist/configs/json-schema-validator.d.mts +26 -0
  94. package/dist/{json-schema-validator.mjs → configs/json-schema-validator.mjs} +4 -4
  95. package/dist/configs/jsonc.d.mts +30 -0
  96. package/dist/{jsonc.mjs → configs/jsonc.mjs} +4 -4
  97. package/dist/configs/jsx-a11y.d.mts +206 -0
  98. package/dist/{jsx-a11y.mjs → configs/jsx-a11y.mjs} +3 -3
  99. package/dist/configs/lit.d.mts +51 -0
  100. package/dist/{lit.mjs → configs/lit.mjs} +3 -3
  101. package/dist/configs/markdown-links.d.mts +24 -0
  102. package/dist/{markdown-links.mjs → configs/markdown-links.mjs} +3 -3
  103. package/dist/configs/markdown-preferences.d.mts +138 -0
  104. package/dist/{markdown-preferences.mjs → configs/markdown-preferences.mjs} +18 -12
  105. package/dist/configs/markdown.d.mts +96 -0
  106. package/dist/{markdown.mjs → configs/markdown.mjs} +9 -8
  107. package/dist/configs/math.d.mts +14 -0
  108. package/dist/{math.mjs → configs/math.mjs} +3 -3
  109. package/dist/configs/mdx.d.mts +25 -0
  110. package/dist/{mdx.mjs → configs/mdx.mjs} +6 -5
  111. package/dist/configs/mocha.d.mts +35 -0
  112. package/dist/{mocha.mjs → configs/mocha.mjs} +4 -4
  113. package/dist/configs/module-interop.d.mts +8 -0
  114. package/dist/{module-interop.mjs → configs/module-interop.mjs} +3 -3
  115. package/dist/configs/nest-js.d.mts +8 -0
  116. package/dist/{nest-js.mjs → configs/nest-js.mjs} +3 -3
  117. package/dist/configs/nextjs.d.mts +22 -0
  118. package/dist/{nextjs.mjs → configs/nextjs.mjs} +3 -3
  119. package/dist/configs/no-only-tests.d.mts +8 -0
  120. package/dist/{no-only-tests.mjs → configs/no-only-tests.mjs} +4 -4
  121. package/dist/configs/no-secrets.d.mts +24 -0
  122. package/dist/{no-secrets.mjs → configs/no-secrets.mjs} +4 -5
  123. package/dist/configs/no-unsanitized.d.mts +8 -0
  124. package/dist/{no-unsanitized.mjs → configs/no-unsanitized.mjs} +3 -3
  125. package/dist/configs/node-dependencies.d.mts +19 -0
  126. package/dist/{node-dependencies.mjs → configs/node-dependencies.mjs} +3 -3
  127. package/dist/configs/node.d.mts +157 -0
  128. package/dist/{node.mjs → configs/node.mjs} +3 -3
  129. package/dist/configs/nx.d.mts +13 -0
  130. package/dist/{nx.mjs → configs/nx.mjs} +3 -3
  131. package/dist/configs/package-json.d.mts +80 -0
  132. package/dist/{package-json.mjs → configs/package-json.mjs} +3 -3
  133. package/dist/configs/perfectionist.d.mts +101 -0
  134. package/dist/{perfectionist.mjs → configs/perfectionist.mjs} +3 -3
  135. package/dist/configs/playwright.d.mts +44 -0
  136. package/dist/{playwright.mjs → configs/playwright.mjs} +4 -4
  137. package/dist/configs/pnpm.d.mts +56 -0
  138. package/dist/{pnpm.mjs → configs/pnpm.mjs} +3 -3
  139. package/dist/configs/prefer-arrow-functions.d.mts +8 -0
  140. package/dist/{prefer-arrow-functions.mjs → configs/prefer-arrow-functions.mjs} +3 -3
  141. package/dist/configs/promise.d.mts +8 -0
  142. package/dist/{promise.mjs → configs/promise.mjs} +3 -3
  143. package/dist/configs/qunit.d.mts +9 -0
  144. package/dist/{qunit.mjs → configs/qunit.mjs} +4 -4
  145. package/dist/configs/qwik.d.mts +10 -0
  146. package/dist/{qwik.mjs → configs/qwik.mjs} +3 -3
  147. package/dist/configs/react.d.mts +330 -0
  148. package/dist/{react.mjs → configs/react.mjs} +4 -4
  149. package/dist/configs/regexp.d.mts +8 -0
  150. package/dist/{regexp.mjs → configs/regexp.mjs} +3 -3
  151. package/dist/configs/rxjs.d.mts +34 -0
  152. package/dist/{rxjs.mjs → configs/rxjs.mjs} +3 -3
  153. package/dist/configs/security.d.mts +8 -0
  154. package/dist/{security.mjs → configs/security.mjs} +3 -3
  155. package/dist/configs/shared.d.mts +42 -0
  156. package/dist/{shared.mjs → configs/shared.mjs} +8 -3
  157. package/dist/configs/solid.d.mts +8 -0
  158. package/dist/{solid.mjs → configs/solid.mjs} +3 -3
  159. package/dist/configs/sonar.d.mts +24 -0
  160. package/dist/{sonar.mjs → configs/sonar.mjs} +3 -3
  161. package/dist/configs/storybook.d.mts +8 -0
  162. package/dist/{storybook.mjs → configs/storybook.mjs} +3 -3
  163. package/dist/configs/stylistic.d.mts +17 -0
  164. package/dist/{stylistic.mjs → configs/stylistic.mjs} +5 -4
  165. package/dist/configs/svelte.d.mts +81 -0
  166. package/dist/{svelte.mjs → configs/svelte.mjs} +7 -5
  167. package/dist/configs/tailwind.d.mts +29 -0
  168. package/dist/{tailwind.mjs → configs/tailwind.mjs} +3 -3
  169. package/dist/configs/tanstack-query.d.mts +8 -0
  170. package/dist/{tanstack-query.mjs → configs/tanstack-query.mjs} +3 -3
  171. package/dist/configs/testing-library.d.mts +76 -0
  172. package/dist/{testing-library.mjs → configs/testing-library.mjs} +4 -4
  173. package/dist/configs/toml.d.mts +34 -0
  174. package/dist/{toml.mjs → configs/toml.mjs} +6 -6
  175. package/dist/configs/tree-shaking.d.mts +13 -0
  176. package/dist/{tree-shaking.mjs → configs/tree-shaking.mjs} +3 -3
  177. package/dist/configs/ts.d.mts +136 -0
  178. package/dist/{ts.mjs → configs/ts.mjs} +6 -5
  179. package/dist/configs/turbo.d.mts +14 -0
  180. package/dist/{turbo.mjs → configs/turbo.mjs} +3 -3
  181. package/dist/configs/un.d.mts +8 -0
  182. package/dist/configs/un.mjs +17 -0
  183. package/dist/configs/unicorn.d.mts +21 -0
  184. package/dist/{unicorn.mjs → configs/unicorn.mjs} +3 -3
  185. package/dist/configs/unnecessary-abstractions.d.mts +8 -0
  186. package/dist/{unnecessary-abstractions.mjs → configs/unnecessary-abstractions.mjs} +3 -3
  187. package/dist/configs/unocss.d.mts +8 -0
  188. package/dist/{unocss.mjs → configs/unocss.mjs} +3 -3
  189. package/dist/configs/unused-imports.d.mts +17 -0
  190. package/dist/{unused-imports.mjs → configs/unused-imports.mjs} +3 -3
  191. package/dist/configs/vitest.d.mts +65 -0
  192. package/dist/{vitest.mjs → configs/vitest.mjs} +7 -6
  193. package/dist/configs/vue.d.mts +225 -0
  194. package/dist/{vue.mjs → configs/vue.mjs} +7 -6
  195. package/dist/configs/web-components.d.mts +21 -0
  196. package/dist/{web-components.mjs → configs/web-components.mjs} +3 -3
  197. package/dist/configs/yaml.d.mts +36 -0
  198. package/dist/{yaml.mjs → configs/yaml.mjs} +6 -6
  199. package/dist/configs/you-dont-need-lodash-underscore.d.mts +15 -0
  200. package/dist/{you-dont-need-lodash-underscore.mjs → configs/you-dont-need-lodash-underscore.mjs} +3 -3
  201. package/dist/configs/zod.d.mts +46 -0
  202. package/dist/{zod.mjs → configs/zod.mjs} +3 -3
  203. package/dist/constants.d.mts +12 -0
  204. package/dist/constants.mjs +3 -83
  205. package/dist/{no-stylistic-rules.mjs → eslint-rules.gen.mjs} +3 -760
  206. package/dist/eslint-types-fixable-only.gen.d.mts +4 -0
  207. package/dist/eslint-types-per-plugin.gen.d.mts +33537 -0
  208. package/dist/eslint-types.gen.d.mts +33076 -0
  209. package/dist/eslint.d.mts +35 -75618
  210. package/dist/eslint.mjs +63 -40
  211. package/dist/index.d.mts +5 -1
  212. package/dist/index.mjs +5 -908
  213. package/dist/loaders/index.d.mts +3 -0
  214. package/dist/loaders/index.mjs +5 -0
  215. package/dist/loaders/packages.d.mts +54 -0
  216. package/dist/loaders/packages.mjs +34 -0
  217. package/dist/loaders/parsers.d.mts +28 -0
  218. package/dist/loaders/parsers.mjs +19 -0
  219. package/dist/loaders/plugins.d.mts +3720 -0
  220. package/dist/{loaders.mjs → loaders/plugins.mjs} +4 -80
  221. package/dist/loaders/shared.d.mts +15 -0
  222. package/dist/loaders/shared.mjs +34 -0
  223. package/dist/node_modules/import-meta-resolve/index.mjs +34 -0
  224. package/dist/node_modules/import-meta-resolve/lib/errors.mjs +342 -0
  225. package/dist/node_modules/import-meta-resolve/lib/get-format.mjs +109 -0
  226. package/dist/node_modules/import-meta-resolve/lib/package-json-reader.mjs +102 -0
  227. package/dist/node_modules/import-meta-resolve/lib/resolve.mjs +681 -0
  228. package/dist/node_modules/import-meta-resolve/lib/utils.mjs +32 -0
  229. package/dist/node_modules/is-in-editor/dist/index.mjs +192 -0
  230. package/dist/package.mjs +82 -0
  231. package/dist/plugin-un/index.mjs +17 -0
  232. package/dist/plugin-un/rules/no-multiple-consecutive-spaces.mjs +50 -0
  233. package/dist/plugin-un/rules/no-typeof-like-comparisons.mjs +72 -0
  234. package/dist/plugin-un/rules/prefer-early-return.mjs +58 -0
  235. package/dist/snippets.d.mts +2 -1
  236. package/dist/snippets.mjs +1 -1
  237. package/dist/types.d.mts +9 -0
  238. package/dist/utils.d.mts +27 -0
  239. package/dist/utils.mjs +12 -1471
  240. package/package.json +12 -6
  241. package/dist/check-file.mjs +0 -21
  242. package/dist/configs.mjs +0 -1
  243. package/dist/plugin-un.mjs +0 -181
  244. package/dist/un.mjs +0 -20
package/README.md CHANGED
@@ -4,7 +4,7 @@ Grown out of the personal collection of rules, an ESLint config aspiring to cove
4
4
 
5
5
  ## Features
6
6
 
7
- - **Every major plugin** is included (50+ in total):
7
+ - **Every major plugin** is included (100+ in total):
8
8
  [![JavaScript](./assets/devicon-javascript.svg) Vanilla JS rules](https://eslint.org/docs/latest/rules),
9
9
  [![TypeScript] typescript-eslint](https://typescript-eslint.io/rules),
10
10
  [🦄unicorn](https://npmjs.com/eslint-plugin-unicorn),
@@ -138,7 +138,8 @@ export default eslintConfig({
138
138
  > [!NOTE]
139
139
  > We highly recommend using TypeScript config file, which is supported since ESLint v9.18.0, or [`@ts-check` directive](https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html#ts-check) at the start of the file otherwise.
140
140
 
141
- ## List of configs
141
+ <!-- eslint-disable-next-line markdown-preferences/heading-casing -->
142
+ ## Configs and Sub-configs
142
143
 
143
144
  eslint-config-un has a concept of Configs and Sub-configs, further referred to as Configs.
144
145
  They are similar to ESLint flat config objects, but with some useful extensions.
@@ -148,12 +149,28 @@ You can enable any Config by setting it to `true` or an object with the Config's
148
149
  Passing `false` disables the Config.
149
150
  Passing an empty array to `files` disables the Config, but not its' Sub-configs.
150
151
 
151
- <details>
152
- <summary>Config interface & docs</summary>
152
+ Sub-config is a Config located within Config's options.
153
+ If the parent config is disabled by passing `false`, all its' Sub-configs are disabled too.
154
+
155
+ After evaluating all the flat configs, eslint-config-un will **load only those plugins that were actually used**, unless `loadPluginsOnDemand` option is set to `false`.
156
+
157
+ ### Config (`UnConfig`) interface
153
158
 
154
159
  The Config has the following interface (exact types are simplified for docs):
155
160
 
156
161
  ```ts
162
+ type Severity = 0 | 1 | 2 | 'off' | 'warn' | 'error';
163
+
164
+ type RuleOptions = { /* ... pre-generated all rules' options */ };
165
+
166
+ type UnRuleEntry<RuleName extends string> = Severity | [Severity, RuleOptions[RuleName]] | {
167
+ severity: Severity;
168
+ options?: RuleOptions[RuleName];
169
+ disableAutofix?: boolean;
170
+ files?: string[];
171
+ ignores?: string[];
172
+ }
173
+
157
174
  type UnConfig =
158
175
  | boolean
159
176
  | {
@@ -162,43 +179,73 @@ type UnConfig =
162
179
 
163
180
  [RuleName in ('overrides' | 'overridesAny')]?: {
164
181
  [RuleName in string]:
165
- | Severity
166
- | [Severity, RuleOptions[RuleName]]
182
+ | UnRuleEntry<RuleName>
167
183
  | ((
168
184
  // These are severity and options *maybe* set by eslint-config-un
169
- ourSeverity: Severity,
170
- ourOptions?: RuleOptions[RuleName],
171
- ) => Severity | [Severity, RuleOptions[RuleName]]);
185
+ unRuleSeverity: Severity,
186
+ unRuleOptions?: RuleOptions[RuleName],
187
+ ) => UnRuleEntry<RuleName>);
172
188
  };
173
189
 
174
190
  forceSeverity?: '2' | 'error' | '1' | 'warn';
175
-
176
191
  [`config${string}`]: UnConfig; // These are Sub-configs
177
-
178
192
  [customOptions: string]: unknown; // Custom options, individual for each Config
179
193
  };
180
-
181
- type Severity = 0 | 1 | 2 | 'off' | 'warn' | 'error';
182
194
  ```
183
195
 
184
- </details>
196
+ #### `files` and `ignores`
185
197
 
186
- <br>
198
+ They have exactly the same meaning as the corresponding ESLint flat config item properties, with the only difference being an empty array `[]` handling:
187
199
 
188
- - Sub-configs are the same as Configs, but configured within Config options.
189
- All Sub-configs use `configXXX` naming convention.
190
- - After evaluating all the flat configs, eslint-config-un will **load only those plugins that were actually used**, unless `loadPluginsOnDemand` option is set to `false`.
191
- - `files` and `ignores` have exactly the same meaning as the corresponding ESLint flat config item properties, with the only difference being an empty array `[]` handling:
192
- - If you specify an empty array for `files`, the Config **will be disabled**, but of its' Sub-configs remain unaffected.
193
- - If you specify an empty array for `ignores`, the default ignore list won't be used.
194
- - `overrides`/`overridesAny` is similar to ESLint's `rules`, but with a very important advantage: you can provide a function that will be called with the rule severity and options set by eslint-config-un, which allows you to **granularly override the options** or change the severity of each rule.
195
- - The difference between `overrides` and `overridesAny` is that `overridesAny` will allow *any* rule to be overridden (from TypeScript's stand point; technically you can pass any rule to `overrides` too), while `overrides` will only allow those rules which are tied to the config.
196
- - `overridesAny` will be applied **after** `overrides`.
197
- - `forceSeverity` allows to bulk override the severity of all the rules not overridden via `overrides` or `overridesAny`.
198
- - Custom options are individual for each Config and are documented in JSDoc format.
200
+ - If you specify an empty array for `files`, the Config **will be disabled**, but of its' Sub-configs remain unaffected.
201
+ - If you specify an empty array for `ignores`, the default ignore list won't be used.
202
+
203
+ #### `overrides` and `overridesAny`
204
+
205
+ These are similar to ESLint's `rules`, but with a very important advantage: you can provide a function that will be called with the rule severity and options set by eslint-config-un, which allows you to **granularly override the options** or change the severity of each rule.
206
+
207
+ - The difference between `overrides` and `overridesAny` is that `overridesAny` will allow *any* rule to be overridden (from TypeScript's stand point; technically you can pass any rule to `overrides` too), while `overrides` will only allow those rules which are tied to the config.
208
+ - `overridesAny` will be applied **after** `overrides`.
209
+
210
+ #### Sub-configs
211
+
212
+ Sub-configs are the same as Configs, but configured within Config options.
213
+ All Sub-configs use `configXXX` naming convention.
214
+
215
+ #### `forceSeverity`
216
+
217
+ Allows to bulk override the severity of all the rules not overridden via `overrides` or `overridesAny`.
218
+
219
+ #### Custom options
220
+
221
+ Custom options are individual for each Config and are documented in JSDoc format.
222
+
223
+ ### Rule entry (`UnRuleEntry`) interface
224
+
225
+ #### `severity` and `options`
226
+
227
+ Normal ESLint severity and rule options.
228
+
229
+ #### `disableAutofix`
230
+
231
+ Apply a copy of the rule with `disable-autofix/` prefix and all autofixes disabled.
232
+
233
+ #### `files` and `ignores`
234
+
235
+ Allows to limit to which files only the current rule will be applied.
236
+ Only works if:
237
+
238
+ - At least one of `files` or `ignores` is provided and non-empty;
239
+ - `files` or the current Config is not an empty array.
240
+
241
+ If these conditions are met, a separate Config will be created with:
242
+
243
+ - `name` being the current Config's name with `/@rule/<rule name with prefix>` postfix;
244
+ - `files` [intersected with the parent's `files`](https://eslint.org/docs/latest/use/configure/configuration-files#specifying-files-with-an-and-operation);
245
+ - `ignores` merged with the parent's `ignores`.
246
+
247
+ ## List of configs
199
248
 
200
- Sub-config is a Config located within Config's options.
201
- If the parent config is disabled by passing `false`, all its' Sub-configs are disabled too.
202
249
  In the following table, Sub-configs have `/` in their names.
203
250
 
204
251
  ### Most popular and well known
@@ -369,7 +416,7 @@ In the following table, Sub-configs have `/` in their names.
369
416
  | `noSecrets/json` | ✅ | ^ | Applied only to `.json` files by default |
370
417
  | `expectType` | ❌ | [eslint-plugin-expect-type](https://npmjs.com/eslint-plugin-expect-type) (`expect-type`) | Since v1.0.0 |
371
418
  | `command` | ❌ | [eslint-plugin-command](https://npmjs.com/eslint-plugin-command) (`command`) | Since v1.0.0 |
372
- | `antfu` | ❌ | [eslint-plugin-antfu](https://npmjs.com/eslint-plugin-antfu) (`antfu`) | Since v1.0.0<br>[Anthony Fu](https://antfu.me/)'s personal collection of rules. |
419
+ | `antfu` | ❌ | [eslint-plugin-antfu](https://npmjs.com/eslint-plugin-antfu) (`antfu`) | Since v1.0.0<br>[Anthony Fu](https://antfu.me)'s personal collection of rules. |
373
420
 
374
421
  ## How to use
375
422
 
@@ -776,34 +823,45 @@ Please don't attempt to migrate to ESLint 9 and eslint-config-un at the same tim
776
823
 
777
824
  ### Migration guide
778
825
 
779
- We recommend that every step and sub-step below is done in a separate commit and on a separate git branch.
826
+ We recommend that every step and sub-step below is done in a separate commit and on a separate git branch.
827
+ If necessary, any step should be additionally split into multiple commits.
780
828
  Before committing, please do also run tests, formatter, other linters and tools to ensure that nothing became broken, if you have any.
781
829
 
782
- 1. Remove **ALL** ESLint related *dev* dependencies - be it plugins, parsers, whatever else or `eslint` itself.
783
- This ensures correct versions of plugins will be resolved by eslint-config-un and saves you from other weird and hard to debug problems.
784
- 2. If you're using `.js` config file, we highly recommend that you migrate to `.ts` one, or at least add `@ts-check` TypeScript directive to the former.
830
+ 1. Dependencies:
831
+ 1. Remove **ALL** ESLint related *dev* dependencies - be it plugins, parsers, whatever else or `eslint` itself.
832
+ This ensures correct versions of plugins will be resolved by eslint-config-un and saves you from other weird and hard to debug problems.
833
+ 2. Install `eslint-config-un` following [the installation instructions](#installation).
834
+ 2. If you're using `.js` config file, we highly recommend that you migrate to `.ts` one, or at least add `@ts-check` TypeScript directive to the former.
785
835
  Please don't forget install [`jiti`](https://npmjs.com/jiti) for ESLint to able be to read your TypeScript config file.
786
836
  3. Following your intuition or/and configs' options JSDoc documentation, migrate the existing config to the closest eslint-config-un equivalent.
787
837
  1. Run ESLint for the first time (without `--fix`!).
788
838
  The list of dependencies to be installed might be shown to you.
789
839
  Please review whether those plugins are actually used/needed and act accordingly: install necessary plugins and disable configs which require packages you do not wish to install.
790
840
  2. Rename rules on existing [`eslint` configuration comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments) if they have different plugin prefixes (the most common case is that `typescript-eslint` plugin has `ts` prefix in eslint-config-un instead of `@typescript-eslint`) **OR** change prefixes using [`pluginRenames` option](#plugin-prefixes-pluginrenames-option).
841
+ Look for `Definition for rule '<rule name>' was not found` comments
791
842
  4. Perform the following two steps in any order:
792
843
  1. Enable stylistic rules only and fix them automatically (if you wish to do so) by running ESLint with `--fix --fix-type problem,suggestion,layout` (the latter flag ensures auto removal of "unused" `eslint-disable` comments will not happen):
793
844
 
794
845
  ```ts
795
- noStylisticRules: {
796
- enableRules: {
797
- rules: true,
798
- disableAllOtherRules: true,
846
+ // ...
847
+ configs: {
848
+ // ...
849
+ noStylisticRules: {
850
+ enableRules: {
851
+ rules: true,
852
+ disableAllOtherRules: true,
853
+ },
799
854
  },
800
- }
855
+ // ...
856
+ },
857
+ // ...
801
858
  ```
802
859
 
803
860
  **Note:** not every stylistic rule is auto-fixable and not all auto-fixes are safe to apply automatically (although we already maintain a list of rules for which we've disabled autofixes by default for these reasons).
804
861
 
805
862
  Please carefully review automatically applied fixes and do not forget about problems requiring manual intervention.
806
- 2. Set `configs.noStylisticRules` to `true` to disable purely stylistic rules and run ESLint for the first time with the new config.
863
+ It might be worth to fix stylistic issues in two stages: auto and manually fixable problems.
864
+ 2. Now set `configs.noStylisticRules` to `true` to disable purely stylistic rules and run ESLint for the first time with the new config.
807
865
  Please don't use `--fix` option - this may complicate things as you will have less idea of what's changed (plus some autofixes may be unsafe to automatically apply).
808
866
  Thoroughly go through the report and:
809
867
  - Decide which rules need to be disabled, enabled or changed the options of;
@@ -0,0 +1,133 @@
1
+ import { createTraverser, groupBy, isObject, isPlainObject, omit, readAndParseJson, readFileSafe } from "../utils.mjs";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import crypto from "node:crypto";
5
+ import * as findUp from "empathic/find";
6
+ import * as packageUtils from "empathic/package";
7
+ import { LOCKS } from "package-manager-detector/constants";
8
+ import { exec } from "tinyexec";
9
+
10
+ //#region src/config-un/cache.ts
11
+ const sha256 = (input) => {
12
+ const hashInstance = crypto.createHash("sha256");
13
+ if (typeof input === "string") hashInstance.update(input, "utf8");
14
+ else hashInstance.update(input);
15
+ return hashInstance.digest("hex");
16
+ };
17
+ const LOCKFILES_PER_PACKAGE_MANAGER = groupBy(Object.entries(LOCKS), ([, packageManager]) => packageManager);
18
+ const ESLINT_FLAT_CONFIG_FILE_NAMES = [
19
+ "eslint.config.js",
20
+ "eslint.config.mjs",
21
+ "eslint.config.cjs",
22
+ "eslint.config.ts",
23
+ "eslint.config.mts",
24
+ "eslint.config.cts"
25
+ ];
26
+ const computeCacheKey = async (context) => {
27
+ const result = [process.version, String(context.rootOptions.offlineMode)];
28
+ const packageManagerInfo = context.meta.usedPackageManager;
29
+ result.push(JSON.stringify(packageManagerInfo));
30
+ const gitignorePath = findUp.file(".gitignore");
31
+ const packageJsonPath = packageUtils.up();
32
+ const lockfilePaths = (packageManagerInfo ? LOCKFILES_PER_PACKAGE_MANAGER[packageManagerInfo.name].map(([lockfileName]) => lockfileName) : []).map((lockfileName) => findUp.file(lockfileName));
33
+ const eslintConfigPaths = ESLINT_FLAT_CONFIG_FILE_NAMES.map((eslintConfigFileName) => findUp.file(eslintConfigFileName));
34
+ const [gitHeadHashResult, ...filesToHash] = await Promise.all([
35
+ exec("git", ["rev-parse", "HEAD"]).then((v) => v, (error) => {
36
+ context.logger.warn("Error getting git HEAD hash:", error);
37
+ return null;
38
+ }),
39
+ gitignorePath && readFileSafe(gitignorePath, true),
40
+ packageJsonPath && readFileSafe(packageJsonPath, true),
41
+ Promise.all(lockfilePaths.map((lockfilePath) => lockfilePath ? readFileSafe(lockfilePath, true) : null)).then((files) => files.find((v) => v != null)),
42
+ Promise.all(eslintConfigPaths.map((eslintConfigPath) => eslintConfigPath ? readFileSafe(eslintConfigPath, true) : null)).then((files) => files.find((v) => v != null))
43
+ ]);
44
+ result.push(gitHeadHashResult ? gitHeadHashResult.exitCode ? String(gitHeadHashResult.exitCode) : gitHeadHashResult.stdout : "", ...filesToHash.map((file) => file ? sha256(file) : ""));
45
+ return {
46
+ source: result,
47
+ hash: sha256(JSON.stringify(result))
48
+ };
49
+ };
50
+ const MAX_CACHE_VALID_MS = 36e5;
51
+ const isCacheFresh = (cacheMetadata) => Date.now() < new Date(cacheMetadata.date).getTime() + MAX_CACHE_VALID_MS;
52
+ const resolveCacheFilePath = (context) => {
53
+ const cachePath = packageUtils.cache("eslint-config-un", { create: true });
54
+ if (!cachePath) {
55
+ context.logger.warn("Could not determine the cache path");
56
+ return cachePath;
57
+ }
58
+ return path.join(cachePath, "config.json");
59
+ };
60
+ const saveCacheToFs = async (context, cacheData) => {
61
+ const cachePath = resolveCacheFilePath(context);
62
+ if (!cachePath) {
63
+ context.logger.warn("Could not determine cache path");
64
+ return false;
65
+ }
66
+ const { hash: cacheKey, source: cacheKeyRaw } = await computeCacheKey(context);
67
+ const dataToStore = {
68
+ date: (/* @__PURE__ */ new Date()).toISOString(),
69
+ key: cacheKey,
70
+ ...cacheData,
71
+ usedParsers: Object.fromEntries(cacheData.usedParsers.entries()),
72
+ usedPackages: Object.fromEntries([...cacheData.usedPackages.entries()].map(([packageId, entries]) => [packageId, entries.map((info) => ({
73
+ ...omit(info, ["valueTransformFn", "path"]),
74
+ property: [info.path, info.property].filter(Boolean).join("."),
75
+ ...info.valueTransformFn && { valueTransformFn: [info.valueTransformFn.fn.toString(), info.valueTransformFn.scope] }
76
+ }))]))
77
+ };
78
+ let dataToStoreStringified;
79
+ try {
80
+ dataToStoreStringified = JSON.stringify(dataToStore);
81
+ } catch (error) {
82
+ context.logger.warn("Could not serialize configs to store in cache:", error);
83
+ return false;
84
+ }
85
+ const unserializablePaths = [];
86
+ createTraverser(dataToStore.configs).forEach(({ path: valuePath }, value) => {
87
+ if (typeof value === "function" || isObject(value) && !isPlainObject(value)) unserializablePaths.push([valuePath, value]);
88
+ });
89
+ if (unserializablePaths.length > 0) {
90
+ const unserializablePathsGrouped = Object.entries(groupBy(unserializablePaths, (v) => v[0][0])).map((values) => ({
91
+ configIndex: Number(values[0]),
92
+ configName: dataToStore.configs.at(Number(values[0]))?.name,
93
+ valuePaths: values[1].map(([valuePath]) => valuePath)
94
+ }));
95
+ context.logger.warn(`Could not serialize configs to store in cache because they contain unserializable data at paths:\n${unserializablePathsGrouped.map(({ configIndex, configName, valuePaths }) => `Config #${configIndex} ${configName ? `"${configName}"` : "[unnamed]"}:\n${valuePaths.map((valuePath) => ` - ${valuePath.slice(1).join(".")}`).join("\n")}`).join("\n")}`);
96
+ return false;
97
+ }
98
+ try {
99
+ await fs.writeFile(cachePath, dataToStoreStringified, "utf8");
100
+ context.debug(`Saved configs to cache, date: ${dataToStore.date}, key: ${cacheKeyRaw.join(",")}`);
101
+ return true;
102
+ } catch (error) {
103
+ context.logger.warn("Could not save cache data:", error);
104
+ return false;
105
+ }
106
+ };
107
+ const restoreCacheFromFs = async (context) => {
108
+ const cachePath = resolveCacheFilePath(context);
109
+ if (!cachePath) {
110
+ context.logger.warn("Could not determine cache path");
111
+ return null;
112
+ }
113
+ const [{ hash: cacheKey }, cachedData] = await Promise.all([computeCacheKey(context), readAndParseJson(cachePath)]);
114
+ if (cachedData?.key === cacheKey && Date.now() < new Date(cachedData.date).getTime() + MAX_CACHE_VALID_MS) return cachedData;
115
+ return null;
116
+ };
117
+ const saveCacheToMemory = async (context, data) => {
118
+ const cacheKey = await computeCacheKey(context);
119
+ globalThis.eslintConfigUnResolvedConfig = {
120
+ ...data,
121
+ key: cacheKey.hash,
122
+ date: (/* @__PURE__ */ new Date()).toISOString()
123
+ };
124
+ };
125
+ const restoreCacheFromMemory = async (context) => {
126
+ const cacheKey = await computeCacheKey(context);
127
+ const configInMemory = globalThis.eslintConfigUnResolvedConfig;
128
+ if (configInMemory?.key === cacheKey.hash && isCacheFresh(configInMemory)) return configInMemory;
129
+ return null;
130
+ };
131
+
132
+ //#endregion
133
+ export { restoreCacheFromFs, restoreCacheFromMemory, saveCacheToFs, saveCacheToMemory };
@@ -0,0 +1,76 @@
1
+ import { arraify, styleConfigName, stylePackageName, styleText } from "../utils.mjs";
2
+ import semver from "semver";
3
+
4
+ //#region src/config-un/config-utils.ts
5
+ const CONFIGS_MISC_GROUP_DISABLED_BY_DEFAULT = new Set([
6
+ "security",
7
+ "yaml",
8
+ "toml",
9
+ "json",
10
+ "jsonSchemaValidator",
11
+ "nodeDependencies",
12
+ "depend"
13
+ ]);
14
+ const CONFIGS_TO_NOT_REPORT_IF_UNNECESSARILY_ENABLED_OR_DISABLED = new Set(["fileProgress"]);
15
+ function getIsConfigEnabled(configName, defaultConditionOrPackageInstalled = true, { preCondition, requireAllListedPackagesToBeInstalled } = {}) {
16
+ const { configs = {}, defaultConfigsStatus } = this.rootOptions;
17
+ let enabledByUser;
18
+ let enabledBySystem;
19
+ let reason;
20
+ const providedConfig = configs[configName];
21
+ if (this.isTestMode) {
22
+ enabledBySystem ??= true;
23
+ reason ??= "all configs are enabled in the test mode";
24
+ }
25
+ if (providedConfig != null) {
26
+ enabledByUser ??= Boolean(providedConfig);
27
+ reason ??= "provided by the user";
28
+ }
29
+ if (defaultConfigsStatus === "all-disabled") {
30
+ enabledBySystem ??= false;
31
+ reason ??= "`defaultConfigsStatus` is set to `all-disabled`";
32
+ }
33
+ if (defaultConfigsStatus === "misc-enabled" && CONFIGS_MISC_GROUP_DISABLED_BY_DEFAULT.has(configName)) {
34
+ enabledBySystem ??= true;
35
+ reason ??= "`defaultConfigsStatus` is set to `misc-enabled` and the config is in the misc group";
36
+ }
37
+ if (typeof defaultConditionOrPackageInstalled === "string" || Array.isArray(defaultConditionOrPackageInstalled) && defaultConditionOrPackageInstalled.length > 0) {
38
+ const packagesList = arraify(defaultConditionOrPackageInstalled).map((packageNameAndMaybeVersionRange) => {
39
+ const [packageName = "", versionRangeToSatisfy] = packageNameAndMaybeVersionRange.split("|");
40
+ return {
41
+ packageName,
42
+ versionRangeToSatisfy
43
+ };
44
+ });
45
+ if (requireAllListedPackagesToBeInstalled && packagesList.length > 1) {
46
+ const notInstalledPackages = packagesList.filter(({ packageName, versionRangeToSatisfy }) => {
47
+ const packageInfo = this.packagesInfo[packageName];
48
+ return !packageInfo || versionRangeToSatisfy && !semver.satisfies(packageInfo.info.version, versionRangeToSatisfy);
49
+ });
50
+ enabledBySystem ??= notInstalledPackages.length === 0;
51
+ reason ??= `${enabledBySystem ? "all of these packages were installed" : `the following package${notInstalledPackages.length === 1 ? " is" : "s are"} not installed`}: ${(enabledBySystem ? packagesList : notInstalledPackages).map(({ packageName }) => stylePackageName(packageName)).join(", ")}`;
52
+ } else {
53
+ enabledBySystem ??= packagesList.some(({ packageName }) => {
54
+ const isInstalled = Boolean(this.packagesInfo[packageName]);
55
+ if (isInstalled) reason ??= `package ${stylePackageName(packageName)} is installed`;
56
+ return isInstalled;
57
+ });
58
+ reason ??= packagesList.length > 1 ? `neither of these packages are installed: ${packagesList.map(({ packageName }) => stylePackageName(packageName)).join(", ")}` : `package ${stylePackageName(packagesList[0]?.packageName || "")} is not installed`;
59
+ }
60
+ } else if (typeof defaultConditionOrPackageInstalled === "boolean") {
61
+ enabledBySystem ??= defaultConditionOrPackageInstalled;
62
+ reason ??= `config is ${defaultConditionOrPackageInstalled ? "enabled" : "disabled"} by default`;
63
+ }
64
+ if (preCondition) {
65
+ enabledBySystem &&= preCondition[0];
66
+ reason = `${reason} and the following condition was${enabledBySystem ? "" : styleText("redBright", " not")} met: ${preCondition[1]}`;
67
+ }
68
+ enabledBySystem ??= false;
69
+ if (typeof enabledByUser === "boolean" && typeof providedConfig === "boolean" && enabledByUser === enabledBySystem && !CONFIGS_TO_NOT_REPORT_IF_UNNECESSARILY_ENABLED_OR_DISABLED.has(configName)) this.logger.warn(`There is no need to ${enabledByUser ? "enable" : "disable"} \`${styleConfigName(configName)}\` config because this is the default`);
70
+ const isEnabled = enabledByUser ?? enabledBySystem;
71
+ this.debug(`Config \`${styleConfigName(configName)}\` is ${isEnabled ? styleText("green", "enabled") : styleText("red", "disabled")} because ${reason}`);
72
+ return isEnabled;
73
+ }
74
+
75
+ //#endregion
76
+ export { getIsConfigEnabled };