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.
- package/README.md +97 -39
- package/dist/config-un/cache.mjs +133 -0
- package/dist/config-un/config-utils.mjs +76 -0
- package/dist/config-un/config.mjs +467 -0
- package/dist/config-un/fast-import.d.mts +14 -0
- package/dist/config-un/fast-import.mjs +35 -0
- package/dist/config-un/is-module-loaded.mjs +21 -0
- package/dist/config-un/resolve-config-async-data.mjs +198 -0
- package/dist/config-un/shared.d.mts +250 -0
- package/dist/config-un/shared.mjs +23 -0
- package/dist/configs/angular.d.mts +151 -0
- package/dist/{angular.mjs → configs/angular.mjs} +7 -5
- package/dist/configs/antfu.d.mts +8 -0
- package/dist/{antfu.mjs → configs/antfu.mjs} +3 -3
- package/dist/configs/astro.d.mts +20 -0
- package/dist/{astro.mjs → configs/astro.mjs} +6 -4
- package/dist/configs/ava.d.mts +26 -0
- package/dist/{ava.mjs → configs/ava.mjs} +4 -4
- package/dist/configs/better-tailwind.d.mts +67 -0
- package/dist/{better-tailwind.mjs → configs/better-tailwind.mjs} +3 -3
- package/dist/configs/boundaries.d.mts +18 -0
- package/dist/{boundaries.mjs → configs/boundaries.mjs} +3 -3
- package/dist/configs/case-police.d.mts +8 -0
- package/dist/{case-police.mjs → configs/case-police.mjs} +3 -3
- package/dist/configs/check-file.d.mts +31 -0
- package/dist/configs/check-file.mjs +22 -0
- package/dist/configs/command.d.mts +8 -0
- package/dist/{command.mjs → configs/command.mjs} +3 -3
- package/dist/configs/compat.d.mts +24 -0
- package/dist/{compat.mjs → configs/compat.mjs} +3 -3
- package/dist/configs/cspell.d.mts +13 -0
- package/dist/{cspell.mjs → configs/cspell.mjs} +3 -3
- package/dist/configs/css-in-js.d.mts +49 -0
- package/dist/{css-in-js.mjs → configs/css-in-js.mjs} +3 -3
- package/dist/configs/css.d.mts +40 -0
- package/dist/{css.mjs → configs/css.mjs} +5 -4
- package/dist/configs/cypress.d.mts +9 -0
- package/dist/{cypress.mjs → configs/cypress.mjs} +4 -4
- package/dist/configs/de-morgan.d.mts +8 -0
- package/dist/{de-morgan.mjs → configs/de-morgan.mjs} +3 -3
- package/dist/configs/depend.d.mts +13 -0
- package/dist/{depend.mjs → configs/depend.mjs} +3 -3
- package/dist/configs/docusaurus.d.mts +8 -0
- package/dist/{docusaurus.mjs → configs/docusaurus.mjs} +3 -3
- package/dist/configs/ember.d.mts +25 -0
- package/dist/{ember.mjs → configs/ember.mjs} +4 -4
- package/dist/configs/erasable-syntax-only.d.mts +19 -0
- package/dist/{erasable-syntax-only.mjs → configs/erasable-syntax-only.mjs} +3 -3
- package/dist/configs/es.d.mts +59 -0
- package/dist/{es.mjs → configs/es.mjs} +3 -3
- package/dist/configs/eslint-comments.d.mts +8 -0
- package/dist/{eslint-comments.mjs → configs/eslint-comments.mjs} +3 -3
- package/dist/configs/eslint-plugin.d.mts +34 -0
- package/dist/{eslint-plugin.mjs → configs/eslint-plugin.mjs} +4 -4
- package/dist/configs/expect-type.d.mts +13 -0
- package/dist/{expect-type.mjs → configs/expect-type.mjs} +3 -3
- package/dist/configs/extra/cli.d.mts +14 -0
- package/dist/{cli.mjs → configs/extra/cli.mjs} +3 -3
- package/dist/configs/extra/cloudfront-functions.d.mts +14 -0
- package/dist/{cloudfront-functions.mjs → configs/extra/cloudfront-functions.mjs} +4 -4
- package/dist/configs/extra/no-stylistic-rules.d.mts +782 -0
- package/dist/configs/extra/no-stylistic-rules.mjs +758 -0
- package/dist/configs/fast-import.d.mts +27 -0
- package/dist/{fast-import.mjs → configs/fast-import.mjs} +3 -3
- package/dist/configs/file-progress.d.mts +29 -0
- package/dist/{file-progress.mjs → configs/file-progress.mjs} +4 -3
- package/dist/configs/formatjs.d.mts +67 -0
- package/dist/{formatjs.mjs → configs/formatjs.mjs} +3 -3
- package/dist/configs/graphql.d.mts +46 -0
- package/dist/{graphql.mjs → configs/graphql.mjs} +6 -4
- package/dist/configs/header.d.mts +33 -0
- package/dist/{header.mjs → configs/header.mjs} +3 -3
- package/dist/configs/headers.d.mts +38 -0
- package/dist/{headers.mjs → configs/headers.mjs} +3 -3
- package/dist/configs/html.d.mts +43 -0
- package/dist/{html.mjs → configs/html.mjs} +4 -4
- package/dist/configs/import-zod.d.mts +8 -0
- package/dist/{import-zod.mjs → configs/import-zod.mjs} +3 -3
- package/dist/configs/import.d.mts +62 -0
- package/dist/{import.mjs → configs/import.mjs} +5 -4
- package/dist/configs/index.d.mts +1116 -0
- package/dist/configs/index.mjs +3 -0
- package/dist/configs/jest-dom.d.mts +8 -0
- package/dist/{jest-dom.mjs → configs/jest-dom.mjs} +4 -4
- package/dist/configs/jest.d.mts +125 -0
- package/dist/{jest.mjs → configs/jest.mjs} +6 -5
- package/dist/configs/js-inline.d.mts +81 -0
- package/dist/{js-inline.mjs → configs/js-inline.mjs} +5 -4
- package/dist/configs/js.d.mts +14 -0
- package/dist/{js.mjs → configs/js.mjs} +3 -3
- package/dist/configs/jsdoc.d.mts +160 -0
- package/dist/{jsdoc.mjs → configs/jsdoc.mjs} +3 -3
- package/dist/configs/json-schema-validator.d.mts +26 -0
- package/dist/{json-schema-validator.mjs → configs/json-schema-validator.mjs} +4 -4
- package/dist/configs/jsonc.d.mts +30 -0
- package/dist/{jsonc.mjs → configs/jsonc.mjs} +4 -4
- package/dist/configs/jsx-a11y.d.mts +206 -0
- package/dist/{jsx-a11y.mjs → configs/jsx-a11y.mjs} +3 -3
- package/dist/configs/lit.d.mts +51 -0
- package/dist/{lit.mjs → configs/lit.mjs} +3 -3
- package/dist/configs/markdown-links.d.mts +24 -0
- package/dist/{markdown-links.mjs → configs/markdown-links.mjs} +3 -3
- package/dist/configs/markdown-preferences.d.mts +138 -0
- package/dist/{markdown-preferences.mjs → configs/markdown-preferences.mjs} +18 -12
- package/dist/configs/markdown.d.mts +96 -0
- package/dist/{markdown.mjs → configs/markdown.mjs} +9 -8
- package/dist/configs/math.d.mts +14 -0
- package/dist/{math.mjs → configs/math.mjs} +3 -3
- package/dist/configs/mdx.d.mts +25 -0
- package/dist/{mdx.mjs → configs/mdx.mjs} +6 -5
- package/dist/configs/mocha.d.mts +35 -0
- package/dist/{mocha.mjs → configs/mocha.mjs} +4 -4
- package/dist/configs/module-interop.d.mts +8 -0
- package/dist/{module-interop.mjs → configs/module-interop.mjs} +3 -3
- package/dist/configs/nest-js.d.mts +8 -0
- package/dist/{nest-js.mjs → configs/nest-js.mjs} +3 -3
- package/dist/configs/nextjs.d.mts +22 -0
- package/dist/{nextjs.mjs → configs/nextjs.mjs} +3 -3
- package/dist/configs/no-only-tests.d.mts +8 -0
- package/dist/{no-only-tests.mjs → configs/no-only-tests.mjs} +4 -4
- package/dist/configs/no-secrets.d.mts +24 -0
- package/dist/{no-secrets.mjs → configs/no-secrets.mjs} +4 -5
- package/dist/configs/no-unsanitized.d.mts +8 -0
- package/dist/{no-unsanitized.mjs → configs/no-unsanitized.mjs} +3 -3
- package/dist/configs/node-dependencies.d.mts +19 -0
- package/dist/{node-dependencies.mjs → configs/node-dependencies.mjs} +3 -3
- package/dist/configs/node.d.mts +157 -0
- package/dist/{node.mjs → configs/node.mjs} +3 -3
- package/dist/configs/nx.d.mts +13 -0
- package/dist/{nx.mjs → configs/nx.mjs} +3 -3
- package/dist/configs/package-json.d.mts +80 -0
- package/dist/{package-json.mjs → configs/package-json.mjs} +3 -3
- package/dist/configs/perfectionist.d.mts +101 -0
- package/dist/{perfectionist.mjs → configs/perfectionist.mjs} +3 -3
- package/dist/configs/playwright.d.mts +44 -0
- package/dist/{playwright.mjs → configs/playwright.mjs} +4 -4
- package/dist/configs/pnpm.d.mts +56 -0
- package/dist/{pnpm.mjs → configs/pnpm.mjs} +3 -3
- package/dist/configs/prefer-arrow-functions.d.mts +8 -0
- package/dist/{prefer-arrow-functions.mjs → configs/prefer-arrow-functions.mjs} +3 -3
- package/dist/configs/promise.d.mts +8 -0
- package/dist/{promise.mjs → configs/promise.mjs} +3 -3
- package/dist/configs/qunit.d.mts +9 -0
- package/dist/{qunit.mjs → configs/qunit.mjs} +4 -4
- package/dist/configs/qwik.d.mts +10 -0
- package/dist/{qwik.mjs → configs/qwik.mjs} +3 -3
- package/dist/configs/react.d.mts +330 -0
- package/dist/{react.mjs → configs/react.mjs} +4 -4
- package/dist/configs/regexp.d.mts +8 -0
- package/dist/{regexp.mjs → configs/regexp.mjs} +3 -3
- package/dist/configs/rxjs.d.mts +34 -0
- package/dist/{rxjs.mjs → configs/rxjs.mjs} +3 -3
- package/dist/configs/security.d.mts +8 -0
- package/dist/{security.mjs → configs/security.mjs} +3 -3
- package/dist/configs/shared.d.mts +42 -0
- package/dist/{shared.mjs → configs/shared.mjs} +8 -3
- package/dist/configs/solid.d.mts +8 -0
- package/dist/{solid.mjs → configs/solid.mjs} +3 -3
- package/dist/configs/sonar.d.mts +24 -0
- package/dist/{sonar.mjs → configs/sonar.mjs} +3 -3
- package/dist/configs/storybook.d.mts +8 -0
- package/dist/{storybook.mjs → configs/storybook.mjs} +3 -3
- package/dist/configs/stylistic.d.mts +17 -0
- package/dist/{stylistic.mjs → configs/stylistic.mjs} +5 -4
- package/dist/configs/svelte.d.mts +81 -0
- package/dist/{svelte.mjs → configs/svelte.mjs} +7 -5
- package/dist/configs/tailwind.d.mts +29 -0
- package/dist/{tailwind.mjs → configs/tailwind.mjs} +3 -3
- package/dist/configs/tanstack-query.d.mts +8 -0
- package/dist/{tanstack-query.mjs → configs/tanstack-query.mjs} +3 -3
- package/dist/configs/testing-library.d.mts +76 -0
- package/dist/{testing-library.mjs → configs/testing-library.mjs} +4 -4
- package/dist/configs/toml.d.mts +34 -0
- package/dist/{toml.mjs → configs/toml.mjs} +6 -6
- package/dist/configs/tree-shaking.d.mts +13 -0
- package/dist/{tree-shaking.mjs → configs/tree-shaking.mjs} +3 -3
- package/dist/configs/ts.d.mts +136 -0
- package/dist/{ts.mjs → configs/ts.mjs} +6 -5
- package/dist/configs/turbo.d.mts +14 -0
- package/dist/{turbo.mjs → configs/turbo.mjs} +3 -3
- package/dist/configs/un.d.mts +8 -0
- package/dist/configs/un.mjs +17 -0
- package/dist/configs/unicorn.d.mts +21 -0
- package/dist/{unicorn.mjs → configs/unicorn.mjs} +3 -3
- package/dist/configs/unnecessary-abstractions.d.mts +8 -0
- package/dist/{unnecessary-abstractions.mjs → configs/unnecessary-abstractions.mjs} +3 -3
- package/dist/configs/unocss.d.mts +8 -0
- package/dist/{unocss.mjs → configs/unocss.mjs} +3 -3
- package/dist/configs/unused-imports.d.mts +17 -0
- package/dist/{unused-imports.mjs → configs/unused-imports.mjs} +3 -3
- package/dist/configs/vitest.d.mts +65 -0
- package/dist/{vitest.mjs → configs/vitest.mjs} +7 -6
- package/dist/configs/vue.d.mts +225 -0
- package/dist/{vue.mjs → configs/vue.mjs} +7 -6
- package/dist/configs/web-components.d.mts +21 -0
- package/dist/{web-components.mjs → configs/web-components.mjs} +3 -3
- package/dist/configs/yaml.d.mts +36 -0
- package/dist/{yaml.mjs → configs/yaml.mjs} +6 -6
- package/dist/configs/you-dont-need-lodash-underscore.d.mts +15 -0
- package/dist/{you-dont-need-lodash-underscore.mjs → configs/you-dont-need-lodash-underscore.mjs} +3 -3
- package/dist/configs/zod.d.mts +46 -0
- package/dist/{zod.mjs → configs/zod.mjs} +3 -3
- package/dist/constants.d.mts +12 -0
- package/dist/constants.mjs +3 -83
- package/dist/{no-stylistic-rules.mjs → eslint-rules.gen.mjs} +3 -760
- package/dist/eslint-types-fixable-only.gen.d.mts +4 -0
- package/dist/eslint-types-per-plugin.gen.d.mts +33537 -0
- package/dist/eslint-types.gen.d.mts +33076 -0
- package/dist/eslint.d.mts +35 -75618
- package/dist/eslint.mjs +63 -40
- package/dist/index.d.mts +5 -1
- package/dist/index.mjs +5 -908
- package/dist/loaders/index.d.mts +3 -0
- package/dist/loaders/index.mjs +5 -0
- package/dist/loaders/packages.d.mts +54 -0
- package/dist/loaders/packages.mjs +34 -0
- package/dist/loaders/parsers.d.mts +28 -0
- package/dist/loaders/parsers.mjs +19 -0
- package/dist/loaders/plugins.d.mts +3720 -0
- package/dist/{loaders.mjs → loaders/plugins.mjs} +4 -80
- package/dist/loaders/shared.d.mts +15 -0
- package/dist/loaders/shared.mjs +34 -0
- package/dist/node_modules/import-meta-resolve/index.mjs +34 -0
- package/dist/node_modules/import-meta-resolve/lib/errors.mjs +342 -0
- package/dist/node_modules/import-meta-resolve/lib/get-format.mjs +109 -0
- package/dist/node_modules/import-meta-resolve/lib/package-json-reader.mjs +102 -0
- package/dist/node_modules/import-meta-resolve/lib/resolve.mjs +681 -0
- package/dist/node_modules/import-meta-resolve/lib/utils.mjs +32 -0
- package/dist/node_modules/is-in-editor/dist/index.mjs +192 -0
- package/dist/package.mjs +82 -0
- package/dist/plugin-un/index.mjs +17 -0
- package/dist/plugin-un/rules/no-multiple-consecutive-spaces.mjs +50 -0
- package/dist/plugin-un/rules/no-typeof-like-comparisons.mjs +72 -0
- package/dist/plugin-un/rules/prefer-early-return.mjs +58 -0
- package/dist/snippets.d.mts +2 -1
- package/dist/snippets.mjs +1 -1
- package/dist/types.d.mts +9 -0
- package/dist/utils.d.mts +27 -0
- package/dist/utils.mjs +12 -1471
- package/package.json +12 -6
- package/dist/check-file.mjs +0 -21
- package/dist/configs.mjs +0 -1
- package/dist/plugin-un.mjs +0 -181
- 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 (
|
|
7
|
+
- **Every major plugin** is included (100+ in total):
|
|
8
8
|
[ 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
|
-
|
|
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
|
-
|
|
152
|
-
|
|
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
|
-
|
|
|
166
|
-
| [Severity, RuleOptions[RuleName]]
|
|
182
|
+
| UnRuleEntry<RuleName>
|
|
167
183
|
| ((
|
|
168
184
|
// These are severity and options *maybe* set by eslint-config-un
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
) =>
|
|
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
|
-
|
|
196
|
+
#### `files` and `ignores`
|
|
185
197
|
|
|
186
|
-
|
|
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
|
-
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
-
|
|
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
|
|
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.
|
|
783
|
-
|
|
784
|
-
|
|
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
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
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
|
-
|
|
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 };
|