@zayne-labs/eslint-config 0.13.13 → 0.13.15
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 +217 -27
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +58 -52
- package/dist/cli/index.js.map +1 -1
- package/dist/constants/defaults.d.ts +5 -6
- package/dist/{index-B8a2EaF4.d.ts → index-CH8E2ZDS.d.ts} +4508 -1256
- package/dist/index.d.ts +61 -53
- package/dist/index.js +355 -116
- package/dist/index.js.map +1 -1
- package/dist/{jsxRules-BAjKnxGs.js → jsxRules-DR1G9lbZ.js} +8 -14
- package/dist/jsxRules-DR1G9lbZ.js.map +1 -0
- package/dist/utils.d.ts +14 -16
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/package.json +83 -78
- package/dist/jsxRules-BAjKnxGs.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# @zayne-labs/eslint-config
|
|
2
2
|
|
|
3
|
+
[](https://npmjs.com/package/@zayne-labs/eslint-config)
|
|
4
|
+
|
|
3
5
|
Opinionated ESLint config with sensible defaults and zero-config setup.
|
|
4
6
|
|
|
5
7
|
- One-line setup with reasonable defaults and best practices
|
|
6
8
|
- Works out-of-the-box with TypeScript, JSX, Vue, JSON, YAML, TOML, Markdown, and more
|
|
7
9
|
- [ESLint Flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new) for easy composition
|
|
8
|
-
- Optional framework support: [Vue](#vue), [React](#react), [
|
|
10
|
+
- Optional framework support: [Vue](#vue), [React](#react), [Astro](#astro), [Solid](#solid), and [Expo](#expo-react-native)
|
|
11
|
+
- First-class integrations for [Better Tailwind CSS](#better-tailwind-css), [TanStack](#tanstack), [pnpm catalogs](#pnpm-workspaces-and-catalogs), and dependency checks
|
|
9
12
|
- Respects `.gitignore` by default
|
|
10
13
|
- Highly [customizable](#customization) when you need it
|
|
11
14
|
- Requires ESLint v9.5.0+ and Node.js v20+
|
|
@@ -25,10 +28,18 @@ pnpx @zayne-labs/eslint-config@latest
|
|
|
25
28
|
|
|
26
29
|
The CLI will guide you through:
|
|
27
30
|
|
|
28
|
-
- Framework selection (React, Vue,
|
|
29
|
-
- Additional integrations (TailwindCSS, etc.)
|
|
31
|
+
- Framework selection (React, Vue, Solid, Astro)
|
|
32
|
+
- Additional integrations (Better TailwindCSS, etc.)
|
|
30
33
|
- Automatic dependency installation
|
|
31
34
|
|
|
35
|
+
The wizard also supports non-interactive setup:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pnpx @zayne-labs/eslint-config@latest --yes --template react --extra tailwindcss-better
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Run it in a project that does not already have an `eslint.config.*` file. Existing legacy ESLint files are left untouched and listed for manual review after migration.
|
|
42
|
+
|
|
32
43
|
### Manual Installation
|
|
33
44
|
|
|
34
45
|
```bash
|
|
@@ -121,7 +132,6 @@ Install the [ESLint extension](https://marketplace.visualstudio.com/items?itemNa
|
|
|
121
132
|
"gql",
|
|
122
133
|
"graphql",
|
|
123
134
|
"astro",
|
|
124
|
-
"svelte",
|
|
125
135
|
"css",
|
|
126
136
|
"less",
|
|
127
137
|
"scss",
|
|
@@ -161,7 +171,6 @@ lspconfig.eslint.setup(
|
|
|
161
171
|
"gql",
|
|
162
172
|
"graphql",
|
|
163
173
|
"astro",
|
|
164
|
-
"svelte",
|
|
165
174
|
"css",
|
|
166
175
|
"less",
|
|
167
176
|
"scss",
|
|
@@ -211,7 +220,7 @@ export default zayne({
|
|
|
211
220
|
// Parse the `.gitignore` file to get the ignores, on by default
|
|
212
221
|
gitignore: true,
|
|
213
222
|
|
|
214
|
-
// Project type:
|
|
223
|
+
// Project type: "app" (default), "app-strict", "lib", or "lib-strict"
|
|
215
224
|
type: "app",
|
|
216
225
|
|
|
217
226
|
// Disable all optional configs at once (keeps only essentials)
|
|
@@ -236,6 +245,30 @@ export default zayne({
|
|
|
236
245
|
});
|
|
237
246
|
```
|
|
238
247
|
|
|
248
|
+
### Configuration Reference
|
|
249
|
+
|
|
250
|
+
The factory accepts booleans for simple enable/disable cases and option objects when an integration needs files, rule overrides, or plugin-specific settings.
|
|
251
|
+
|
|
252
|
+
| Option | Default | Purpose |
|
|
253
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------ | -------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
254
|
+
| `type` | `"app"` | Selects `"app"`, `"app-strict"`, `"lib"`, or `"lib-strict"` rule behavior. |
|
|
255
|
+
| `withDefaults` | `true` | Controls the standard optional baseline without disabling essential JavaScript, ignore, JSX, or command support. |
|
|
256
|
+
| `gitignore` | `true` | Reads the nearest `.gitignore`; accepts the underlying flat-gitignore options. |
|
|
257
|
+
| `typescript` | Auto-detected | Enables TypeScript rules and optional type-aware or erasable-syntax rules. |
|
|
258
|
+
| `react` | Auto-detected | Enables the React integration when React is installed. |
|
|
259
|
+
| `pnpm` | Auto-detected | Enables workspace rules when a `pnpm-workspace.yaml` is found. |
|
|
260
|
+
| `baseline`, `comments`, `imports`, `jsdoc`, `jsonc`, `markdown`, `node`, `perfectionist`, `regexp`, `stylistic`, `toml`, `unicorn`, `yaml` | `withDefaults` | Controls the standard integrations; Baseline defaults to widely available JS/TS compatibility warnings. |
|
|
261
|
+
| `astro`, `vue`, `solid`, `expo` | `false` | Enables framework-specific parsing and rules. |
|
|
262
|
+
| `depend`, `tailwindcssBetter`, `tanstack` | `false` | Enables optional dependency, Tailwind CSS, and TanStack integrations. |
|
|
263
|
+
|
|
264
|
+
Most integrations accept an `overrides` object. Integrations that apply to special file types also accept `files`. TypeScript, Baseline, and React provide separate type-aware file and override options, while Solid provides a separate `filesTypeAware` scope.
|
|
265
|
+
|
|
266
|
+
[Baseline JS](https://baselinejs.vercel.app/docs/config) automatically uses type-aware checks for TypeScript files when type-aware linting is active.
|
|
267
|
+
|
|
268
|
+
### Optional Dependencies
|
|
269
|
+
|
|
270
|
+
Optional framework and integration plugins are loaded only when their feature is enabled. In an interactive terminal outside CI, the config can offer to install a missing peer dependency. In CI and non-interactive environments, install the documented peers explicitly.
|
|
271
|
+
|
|
239
272
|
### Custom Rules
|
|
240
273
|
|
|
241
274
|
Pass additional configs as extra arguments:
|
|
@@ -264,6 +297,65 @@ export default zayne(
|
|
|
264
297
|
);
|
|
265
298
|
```
|
|
266
299
|
|
|
300
|
+
Rules from an integration can also be overridden alongside that integration. This keeps the correct file scope and parser configuration:
|
|
301
|
+
|
|
302
|
+
```js
|
|
303
|
+
import { zayne } from "@zayne-labs/eslint-config";
|
|
304
|
+
|
|
305
|
+
export default zayne({
|
|
306
|
+
react: {
|
|
307
|
+
overrides: {
|
|
308
|
+
"react/no-array-index-key": "off",
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
typescript: {
|
|
312
|
+
overrides: {
|
|
313
|
+
"ts-eslint/consistent-type-definitions": ["error", "type"],
|
|
314
|
+
},
|
|
315
|
+
overridesTypeAware: {
|
|
316
|
+
"ts-eslint/no-unsafe-assignment": "warn",
|
|
317
|
+
},
|
|
318
|
+
tsconfigPath: true,
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Plugin Renaming
|
|
324
|
+
|
|
325
|
+
Plugin prefixes are normalized by default so rule names stay stable if the underlying implementation package changes:
|
|
326
|
+
|
|
327
|
+
| Prefix | Original plugin prefix |
|
|
328
|
+
| ---------------------- | ---------------------- |
|
|
329
|
+
| `react/*` | `@eslint-react/*` |
|
|
330
|
+
| `nextjs/*` | `@next/next/*` |
|
|
331
|
+
| `stylistic/*` | `@stylistic/*` |
|
|
332
|
+
| `tanstack-query/*` | `@tanstack/query/*` |
|
|
333
|
+
| `tanstack-router/*` | `@tanstack/router/*` |
|
|
334
|
+
| `ts-eslint/*` | `@typescript-eslint/*` |
|
|
335
|
+
| `tailwindcss-better/*` | `better-tailwindcss/*` |
|
|
336
|
+
| `import/*` | `import-x/*` |
|
|
337
|
+
| `node/*` | `n/*` |
|
|
338
|
+
|
|
339
|
+
The factory also renames matching rule prefixes in custom configs. Set `autoRenamePlugins: false` to opt out, or use the returned composer's `renamePlugins()` method to define another mapping.
|
|
340
|
+
|
|
341
|
+
### Config Composer
|
|
342
|
+
|
|
343
|
+
`zayne()` returns a [`FlatConfigComposer`](https://github.com/antfu/eslint-flat-config-utils), so configurations can be inserted or overridden by their stable `zayne/*` names:
|
|
344
|
+
|
|
345
|
+
```js
|
|
346
|
+
import { zayne } from "@zayne-labs/eslint-config";
|
|
347
|
+
|
|
348
|
+
export default zayne()
|
|
349
|
+
.prepend({
|
|
350
|
+
ignores: ["**/generated/**"],
|
|
351
|
+
})
|
|
352
|
+
.override("zayne/stylistic/rules", {
|
|
353
|
+
rules: {
|
|
354
|
+
"stylistic/quotes": ["error", "single"],
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
267
359
|
### Advanced Composition
|
|
268
360
|
|
|
269
361
|
Import and compose fine-grained configs directly:
|
|
@@ -276,6 +368,8 @@ Import and compose fine-grained configs directly:
|
|
|
276
368
|
```js
|
|
277
369
|
import {
|
|
278
370
|
astro,
|
|
371
|
+
baseline,
|
|
372
|
+
command,
|
|
279
373
|
comments,
|
|
280
374
|
depend,
|
|
281
375
|
expo,
|
|
@@ -290,6 +384,7 @@ import {
|
|
|
290
384
|
perfectionist,
|
|
291
385
|
pnpm,
|
|
292
386
|
react,
|
|
387
|
+
regexp,
|
|
293
388
|
solid,
|
|
294
389
|
sortPackageJson,
|
|
295
390
|
sortTsconfig,
|
|
@@ -307,14 +402,17 @@ import { FlatConfigComposer } from "eslint-flat-config-utils";
|
|
|
307
402
|
export default new FlatConfigComposer().append(
|
|
308
403
|
ignores(),
|
|
309
404
|
javascript(),
|
|
405
|
+
command(),
|
|
310
406
|
typescript(),
|
|
311
407
|
jsx(),
|
|
408
|
+
baseline(),
|
|
312
409
|
comments(),
|
|
313
410
|
node(),
|
|
314
411
|
jsdoc(),
|
|
315
412
|
imports(),
|
|
316
413
|
unicorn(),
|
|
317
414
|
perfectionist(),
|
|
415
|
+
regexp(),
|
|
318
416
|
stylistic(),
|
|
319
417
|
react(),
|
|
320
418
|
vue(),
|
|
@@ -327,7 +425,7 @@ export default new FlatConfigComposer().append(
|
|
|
327
425
|
|
|
328
426
|
</details>
|
|
329
427
|
|
|
330
|
-
See [configs](https://github.com/zayne-labs/
|
|
428
|
+
See [configs](https://github.com/zayne-labs/config/tree/main/packages/eslint-config/src/configs) and [factory](https://github.com/zayne-labs/config/blob/main/packages/eslint-config/src/factory.ts) for implementation details.
|
|
331
429
|
|
|
332
430
|
> Thanks to [antfu/eslint-config](https://github.com/antfu/eslint-config) for the inspiration and reference.
|
|
333
431
|
|
|
@@ -345,10 +443,24 @@ export default zayne({
|
|
|
345
443
|
});
|
|
346
444
|
```
|
|
347
445
|
|
|
446
|
+
Vue 3 and custom SFC block processing are enabled by default. Vue 2 can be selected explicitly, accessibility rules are opt-in, and SFC block processing can be disabled when it is not needed:
|
|
447
|
+
|
|
448
|
+
```js
|
|
449
|
+
export default zayne({
|
|
450
|
+
vue: {
|
|
451
|
+
a11y: true,
|
|
452
|
+
sfcBlocks: false,
|
|
453
|
+
vueVersion: 2,
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
```
|
|
457
|
+
|
|
348
458
|
Install peer dependencies:
|
|
349
459
|
|
|
350
460
|
```bash
|
|
351
|
-
pnpm i -D eslint-plugin-vue vue-eslint-parser
|
|
461
|
+
pnpm i -D eslint-plugin-vue vue-eslint-parser eslint-processor-vue-blocks
|
|
462
|
+
# When a11y is enabled:
|
|
463
|
+
pnpm i -D eslint-plugin-vuejs-accessibility
|
|
352
464
|
```
|
|
353
465
|
|
|
354
466
|
### React
|
|
@@ -359,31 +471,38 @@ Auto-detected in most cases, or enable explicitly:
|
|
|
359
471
|
import { zayne } from "@zayne-labs/eslint-config";
|
|
360
472
|
|
|
361
473
|
export default zayne({
|
|
362
|
-
react:
|
|
474
|
+
react: {
|
|
475
|
+
compiler: true,
|
|
476
|
+
nextjs: true,
|
|
477
|
+
refresh: true,
|
|
478
|
+
youMightNotNeedAnEffect: true,
|
|
479
|
+
},
|
|
363
480
|
});
|
|
364
481
|
```
|
|
365
482
|
|
|
483
|
+
The base React integration, React Compiler checks, refresh rules, and effect guidance can each be configured or disabled independently. Next.js rules are enabled only through `react.nextjs`.
|
|
484
|
+
|
|
366
485
|
Install peer dependencies (prompted automatically when running ESLint):
|
|
367
486
|
|
|
368
487
|
```bash
|
|
369
|
-
pnpm i -D @eslint-react/eslint-plugin eslint-plugin-react-hooks eslint-plugin-react-refresh
|
|
488
|
+
pnpm i -D @eslint-react/eslint-plugin eslint-plugin-react-hooks eslint-plugin-react-refresh eslint-plugin-react-you-might-not-need-an-effect
|
|
489
|
+
# When react.nextjs is enabled:
|
|
490
|
+
pnpm i -D @next/eslint-plugin-next
|
|
370
491
|
```
|
|
371
492
|
|
|
372
|
-
|
|
493
|
+
#### Next.js
|
|
373
494
|
|
|
374
|
-
|
|
375
|
-
import { zayne } from "@zayne-labs/eslint-config";
|
|
495
|
+
Next.js is supported but must be enabled explicitly. Set `nextjs: true` inside the React integration:
|
|
376
496
|
|
|
497
|
+
```js
|
|
377
498
|
export default zayne({
|
|
378
|
-
|
|
499
|
+
react: {
|
|
500
|
+
nextjs: true,
|
|
501
|
+
},
|
|
379
502
|
});
|
|
380
503
|
```
|
|
381
504
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
```bash
|
|
385
|
-
pnpm i -D eslint-plugin-svelte
|
|
386
|
-
```
|
|
505
|
+
The integration combines the plugin's recommended and Core Web Vitals rules. Its refresh configuration also permits the standard Next.js route exports. Pass an object instead when custom `files` or `overrides` are needed.
|
|
387
506
|
|
|
388
507
|
### Astro
|
|
389
508
|
|
|
@@ -398,7 +517,7 @@ export default zayne({
|
|
|
398
517
|
Install peer dependencies:
|
|
399
518
|
|
|
400
519
|
```bash
|
|
401
|
-
pnpm i -D eslint-plugin-astro
|
|
520
|
+
pnpm i -D eslint-plugin-astro astro-eslint-parser
|
|
402
521
|
```
|
|
403
522
|
|
|
404
523
|
### Solid
|
|
@@ -417,7 +536,23 @@ Install peer dependencies:
|
|
|
417
536
|
pnpm i -D eslint-plugin-solid
|
|
418
537
|
```
|
|
419
538
|
|
|
420
|
-
###
|
|
539
|
+
### JSX Accessibility
|
|
540
|
+
|
|
541
|
+
JSX syntax is enabled by default. Accessibility rules are opt-in and work independently of the React integration:
|
|
542
|
+
|
|
543
|
+
```js
|
|
544
|
+
export default zayne({
|
|
545
|
+
jsx: {
|
|
546
|
+
a11y: true,
|
|
547
|
+
},
|
|
548
|
+
});
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
```bash
|
|
552
|
+
pnpm i -D eslint-plugin-jsx-a11y
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Better Tailwind CSS
|
|
421
556
|
|
|
422
557
|
Uses the enhanced `eslint-plugin-better-tailwindcss` for improved class sorting and validation:
|
|
423
558
|
|
|
@@ -451,6 +586,18 @@ Install peer dependencies:
|
|
|
451
586
|
pnpm i -D eslint-config-expo
|
|
452
587
|
```
|
|
453
588
|
|
|
589
|
+
### Node Security
|
|
590
|
+
|
|
591
|
+
Node rules are enabled by default. The additional `eslint-plugin-security` rules are opt-in:
|
|
592
|
+
|
|
593
|
+
```js
|
|
594
|
+
export default zayne({
|
|
595
|
+
node: {
|
|
596
|
+
security: true,
|
|
597
|
+
},
|
|
598
|
+
});
|
|
599
|
+
```
|
|
600
|
+
|
|
454
601
|
### TanStack
|
|
455
602
|
|
|
456
603
|
Support for TanStack Query and Router:
|
|
@@ -472,15 +619,20 @@ Install peer dependencies:
|
|
|
472
619
|
pnpm i -D @tanstack/eslint-plugin-query @tanstack/eslint-plugin-router
|
|
473
620
|
```
|
|
474
621
|
|
|
475
|
-
### PNPM Catalogs
|
|
622
|
+
### PNPM Workspaces and Catalogs
|
|
476
623
|
|
|
477
|
-
|
|
624
|
+
pnpm support is auto-detected from the nearest `pnpm-workspace.yaml`. It can validate package and workspace manifests, require catalog usage, and sort workspace YAML entries:
|
|
478
625
|
|
|
479
626
|
```js
|
|
480
627
|
import { zayne } from "@zayne-labs/eslint-config";
|
|
481
628
|
|
|
482
629
|
export default zayne({
|
|
483
|
-
pnpm:
|
|
630
|
+
pnpm: {
|
|
631
|
+
catalogs: true,
|
|
632
|
+
json: true,
|
|
633
|
+
sort: true,
|
|
634
|
+
yaml: true,
|
|
635
|
+
},
|
|
484
636
|
});
|
|
485
637
|
```
|
|
486
638
|
|
|
@@ -508,6 +660,19 @@ Install peer dependencies:
|
|
|
508
660
|
pnpm i -D eslint-plugin-depend
|
|
509
661
|
```
|
|
510
662
|
|
|
663
|
+
### Command Comments
|
|
664
|
+
|
|
665
|
+
[`eslint-plugin-command`](https://github.com/antfu/eslint-plugin-command) is always available for explicit, comment-driven transformations. Place a supported triple-slash command directly above the code and run ESLint with fixes:
|
|
666
|
+
|
|
667
|
+
```ts
|
|
668
|
+
/// to-for-of
|
|
669
|
+
items.forEach((item) => {
|
|
670
|
+
console.log(item);
|
|
671
|
+
});
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Commands are intended as temporary codemods; their trigger comments are removed with the transformation.
|
|
675
|
+
|
|
511
676
|
## Type-Aware Rules
|
|
512
677
|
|
|
513
678
|
Type-aware linting is automatically enabled when TypeScript is detected. It uses the nearest `tsconfig.json` by default.
|
|
@@ -541,27 +706,52 @@ export default zayne({
|
|
|
541
706
|
});
|
|
542
707
|
```
|
|
543
708
|
|
|
709
|
+
Set `tsconfigPath: true` to use the nearest project automatically. Type-aware file globs and rules can be refined with `filesTypeAware`, `ignoresTypeAware`, and `overridesTypeAware`.
|
|
710
|
+
|
|
711
|
+
Projects targeting erasable TypeScript syntax can enable the corresponding optional rules:
|
|
712
|
+
|
|
713
|
+
```js
|
|
714
|
+
export default zayne({
|
|
715
|
+
typescript: {
|
|
716
|
+
erasableOnly: true,
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
```
|
|
720
|
+
|
|
544
721
|
### Editor Specific Disables
|
|
545
722
|
|
|
546
723
|
Auto-fixing for the following rules are disabled when ESLint is running in a code editor:
|
|
547
724
|
|
|
548
725
|
- [`prefer-const`](https://eslint.org/docs/rules/prefer-const)
|
|
549
|
-
- [`test/no-only-tests`](https://github.com/levibuzolic/eslint-plugin-no-only-tests)
|
|
550
726
|
- [`pnpm/json-enforce-catalog`](https://github.com/antfu/pnpm-workspace-utils/tree/main/packages/eslint-plugin-pnpm#rules)
|
|
551
727
|
- [`pnpm/json-prefer-workspace-settings`](https://github.com/antfu/pnpm-workspace-utils/tree/main/packages/eslint-plugin-pnpm#rules)
|
|
552
728
|
- [`pnpm/json-valid-catalog`](https://github.com/antfu/pnpm-workspace-utils/tree/main/packages/eslint-plugin-pnpm#rules)
|
|
553
729
|
|
|
554
|
-
This
|
|
730
|
+
This prevents editor autosave from applying potentially disruptive fixes while code is being refactored. Full autofix behavior is restored when ESLint runs in the terminal or through [lint-staged](#lint-staged). If you don't want this behavior, disable editor detection explicitly:
|
|
555
731
|
|
|
556
732
|
```js
|
|
557
733
|
// eslint.config.js
|
|
558
|
-
import { zayne } from "@
|
|
734
|
+
import { zayne } from "@zayne-labs/eslint-config";
|
|
559
735
|
|
|
560
736
|
export default zayne({
|
|
561
737
|
isInEditor: false,
|
|
562
738
|
});
|
|
563
739
|
```
|
|
564
740
|
|
|
741
|
+
### Lint Staged
|
|
742
|
+
|
|
743
|
+
To apply safe autofixes before each commit:
|
|
744
|
+
|
|
745
|
+
```json
|
|
746
|
+
{
|
|
747
|
+
"lint-staged": {
|
|
748
|
+
"*": "eslint --fix"
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
When ESLint runs through lint-staged or a Git hook, terminal rule behavior is preserved instead of the editor-specific non-fixable mode.
|
|
754
|
+
|
|
565
755
|
## Inspecting Config
|
|
566
756
|
|
|
567
757
|
View active rules using the [ESLint Config Inspector](https://github.com/eslint/config-inspector):
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
package/dist/cli/index.js
CHANGED
|
@@ -10,14 +10,14 @@ import fsp from "node:fs/promises";
|
|
|
10
10
|
import parse from "parse-gitignore";
|
|
11
11
|
import { execSync } from "node:child_process";
|
|
12
12
|
//#region package.json
|
|
13
|
-
var version = "0.13.
|
|
13
|
+
var version = "0.13.15";
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/cli/constants.ts
|
|
16
16
|
const vscodeSettingsString = `
|
|
17
17
|
// Auto fix
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
"editor.codeActionsOnSave": {
|
|
19
|
+
"source.fixAll.eslint": "explicit",
|
|
20
|
+
},
|
|
21
21
|
|
|
22
22
|
// Enable eslint for all supported languages
|
|
23
23
|
"eslint.validate": [
|
|
@@ -37,10 +37,10 @@ const vscodeSettingsString = `
|
|
|
37
37
|
"gql",
|
|
38
38
|
"graphql",
|
|
39
39
|
"astro",
|
|
40
|
-
"svelte",
|
|
41
40
|
"css",
|
|
42
41
|
"less",
|
|
43
42
|
"scss",
|
|
43
|
+
"pcss",
|
|
44
44
|
"postcss"
|
|
45
45
|
]
|
|
46
46
|
`;
|
|
@@ -53,10 +53,6 @@ const frameworkOptions = [
|
|
|
53
53
|
label: c.cyan("React"),
|
|
54
54
|
value: "react"
|
|
55
55
|
},
|
|
56
|
-
{
|
|
57
|
-
label: c.red("Svelte"),
|
|
58
|
-
value: "svelte"
|
|
59
|
-
},
|
|
60
56
|
{
|
|
61
57
|
label: c.magenta("Astro"),
|
|
62
58
|
value: "astro"
|
|
@@ -81,7 +77,6 @@ const dependenciesMap = defineEnumDeep({
|
|
|
81
77
|
"eslint-plugin-react-you-might-not-need-an-effect"
|
|
82
78
|
],
|
|
83
79
|
solid: ["eslint-plugin-solid"],
|
|
84
|
-
svelte: ["eslint-plugin-svelte", "svelte-eslint-parser"],
|
|
85
80
|
"tailwindcss-better": ["eslint-plugin-better-tailwindcss"],
|
|
86
81
|
vue: [
|
|
87
82
|
"eslint-plugin-vue",
|
|
@@ -110,6 +105,8 @@ ${mainConfig}
|
|
|
110
105
|
};
|
|
111
106
|
//#endregion
|
|
112
107
|
//#region src/cli/stages/update-eslint-files.ts
|
|
108
|
+
const ESLINT = "eslint";
|
|
109
|
+
const ESLINT_CONFIG = "eslint.config.";
|
|
113
110
|
const updateEslintFiles = async (result) => {
|
|
114
111
|
const cwd = process.cwd();
|
|
115
112
|
const pathESLintIgnore = path.join(cwd, ".eslintignore");
|
|
@@ -120,37 +117,39 @@ const updateEslintFiles = async (result) => {
|
|
|
120
117
|
const eslintIgnores = [];
|
|
121
118
|
if (fs.existsSync(pathESLintIgnore)) {
|
|
122
119
|
p.log.step(c.cyan`Migrating existing .eslintignore`);
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
120
|
+
const content = await fsp.readFile(pathESLintIgnore, "utf8");
|
|
121
|
+
const globs = parse(content).globs();
|
|
122
|
+
for (const glob of globs) if (glob.type === "ignore") eslintIgnores.push(...glob.patterns);
|
|
123
|
+
else if (glob.type === "unignore") eslintIgnores.push(...glob.patterns.map((pattern) => `!${pattern}`));
|
|
128
124
|
}
|
|
129
125
|
const configLines = [];
|
|
130
126
|
if (eslintIgnores.length > 0) configLines.push(`ignores: ${JSON.stringify(eslintIgnores)},`);
|
|
131
|
-
if (result.extra.includes("
|
|
127
|
+
if (result.extra.includes("tailwindcss-better")) configLines.push(`tailwindcssBetter: true,`);
|
|
132
128
|
for (const framework of result.frameworks) configLines.push(`${framework}: true,`);
|
|
133
|
-
const
|
|
129
|
+
const mainConfig = configLines.map((line) => ` ${line}`).join("\n");
|
|
130
|
+
const eslintConfigContent = getEslintConfigContent(mainConfig, []);
|
|
134
131
|
await fsp.writeFile(pathFlatConfig, eslintConfigContent);
|
|
135
132
|
p.log.success(c.green`Created ${configFileName}`);
|
|
133
|
+
const files = fs.readdirSync(cwd);
|
|
134
|
+
const legacyConfig = [];
|
|
135
|
+
for (const file of files) if (file.includes(ESLINT) && !file.includes(ESLINT_CONFIG)) legacyConfig.push(file);
|
|
136
|
+
if (legacyConfig.length > 0) p.note(c.dim(legacyConfig.join(", ")), "You can now remove those files manually");
|
|
136
137
|
};
|
|
137
138
|
//#endregion
|
|
138
139
|
//#region src/cli/constants-generated.ts
|
|
139
140
|
const versionsMap = defineEnum({
|
|
140
|
-
"@eslint-react/eslint-plugin": "^5.
|
|
141
|
-
"astro-eslint-parser": "^1.
|
|
142
|
-
eslint: "^10.
|
|
143
|
-
"eslint-plugin-astro": "^1.
|
|
144
|
-
"eslint-plugin-better-tailwindcss": "^4.
|
|
141
|
+
"@eslint-react/eslint-plugin": "^5.19.0",
|
|
142
|
+
"astro-eslint-parser": "^3.1.0",
|
|
143
|
+
eslint: "^10.10.0",
|
|
144
|
+
"eslint-plugin-astro": "^3.1.0",
|
|
145
|
+
"eslint-plugin-better-tailwindcss": "^4.7.0",
|
|
145
146
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
146
|
-
"eslint-plugin-react-refresh": "^0.5.
|
|
147
|
-
"eslint-plugin-react-you-might-not-need-an-effect": "^0.
|
|
148
|
-
"eslint-plugin-solid": "^0.
|
|
149
|
-
"eslint-plugin-
|
|
150
|
-
"eslint-plugin-vue": "^10.9.1",
|
|
147
|
+
"eslint-plugin-react-refresh": "^0.5.6",
|
|
148
|
+
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.2",
|
|
149
|
+
"eslint-plugin-solid": "^0.17.0",
|
|
150
|
+
"eslint-plugin-vue": "^10.11.0",
|
|
151
151
|
"eslint-processor-vue-blocks": "^2.0.0",
|
|
152
|
-
"
|
|
153
|
-
"vue-eslint-parser": "^10.4.0"
|
|
152
|
+
"vue-eslint-parser": "^10.4.1"
|
|
154
153
|
});
|
|
155
154
|
//#endregion
|
|
156
155
|
//#region src/cli/stages/update-package-json.ts
|
|
@@ -164,23 +163,20 @@ const updatePackageJson = async (result) => {
|
|
|
164
163
|
pkg.devDependencies["@zayne-labs/eslint-config"] = `^${version}`;
|
|
165
164
|
pkg.devDependencies.eslint ??= versionsMap.eslint;
|
|
166
165
|
const addedPackages = [];
|
|
167
|
-
for (const item of result.extra)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
break;
|
|
174
|
-
default:
|
|
166
|
+
for (const item of result.extra) {
|
|
167
|
+
const dependencies = dependenciesMap[item];
|
|
168
|
+
for (const dependency of dependencies) {
|
|
169
|
+
pkg.devDependencies[dependency] = versionsMap[dependency];
|
|
170
|
+
addedPackages.push(dependency);
|
|
171
|
+
}
|
|
175
172
|
}
|
|
176
173
|
for (const framework of result.frameworks) {
|
|
177
174
|
const dependencies = dependenciesMap[framework];
|
|
178
175
|
if (!dependencies) continue;
|
|
179
|
-
|
|
180
|
-
if (!pkg.devDependencies) return;
|
|
176
|
+
for (const dependency of dependencies) {
|
|
181
177
|
pkg.devDependencies[dependency] = versionsMap[dependency];
|
|
182
178
|
addedPackages.push(dependency);
|
|
183
|
-
}
|
|
179
|
+
}
|
|
184
180
|
}
|
|
185
181
|
if (addedPackages.length > 0) p.note(c.dim(addedPackages.join(", ")), "Added packages");
|
|
186
182
|
await fsp.writeFile(pathPackageJSON, JSON.stringify(pkg, null, 2));
|
|
@@ -189,8 +185,8 @@ const updatePackageJson = async (result) => {
|
|
|
189
185
|
//#endregion
|
|
190
186
|
//#region src/cli/stages/update-vscode-settings.ts
|
|
191
187
|
const updateVscodeSettings = async (result) => {
|
|
192
|
-
const cwd = process.cwd();
|
|
193
188
|
if (!result.updateVscodeSettings) return;
|
|
189
|
+
const cwd = process.cwd();
|
|
194
190
|
const dotVscodePath = path.join(cwd, ".vscode");
|
|
195
191
|
const settingsPath = path.join(dotVscodePath, "settings.json");
|
|
196
192
|
if (!fs.existsSync(dotVscodePath)) await fsp.mkdir(dotVscodePath, { recursive: true });
|
|
@@ -208,12 +204,24 @@ const updateVscodeSettings = async (result) => {
|
|
|
208
204
|
};
|
|
209
205
|
//#endregion
|
|
210
206
|
//#region src/cli/run.ts
|
|
207
|
+
const ESLINT_CONFIG_FILES = [
|
|
208
|
+
"eslint.config.js",
|
|
209
|
+
"eslint.config.mjs",
|
|
210
|
+
"eslint.config.cjs",
|
|
211
|
+
"eslint.config.ts",
|
|
212
|
+
"eslint.config.mts",
|
|
213
|
+
"eslint.config.cts"
|
|
214
|
+
];
|
|
211
215
|
const runCli = async (options = {}) => {
|
|
212
|
-
const
|
|
213
|
-
const argTemplate = options.frameworks?.map((
|
|
214
|
-
const argExtra = options.extra?.map((
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
const isSkippingPrompts = Boolean(process.env.SKIP_PROMPT) || Boolean(options.yes);
|
|
217
|
+
const argTemplate = options.frameworks?.filter((framework) => typeof framework === "string").map((framework) => framework.trim()).filter(Boolean);
|
|
218
|
+
const argExtra = options.extra?.filter((extraOption) => typeof extraOption === "string").map((extraOption) => extraOption.trim()).filter(Boolean);
|
|
219
|
+
const invalidFrameworks = argTemplate?.filter((framework) => !frameworks.includes(framework));
|
|
220
|
+
const invalidExtras = argExtra?.filter((extraOption) => !extra.includes(extraOption));
|
|
221
|
+
if (isSkippingPrompts && ((invalidFrameworks?.length ?? 0) > 0 || (invalidExtras?.length ?? 0) > 0)) throw new Error(`Invalid CLI options.${invalidFrameworks?.length ? ` Frameworks: ${invalidFrameworks.join(", ")}.` : ""}${invalidExtras?.length ? ` Extras: ${invalidExtras.join(", ")}.` : ""}`);
|
|
222
|
+
const existingConfigFile = ESLINT_CONFIG_FILES.find((fileName) => fs.existsSync(path.join(process.cwd(), fileName)));
|
|
223
|
+
if (existingConfigFile) {
|
|
224
|
+
p.log.warn(c.yellow`${existingConfigFile} already exists, migration wizard exited.`);
|
|
217
225
|
return process.exit(1);
|
|
218
226
|
}
|
|
219
227
|
let result = {
|
|
@@ -222,7 +230,7 @@ const runCli = async (options = {}) => {
|
|
|
222
230
|
uncommittedConfirmed: false,
|
|
223
231
|
updateVscodeSettings: true
|
|
224
232
|
};
|
|
225
|
-
if (!
|
|
233
|
+
if (!isSkippingPrompts) {
|
|
226
234
|
result = await p.group({
|
|
227
235
|
uncommittedConfirmed: () => {
|
|
228
236
|
if (isGitClean()) return Promise.resolve(true);
|
|
@@ -232,8 +240,7 @@ const runCli = async (options = {}) => {
|
|
|
232
240
|
});
|
|
233
241
|
},
|
|
234
242
|
frameworks: ({ results }) => {
|
|
235
|
-
|
|
236
|
-
if (!results.uncommittedConfirmed || isArgTemplateValid) return;
|
|
243
|
+
if ((argTemplate?.length ?? 0) > 0 && (argTemplate ?? []).filter((element) => !frameworks.includes(element)).length === 0 || !results.uncommittedConfirmed) return;
|
|
237
244
|
const message = argTemplate ? `"${JSON.stringify(argTemplate)}" isn't a valid template. Please choose from below: ` : "Select a framework:";
|
|
238
245
|
return p.multiselect({
|
|
239
246
|
message: c.reset(message),
|
|
@@ -242,8 +249,7 @@ const runCli = async (options = {}) => {
|
|
|
242
249
|
});
|
|
243
250
|
},
|
|
244
251
|
extra: ({ results }) => {
|
|
245
|
-
|
|
246
|
-
if (!results.uncommittedConfirmed || isArgExtraValid) return;
|
|
252
|
+
if ((argExtra?.length ?? 0) > 0 && (argExtra ?? []).filter((element) => !extra.includes(element)).length === 0 || !results.uncommittedConfirmed) return;
|
|
247
253
|
const message = argExtra ? `"${JSON.stringify(argExtra)}" isn't a valid extra util. Please choose from below: ` : "Select an extra util:";
|
|
248
254
|
return p.multiselect({
|
|
249
255
|
message: c.reset(message),
|
|
@@ -276,7 +282,7 @@ const header = () => {
|
|
|
276
282
|
p.intro(`${c.green`@zayne-labs/eslint-config `}${c.dim`v${version}`}`);
|
|
277
283
|
};
|
|
278
284
|
const cli = cac("@zayne-labs/eslint-config");
|
|
279
|
-
cli.command("", "Run the initialization or migration").option("--yes, -y", "Skip prompts and use default values", { default: false }).option("--template, -t <template>", "Use the framework template for optimal customization: vue / react /
|
|
285
|
+
cli.command("", "Run the initialization or migration").option("--yes, -y", "Skip prompts and use default values", { default: false }).option("--template, -t <template>", "Use the framework template for optimal customization: vue / react / solid / astro", { type: [] }).option("--extra, -e <extra>", "Use the extra utils: tailwindcss-better", { type: [] }).action(async (options) => {
|
|
280
286
|
header();
|
|
281
287
|
try {
|
|
282
288
|
await runCli(options);
|