@fabdeh/eslint-config 0.2.3 → 0.4.0

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 CHANGED
@@ -9,14 +9,14 @@
9
9
  - Designed to work with TypeScript, JSX, etc. Out-of-box.
10
10
  - Opinionated, but [very customizable](#customization)
11
11
  - [ESLint Flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new), compose easily!
12
- - Automatic [Angular](#angular), [NGRX](#ngrx), [TailwindCSS](#tailwindcc), [Vitest](#vitest) support when the corresponding dependency is detected.
13
- <!--- - Optional [formatters](#formatters) support for formatting CSS, HTML, XML, etc. --->
12
+ - Automatic [Angular](#angular), [NGRX](#ngrx), [TypeScript](#typescript), [Vitest](#vitest) support when the corresponding dependency is detected.
13
+ - Optional [formatters](#formatters) support for formatting CSS, HTML, XML, etc.
14
14
  - **Style principle**: Minimal for reading, stable for diff, consistent
15
15
  - Sorted imports, dangling commas
16
16
  - Single quotes, no semi
17
17
  - Using [ESLint Stylistic](https://github.com/eslint-stylistic/eslint-stylistic)
18
18
  - Respects `.gitignore` by default
19
- - Requires ESLint v9.5.0+
19
+ - Requires ESLint v9.21.0+
20
20
 
21
21
  > [!WARNING]
22
22
  > Please keep in mind that this is **_a personal config_** with a lot opinions. Changes might not always be pleased by everyone and every use cases.
@@ -49,8 +49,8 @@ For example:
49
49
  ```json
50
50
  {
51
51
  "scripts": {
52
- "lint": "eslint .",
53
- "lint:fix": "eslint . --fix"
52
+ "lint": "eslint . --fix",
53
+ "lint:ci": "eslint ."
54
54
  }
55
55
  }
56
56
  ```
@@ -78,11 +78,27 @@ Add the following settings to your `.vscode/settings.json`:
78
78
  "source.organizeImports": "never"
79
79
  },
80
80
 
81
- // Silent the stylistic rules in you IDE, but still auto fix them
81
+ // Silence the style rules in you IDE, but still fix them automatically
82
82
  "eslint.rules.customizations": [{ "rule": "@stylistic/*", "severity": "off", "fixable": true }],
83
83
 
84
84
  // Enable eslint for all supported languages
85
- "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "html"]
85
+ "eslint.validate": [
86
+ "css",
87
+ "html",
88
+ "javascript",
89
+ "javascriptreact",
90
+ "json",
91
+ "jsonc",
92
+ "json5",
93
+ "less",
94
+ "markdown",
95
+ "scss",
96
+ "typescript",
97
+ "typescriptreact",
98
+ "toml",
99
+ "yaml",
100
+ "xml"
101
+ ]
86
102
  }
87
103
  ```
88
104
 
@@ -202,6 +218,242 @@ Check out the [configs](https://github.com/FabienDehopre/eslint-config/blob/main
202
218
 
203
219
  > Thanks to [antfu/eslint-config](https://github.com/antfu/eslint-config) for the inspiration and reference.
204
220
 
221
+ ### Rules Overrides
222
+
223
+ All the rules are always bound to one or more file extensions (via minimatch pattern. i.e.: \*_/_.?([cm])[jt]s?(x) for all JS and TS file types including JSX syntax).
224
+ If you want to override the rules, you need to specify the file extension:
225
+
226
+ ```js
227
+ // eslint.config.js
228
+ import { createConfig } from '@fabdeh/eslint-config';
229
+
230
+ export default createConfig(
231
+ {
232
+ typescript: true,
233
+ vitest: true
234
+ },
235
+ {
236
+ // Remember to specify the file glob here, otherwise it might cause the vitest plugin to handle non-spec files
237
+ files: ['**/*.spec.?([cm])[jt]s', '**/*.test.?([cm])[jt]s'],
238
+ rules: {
239
+ 'vitest/consistent-test-it': ['error', { fn: 'it' }],
240
+ }
241
+ },
242
+ {
243
+ // Without `files`, they are general rules for all files
244
+ rules: {
245
+ '@stylistic/semi': ['error', 'never']
246
+ }
247
+ }
248
+ );
249
+ ```
250
+
251
+ We also provide the `overrides` option in each integration to make it easier:
252
+
253
+ ```js
254
+ // eslint.config.js
255
+ import { createConfig } from '@fabdeh/eslint-config';
256
+
257
+ export default createConfig({
258
+ typescript: {
259
+ overrides: {
260
+ '@typescript-eslint/consisten-type-definitions': ['error', 'interface'],
261
+ },
262
+ },
263
+ angular: {
264
+ tsOverrides: {
265
+ '@angular-eslint/prefer-signals': 'off',
266
+ },
267
+ htmlOverrides: {
268
+ '@angular-eslint/template/no-any': 'warn',
269
+ },
270
+ },
271
+ yaml: {
272
+ overrides: {
273
+ // ...
274
+ }
275
+ }
276
+ });
277
+ ```
278
+
279
+ ### Auto-detected integrations
280
+
281
+ The following integrations are automatically enabled if the corresponding package is installed in your project:
282
+
283
+ - [TypeScript](#typescript)
284
+ - [Angular](#angular)
285
+ - [NgRx](#ngrx)
286
+ - [Vitest](#vitest)
287
+
288
+ #### TypeScript
289
+
290
+ Most of TypeScript rules are enable automatically if `typescript` package is installed in you project. Some `@typescript-eslint` rules are also enabled by default for JavaScript files.
291
+ You can explicitly enable/disable TypeScript integration manually:
292
+
293
+ ```js
294
+ // eslint.config.js
295
+ import { createConfig } from '@fabdeh/eslint-config';
296
+
297
+ export default createConfig({
298
+ typescript: true,
299
+ });
300
+ ```
301
+
302
+ ##### Erasable Syntax Only
303
+
304
+ The TypeScript integration also allow you to turn on/off rules that will report on using syntax that will not be allowed by TypeScript's [--erasableSyntaxOnly option](https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-beta/#the---erasablesyntaxonly-option):
305
+
306
+ > Recently, Node.js 23.6 unflagged [experimental support for running TypeScript files directly](https://nodejs.org/api/typescript.html#type-stripping); however, only certain constructs are supported under this mode.
307
+ >
308
+ > ...
309
+ >
310
+ > TypeScript 5.8 introduces the `--erasableSyntaxOnly` flag. When this flag is enabled, TypeScript will only allow you to use constructs that can be erased from a file, and will issue an error if it encounters any constructs that cannot be erased.
311
+
312
+ You can enable these rules as follow:
313
+
314
+ ```js
315
+ // eslint.config.js
316
+ import { createConfig } from '@fabdeh/eslint-config';
317
+
318
+ export default createConfig({
319
+ typescript: {
320
+ enableErasableSyntaxOnly: true,
321
+ },
322
+ });
323
+ ```
324
+
325
+ These rules are disabled by default and therefore the associated ESLint plugin is also not installed by default.
326
+ Running `pnpx eslint` should prompt you to install the required plugin; otherwise, you can install it manually:
327
+
328
+ ```bash
329
+ pnpm add -D eslint-plugin-erasable-syntax-only
330
+ ```
331
+
332
+ #### Angular
333
+
334
+ Angular support is detected automatically by checking if `@angular/core` is installed in your project. You can also explicitly enable/disable it:
335
+
336
+ ```js
337
+ // eslint.config.js
338
+ import { createConfig } from '@fabdeh/eslint-config';
339
+
340
+ export default createConfig({
341
+ angular: true,
342
+ });
343
+ ```
344
+
345
+ #### NgRx
346
+
347
+ NgRx support is also detected automatically if any of the following package is installed in your project.
348
+
349
+ - `@ngrx/store`
350
+ - `@ngrx/effects`
351
+ - `@ngrx/signals`
352
+ - `@ngrx/operators`
353
+
354
+ As the Angular integration is can be explicitly enabled/disabled:
355
+
356
+ ```js
357
+ // eslint.config.js
358
+ import { createConfig } from '@fabdeh/eslint-config';
359
+
360
+ export default createConfig({
361
+ ngrx: true,
362
+ });
363
+ ```
364
+
365
+ > Of course, NgRx depends on Angular so the Angular integration will be enabled as well.
366
+
367
+ #### Vitest
368
+
369
+ The vitest integration is detected automatically by checking if `vitest` is installed in your project. It can be enable/disable manually in the configuration:
370
+
371
+ ```js
372
+ // eslint.config.js
373
+ import { createConfig } from '@fabdeh/eslint-config';
374
+
375
+ export default createConfig({
376
+ vitest: true,
377
+ });
378
+ ```
379
+
380
+ ### Optional integrations
381
+
382
+ We provide some optional integrations for specific use cases, that we don't include their dependencies by default.
383
+
384
+ #### Formatters
385
+
386
+ Use external formatters to format files that ESLint cannot handle yet (`.css`, `.html`, etc). Powered by [`eslint-plugin-format`](https://github.com/antfu/eslint-plugin-format).
387
+
388
+ ```js
389
+ // eslint.config.js
390
+ import { createConfig } from '@fabdeh/eslint-config';
391
+
392
+ export default createConfig({
393
+ formatters: {
394
+ /**
395
+ * Format CSS, LESS, SCSS files
396
+ */
397
+ css: true,
398
+ /**
399
+ * Format HTML files
400
+ */
401
+ html: true,
402
+ /**
403
+ * Format Markdown files
404
+ */
405
+ markdown: true,
406
+ }
407
+ });
408
+ ```
409
+
410
+ Running `npx eslint` should prompt you to install the required dependencies; otherwise, you can install them manually:
411
+
412
+ ```bash
413
+ pnpm add -D eslint-plugin-format
414
+ ```
415
+
416
+ ### Lint Staged
417
+
418
+ If you want to apply lint and auto-fix before every commit, you can add the following to your `package.json`:
419
+
420
+ ```json
421
+ {
422
+ "simple-git-hooks": {
423
+ "pre-commit": "pnpm nano-staged"
424
+ },
425
+ "nano-staged": {
426
+ "*": "eslint --fix"
427
+ }
428
+ }
429
+ ```
430
+
431
+ and then
432
+
433
+ ```bash
434
+ pnpm add -D nano-staged simple-git-hooks
435
+
436
+ # then, to activate the hooks
437
+ pnpm simple-git-hooks
438
+ ```
439
+
440
+ ## Versioning Policy
441
+
442
+ This project follows [Semantic Versioning](https://semver.org/) for releases. However, since this is just a config and involves opinions and many moving parts, we don't treat rules changes as breaking changes.
443
+
444
+ ### Changes Considered as Breaking Changes
445
+
446
+ - Node.js version requirement changes
447
+ - Huge refactors that might break the config
448
+ - Plugins made major changes that might break the config
449
+ - Changes that might affect most of the codebases
450
+
451
+ ### Changes Considered as Non-breaking Changes
452
+
453
+ - Enable/disable rules and plugins (that might become stricter)
454
+ - Rules options changes
455
+ - Version bumps of dependencies
456
+
205
457
  ## License
206
458
 
207
459
  [MIT](./LICENSE) License &copy; 2025-PRESENT [Fabien Dehopré](https://github.com/FabienDehopre)
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { ConfigArray, ConfigWithExtends } from 'typescript-eslint';
2
- import { StylisticCustomizeOptions } from '@stylistic/eslint-plugin';
3
- import { TSESLint } from '@typescript-eslint/utils';
4
- import { FlatGitignoreOptions } from 'eslint-config-flat-gitignore';
1
+ import type { ConfigArray, ConfigWithExtends } from 'typescript-eslint';
2
+ import type { StylisticCustomizeOptions } from '@stylistic/eslint-plugin';
3
+ import type { TSESLint } from '@typescript-eslint/utils';
4
+ import type { FlatGitignoreOptions } from 'eslint-config-flat-gitignore';
5
5
 
6
6
  /**
7
7
  * Vendor types from Prettier so we don't rely on the dependency.
@@ -136,6 +136,11 @@ interface VendoredPrettierOptionsRequired {
136
136
  xmlWhitespaceSensitivity: 'ignore' | 'preserve' | 'strict';
137
137
  }
138
138
 
139
+
140
+
141
+
142
+
143
+
139
144
  /**
140
145
  * A type that can be awaited. Promise<T> or T.
141
146
  */
@@ -170,9 +175,9 @@ interface UnicornOptions {
170
175
  allRecommended?: boolean;
171
176
  }
172
177
  /**
173
- * An alias for the `StylisticCustomizeOptions` type without the `flat`, `name`, and `pluginName` properties.
178
+ * An alias for the `StylisticCustomizeOptions` type without the `pluginName` property.
174
179
  */
175
- type StylisticConfig = Omit<StylisticCustomizeOptions, 'flat' | 'name' | 'pluginName'>;
180
+ type StylisticConfig = Omit<StylisticCustomizeOptions, 'pluginName'>;
176
181
  /**
177
182
  * Interface representing the stylistic options.
178
183
  */
@@ -191,6 +196,14 @@ interface TypeScriptParserOptions {
191
196
  */
192
197
  parserOptions?: TSESLint.FlatConfig.ParserOptions;
193
198
  }
199
+ interface TypeScriptErasableSyntaxOnlyOptions {
200
+ /**
201
+ * Indicates whether the erasable syntax only rules should be enabled or not.
202
+ *
203
+ * @default false
204
+ */
205
+ enableErasableSyntaxOnly?: boolean;
206
+ }
194
207
  /**
195
208
  * Options for configuring Angular-specific linting rules.
196
209
  */
@@ -289,6 +302,13 @@ interface RegExpOptions {
289
302
  */
290
303
  level?: 'error' | 'warn';
291
304
  }
305
+ interface TailwindcssParserPerGlobOptions {
306
+ /**
307
+ * Provides a specific ESLint parser per glob pattern.
308
+ * This is only needed if you want to lint tailwindcss without using Angular and TypeScript.
309
+ */
310
+ parsers?: Record<string, TSESLint.FlatConfig.Parser>;
311
+ }
292
312
  /**
293
313
  * Options for creating an ESLint configuration.
294
314
  *
@@ -313,7 +333,7 @@ interface CreateConfigOptions {
313
333
  *
314
334
  * @default auto-detected
315
335
  */
316
- typescript?: boolean | (OverridesOptions & TypeScriptParserOptions);
336
+ typescript?: boolean | (OverridesOptions & TypeScriptErasableSyntaxOnlyOptions & TypeScriptParserOptions);
317
337
  /**
318
338
  * Enable stylistic rules.
319
339
  *
@@ -321,6 +341,12 @@ interface CreateConfigOptions {
321
341
  * @default true
322
342
  */
323
343
  stylistic?: boolean | (OverridesOptions & StylisticConfig);
344
+ /**
345
+ * Enable or disable JSDoc rules.
346
+ *
347
+ * @default true
348
+ */
349
+ jsdoc?: boolean;
324
350
  /**
325
351
  * Enable regexp rules.
326
352
  *
@@ -355,9 +381,9 @@ interface CreateConfigOptions {
355
381
  /**
356
382
  * Options for the TailwindCSS linting rules.
357
383
  *
358
- * @default auto-detect based on dependencies.
384
+ * @default false
359
385
  */
360
- tailwindcss?: OverridesOptions | boolean;
386
+ tailwindcss?: boolean | (FilesOptions & OverridesOptions) | (OverridesOptions & TailwindcssParserPerGlobOptions);
361
387
  /**
362
388
  * Enable JSONC support.
363
389
  *
@@ -397,6 +423,9 @@ interface CreateConfigOptions {
397
423
  formatters?: FormattersOptions | boolean;
398
424
  }
399
425
 
426
+
427
+
428
+
400
429
  /**
401
430
  * Generates an ESLint configuration for Angular projects.
402
431
  *
@@ -409,6 +438,8 @@ interface CreateConfigOptions {
409
438
  */
410
439
  declare function angular(options?: AngularOptions): Promise<ConfigArray>;
411
440
 
441
+
442
+
412
443
  /**
413
444
  * Generates a configuration array for ESLint comments rules.
414
445
  *
@@ -420,6 +451,8 @@ declare function angular(options?: AngularOptions): Promise<ConfigArray>;
420
451
  */
421
452
  declare function comments(): ConfigArray;
422
453
 
454
+
455
+
423
456
  /**
424
457
  * Generates a configuration array for ESLint with default and user-defined ignore patterns.
425
458
  *
@@ -428,6 +461,9 @@ declare function comments(): ConfigArray;
428
461
  */
429
462
  declare function ignores(userIgnores?: string[]): ConfigArray;
430
463
 
464
+
465
+
466
+
431
467
  /**
432
468
  * Generates an ESLint configuration array for import rules.
433
469
  *
@@ -437,6 +473,9 @@ declare function ignores(userIgnores?: string[]): ConfigArray;
437
473
  */
438
474
  declare function imports(options?: StylisticOptions): ConfigArray;
439
475
 
476
+
477
+
478
+
440
479
  /**
441
480
  * Generates a configuration array for JavaScript projects with ESLint.
442
481
  *
@@ -455,6 +494,9 @@ declare function imports(options?: StylisticOptions): ConfigArray;
455
494
  */
456
495
  declare function javascript(options?: OverridesOptions): ConfigArray;
457
496
 
497
+
498
+
499
+
458
500
  /**
459
501
  * Generates a configuration array for JSDoc rules.
460
502
  *
@@ -464,6 +506,13 @@ declare function javascript(options?: OverridesOptions): ConfigArray;
464
506
  */
465
507
  declare function jsdoc(options?: StylisticOptions): ConfigArray;
466
508
 
509
+
510
+
511
+
512
+
513
+
514
+
515
+
467
516
  /**
468
517
  * Generates an ESLint configuration for JSONC files.
469
518
  *
@@ -484,6 +533,11 @@ declare function jsdoc(options?: StylisticOptions): ConfigArray;
484
533
  */
485
534
  declare function jsonc(options?: FilesOptions & OverridesOptions & StylisticOptions): Promise<ConfigArray>;
486
535
 
536
+
537
+
538
+
539
+
540
+
487
541
  /**
488
542
  * Configures ESLint for Markdown files.
489
543
  *
@@ -506,6 +560,9 @@ declare function jsonc(options?: FilesOptions & OverridesOptions & StylisticOpti
506
560
  */
507
561
  declare function markdown(options?: FilesOptions & OverridesOptions): Promise<ConfigArray>;
508
562
 
563
+
564
+
565
+
509
566
  /**
510
567
  * Generates an ESLint configuration array for NgRx based on the provided options.
511
568
  *
@@ -529,6 +586,8 @@ declare function markdown(options?: FilesOptions & OverridesOptions): Promise<Co
529
586
  */
530
587
  declare function ngrx(options?: NgrxOptions): Promise<ConfigArray>;
531
588
 
589
+
590
+
532
591
  /**
533
592
  * Generates a configuration array for the "perfectionist" ESLint plugin.
534
593
  *
@@ -542,12 +601,21 @@ declare function ngrx(options?: NgrxOptions): Promise<ConfigArray>;
542
601
  */
543
602
  declare function perfectionist(): Promise<ConfigArray>;
544
603
 
604
+
605
+
606
+
607
+
608
+
545
609
  /**
610
+ * Configure the recommended regexp rules.
546
611
  *
547
- * @param options
612
+ * @param options - The options
613
+ * @returns The ESLint configuration for regexp linting
548
614
  */
549
615
  declare function regexp(options?: OverridesOptions & RegExpOptions): ConfigArray;
550
616
 
617
+
618
+
551
619
  /**
552
620
  * Configures ESLint rules for sorting keys and array values in `package.json` files.
553
621
  *
@@ -573,6 +641,11 @@ declare function sortPackageJson(): ConfigArray;
573
641
  */
574
642
  declare function sortTsConfig(): ConfigArray;
575
643
 
644
+
645
+
646
+
647
+
648
+
576
649
  declare const STYLISTIC_CONFIG_DEFAULT: StylisticConfig;
577
650
  /**
578
651
  * Generates a stylistic ESLint configuration.
@@ -584,6 +657,13 @@ declare const STYLISTIC_CONFIG_DEFAULT: StylisticConfig;
584
657
  */
585
658
  declare function stylistic(options?: StylisticOptions): Promise<ConfigArray>;
586
659
 
660
+
661
+
662
+
663
+
664
+
665
+
666
+
587
667
  /**
588
668
  * Generates an ESLint configuration array for Tailwind CSS.
589
669
  *
@@ -596,7 +676,14 @@ declare function stylistic(options?: StylisticOptions): Promise<ConfigArray>;
596
676
  * },
597
677
  * });
598
678
  */
599
- declare function tailwindcss(options?: OverridesOptions): Promise<ConfigArray>;
679
+ declare function tailwindcss(options?: (FilesOptions & OverridesOptions) | (OverridesOptions & TailwindcssParserPerGlobOptions)): Promise<ConfigArray>;
680
+
681
+
682
+
683
+
684
+
685
+
686
+
600
687
 
601
688
  /**
602
689
  * Generates an ESLint configuration for TOML files.
@@ -610,6 +697,15 @@ declare function tailwindcss(options?: OverridesOptions): Promise<ConfigArray>;
610
697
  */
611
698
  declare function toml(options?: FilesOptions & OverridesOptions & StylisticOptions): Promise<ConfigArray>;
612
699
 
700
+
701
+
702
+
703
+
704
+
705
+
706
+
707
+
708
+
613
709
  /**
614
710
  * Generates a TypeScript ESLint configuration.
615
711
  *
@@ -619,7 +715,10 @@ declare function toml(options?: FilesOptions & OverridesOptions & StylisticOptio
619
715
  * @param options.overrides - Additional rule overrides.
620
716
  * @returns A ConfigArray containing the TypeScript ESLint configuration.
621
717
  */
622
- declare function typescript(options?: OverridesOptions & StylisticOptions & TypeScriptParserOptions): ConfigArray;
718
+ declare function typescript(options?: OverridesOptions & StylisticOptions & TypeScriptErasableSyntaxOnlyOptions & TypeScriptParserOptions): Promise<ConfigArray>;
719
+
720
+
721
+
623
722
 
624
723
  /**
625
724
  * Generates a configuration array for the Unicorn plugin with the specified options.
@@ -629,6 +728,11 @@ declare function typescript(options?: OverridesOptions & StylisticOptions & Type
629
728
  */
630
729
  declare function unicorn(options?: UnicornOptions): ConfigArray;
631
730
 
731
+
732
+
733
+
734
+
735
+
632
736
  /**
633
737
  * Configures and returns an ESLint configuration array for Vitest.
634
738
  *
@@ -648,6 +752,13 @@ declare function unicorn(options?: UnicornOptions): ConfigArray;
648
752
  */
649
753
  declare function vitest(options?: OverridesOptions & TestingOptions): Promise<ConfigArray>;
650
754
 
755
+
756
+
757
+
758
+
759
+
760
+
761
+
651
762
  /**
652
763
  * Generates an ESLint configuration for YAML files.
653
764
  *
@@ -661,6 +772,13 @@ declare function vitest(options?: OverridesOptions & TestingOptions): Promise<Co
661
772
  */
662
773
  declare function yaml(options?: FilesOptions & OverridesOptions & StylisticOptions): Promise<ConfigArray>;
663
774
 
775
+
776
+
777
+
778
+
779
+
780
+
781
+
664
782
  /**
665
783
  * Creates an ESLint configuration array based on the provided options and user configurations.
666
784
  *
@@ -672,7 +790,7 @@ declare function yaml(options?: FilesOptions & OverridesOptions & StylisticOptio
672
790
  * const config = await createConfig({ vitest: true, typescript: { parserOptions: { project: './tsconfig.json' } } });
673
791
  * ```
674
792
  */
675
- declare function createConfig(options?: ConfigWithExtends & CreateConfigOptions, ...userConfigs: Awaitable<ConfigWithExtends | ConfigWithExtends[]>[]): Promise<ConfigArray>;
793
+ declare function defineConfig(options?: ConfigWithExtends & CreateConfigOptions, ...userConfigs: Awaitable<ConfigWithExtends | ConfigWithExtends[]>[]): Promise<ConfigArray>;
676
794
 
677
795
  /**
678
796
  * A glob pattern that matches JavaScript and TypeScript source files (including JSX/TSX).
@@ -695,6 +813,10 @@ declare const GLOB_HTML = "**/*.htm?(l)";
695
813
  */
696
814
  declare const GLOB_TESTS: string[];
697
815
 
816
+
817
+
818
+
819
+
698
820
  /**
699
821
  * A utility function to handle the default export of a module.
700
822
  *
@@ -758,4 +880,5 @@ type ResolvedOptions<T> = T extends boolean ? never : NonNullable<T>;
758
880
  */
759
881
  declare function resolveSubOptions<K extends keyof CreateConfigOptions>(options: CreateConfigOptions, key: K): ResolvedOptions<CreateConfigOptions[K]>;
760
882
 
761
- export { type AngularOptions, type Awaitable, type CreateConfigOptions, type FilesOptions, type FormattersOptions, GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, type NgrxOperators, type NgrxOptions, type OverridesOptions, type RegExpOptions, type ResolvedOptions, STYLISTIC_CONFIG_DEFAULT, type StylisticConfig, type StylisticOptions, type TestingOptions, type TypeScriptParserOptions, type UnicornOptions, angular, comments, createConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, regexp, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
883
+ export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, defineConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, regexp, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
884
+ export type { AngularOptions, Awaitable, CreateConfigOptions, FilesOptions, FormattersOptions, NgrxOperators, NgrxOptions, OverridesOptions, RegExpOptions, ResolvedOptions, StylisticConfig, StylisticOptions, TailwindcssParserPerGlobOptions, TestingOptions, TypeScriptErasableSyntaxOnlyOptions, TypeScriptParserOptions, UnicornOptions };
package/dist/index.mjs CHANGED
@@ -10,9 +10,9 @@ import preferArrowFunctions from 'eslint-plugin-prefer-arrow-functions';
10
10
  import unusedImports from 'eslint-plugin-unused-imports';
11
11
  import globals from 'globals';
12
12
  import eslintComments from '@eslint-community/eslint-plugin-eslint-comments';
13
- import jsdocPlugin from 'eslint-plugin-jsdoc';
14
13
  import * as importX from 'eslint-plugin-import-x';
15
14
  import perfectionistPlugin from 'eslint-plugin-perfectionist';
15
+ import jsdocPlugin from 'eslint-plugin-jsdoc';
16
16
  import unicornPlugin from 'eslint-plugin-unicorn';
17
17
  import { configs } from 'eslint-plugin-regexp';
18
18
  import { mergeProcessors, processorPassThrough } from 'eslint-merge-processors';
@@ -38,7 +38,7 @@ const GLOB_XML = "**/*.xml";
38
38
  const GLOB_SVG = "**/*.svg";
39
39
  const GLOB_GRAPHQL = "**/*.{g,graph}ql";
40
40
  const GLOB_HTML = "**/*.htm?(l)";
41
- const GLOB_TESTS = [`**/*.spec.${GLOB_SRC_EXT}`, `**/*.test.${GLOB_SRC_EXT}`, `**/test-setup.${GLOB_SRC_EXT}`];
41
+ const GLOB_TESTS = [`**/*.spec.?([cm])[jt]s`, `**/*.test.?([cm])[jt]s`, `**/test-setup.?([cm])[jt]s`];
42
42
  const GLOB_EXCLUDE = [
43
43
  "**/node_modules",
44
44
  "**/dist",
@@ -470,6 +470,54 @@ function javascript(options = {}) {
470
470
  );
471
471
  }
472
472
 
473
+ function getJsDocRules(level, stylistic, mode) {
474
+ return {
475
+ ...mode === "both" || mode === "jsOnly" ? {
476
+ "jsdoc/check-access": level,
477
+ "jsdoc/check-param-names": level,
478
+ "jsdoc/check-property-names": level,
479
+ "jsdoc/check-tag-names": level,
480
+ "jsdoc/check-types": level,
481
+ "jsdoc/check-values": level,
482
+ "jsdoc/empty-tags": level,
483
+ "jsdoc/implements-on-classes": level,
484
+ "jsdoc/no-defaults": level,
485
+ "jsdoc/no-undefined-types": level,
486
+ "jsdoc/require-jsdoc": level,
487
+ "jsdoc/require-param": level,
488
+ "jsdoc/require-param-description": level,
489
+ "jsdoc/require-param-name": level,
490
+ "jsdoc/require-param-type": level,
491
+ "jsdoc/require-property": level,
492
+ "jsdoc/require-property-description": level,
493
+ "jsdoc/require-property-name": level,
494
+ "jsdoc/require-property-type": level,
495
+ "jsdoc/require-returns": level,
496
+ "jsdoc/require-returns-check": level,
497
+ "jsdoc/require-returns-description": level,
498
+ "jsdoc/require-returns-type": level,
499
+ "jsdoc/require-yields": level,
500
+ "jsdoc/require-yields-check": level,
501
+ "jsdoc/valid-types": level,
502
+ ...stylistic ? {
503
+ "jsdoc/check-alignment": level,
504
+ "jsdoc/multiline-blocks": level,
505
+ "jsdoc/no-multi-asterisks": level,
506
+ "jsdoc/require-asterisk-prefix": level,
507
+ "jsdoc/require-hyphen-before-param-description": level,
508
+ "jsdoc/tag-lines": [level, "never", { startLines: 1 }]
509
+ } : {}
510
+ } : {},
511
+ ...mode === "both" || mode === "tsOnly" ? {
512
+ "jsdoc/check-tag-names": [level, { typed: true }],
513
+ "jsdoc/no-types": level,
514
+ "jsdoc/no-undefined-types": "off",
515
+ "jsdoc/require-param-type": "off",
516
+ "jsdoc/require-property-type": "off",
517
+ "jsdoc/require-returns-type": "off"
518
+ } : {}
519
+ };
520
+ }
473
521
  function jsdoc(options = {}) {
474
522
  const { stylistic = true } = options;
475
523
  return tseslint.config(
@@ -477,52 +525,12 @@ function jsdoc(options = {}) {
477
525
  name: "fabdeh/jsdoc/rules",
478
526
  files: [GLOB_SRC],
479
527
  plugins: { jsdoc: jsdocPlugin },
480
- rules: {
481
- "jsdoc/check-access": "warn",
482
- "jsdoc/check-param-names": "warn",
483
- "jsdoc/check-property-names": "warn",
484
- "jsdoc/check-tag-names": "warn",
485
- "jsdoc/check-types": "warn",
486
- "jsdoc/check-values": "warn",
487
- "jsdoc/empty-tags": "warn",
488
- "jsdoc/implements-on-classes": "warn",
489
- "jsdoc/no-defaults": "warn",
490
- "jsdoc/no-multi-asterisks": "warn",
491
- "jsdoc/no-undefined-types": "warn",
492
- "jsdoc/require-jsdoc": "warn",
493
- "jsdoc/require-param": "warn",
494
- "jsdoc/require-param-description": "warn",
495
- "jsdoc/require-param-name": "warn",
496
- "jsdoc/require-param-type": "warn",
497
- "jsdoc/require-property": "warn",
498
- "jsdoc/require-property-description": "warn",
499
- "jsdoc/require-property-name": "warn",
500
- "jsdoc/require-property-type": "warn",
501
- "jsdoc/require-returns": "warn",
502
- "jsdoc/require-returns-check": "warn",
503
- "jsdoc/require-returns-description": "warn",
504
- "jsdoc/require-returns-type": "warn",
505
- "jsdoc/require-yields": "warn",
506
- "jsdoc/require-yields-check": "warn",
507
- "jsdoc/tag-lines": ["warn", "never", { startLines: 1 }],
508
- "jsdoc/valid-types": "warn",
509
- ...stylistic ? {
510
- "jsdoc/check-alignment": "warn",
511
- "jsdoc/multiline-blocks": "warn"
512
- } : {}
513
- }
528
+ rules: getJsDocRules("warn", !!stylistic, "jsOnly")
514
529
  },
515
530
  {
516
531
  name: "fabdeh/jsdoc/ts-only/rules",
517
532
  files: [GLOB_TS],
518
- rules: {
519
- "jsdoc/check-tag-names": ["warn", { typed: true }],
520
- "jsdoc/no-types": "warn",
521
- "jsdoc/no-undefined-types": "off",
522
- "jsdoc/require-param-type": "off",
523
- "jsdoc/require-property-type": "off",
524
- "jsdoc/require-returns-type": "off"
525
- }
533
+ rules: getJsDocRules("warn", !!stylistic, "tsOnly")
526
534
  }
527
535
  );
528
536
  }
@@ -1190,9 +1198,12 @@ const STYLISTIC_CONFIG_DEFAULT = {
1190
1198
  quoteProps: "as-needed"
1191
1199
  };
1192
1200
  async function stylistic(options = {}) {
1193
- const stylisticOptions = { ...STYLISTIC_CONFIG_DEFAULT, ...options };
1201
+ const stylisticOptions = {
1202
+ ...STYLISTIC_CONFIG_DEFAULT,
1203
+ ...typeof options.stylistic === "boolean" ? {} : options.stylistic
1204
+ };
1194
1205
  const stylisticPlugin = await interopDefault(import('@stylistic/eslint-plugin'));
1195
- const config = stylisticPlugin.configs.customize({ ...stylisticOptions, flat: true });
1206
+ const config = stylisticPlugin.configs.customize(stylisticOptions);
1196
1207
  return tseslint.config({
1197
1208
  name: "fabdeh/stylistic/rules",
1198
1209
  files: [GLOB_SRC],
@@ -1208,22 +1219,45 @@ async function stylistic(options = {}) {
1208
1219
  });
1209
1220
  }
1210
1221
 
1222
+ function isTailwindcssParserPerGlobOptions(options) {
1223
+ return "parsers" in options && options.parsers !== void 0;
1224
+ }
1211
1225
  async function tailwindcss(options = {}) {
1226
+ await ensurePackages(["eslint-plugin-tailwindcss"]);
1212
1227
  const tailwindcssPlugin = await interopDefault(import('eslint-plugin-tailwindcss'));
1213
- const { overrides } = options;
1214
- return tseslint.config({
1215
- name: "fabdeh/tailwindcss/rules",
1216
- plugins: { tailwindcss: tailwindcssPlugin },
1217
- files: [GLOB_SRC, GLOB_HTML],
1218
- rules: {
1219
- "tailwindcss/classnames-order": "error",
1220
- "tailwindcss/enforces-negative-arbitrary-values": "error",
1221
- "tailwindcss/enforces-shorthand": "error",
1222
- "tailwindcss/no-contradicting-classname": "error",
1223
- "tailwindcss/no-unnecessary-arbitrary-value": "error",
1224
- ...overrides
1228
+ let files;
1229
+ let parserConfigs;
1230
+ const { overrides = {} } = options;
1231
+ if (isTailwindcssParserPerGlobOptions(options)) {
1232
+ const parsers = options.parsers ?? {};
1233
+ files = { files: [...new Set(Object.keys(parsers))] };
1234
+ parserConfigs = Object.entries(parsers).map(([glob, parser], index) => ({
1235
+ name: `fabdeh/tailwindcss/parser-${index + 1}`,
1236
+ file: [glob],
1237
+ languageOptions: {
1238
+ parser
1239
+ }
1240
+ }));
1241
+ } else {
1242
+ files = { files: options.files ?? [GLOB_SRC, GLOB_HTML] };
1243
+ parserConfigs = [];
1244
+ }
1245
+ return tseslint.config(
1246
+ ...parserConfigs,
1247
+ {
1248
+ name: "fabdeh/tailwindcss/rules",
1249
+ plugins: { tailwindcss: tailwindcssPlugin },
1250
+ ...files,
1251
+ rules: {
1252
+ "tailwindcss/classnames-order": "error",
1253
+ "tailwindcss/enforces-negative-arbitrary-values": "error",
1254
+ "tailwindcss/enforces-shorthand": "error",
1255
+ "tailwindcss/no-contradicting-classname": "error",
1256
+ "tailwindcss/no-unnecessary-arbitrary-value": "error",
1257
+ ...overrides
1258
+ }
1225
1259
  }
1226
- });
1260
+ );
1227
1261
  }
1228
1262
 
1229
1263
  async function toml(options = {}) {
@@ -1300,8 +1334,16 @@ const memberOrdering = {
1300
1334
  ]
1301
1335
  };
1302
1336
 
1303
- function typescript(options = {}) {
1304
- const { stylistic = true, parserOptions = {}, overrides = {} } = options;
1337
+ async function typescript(options = {}) {
1338
+ const { stylistic = true, parserOptions = {}, overrides = {}, enableErasableSyntaxOnly = false } = options;
1339
+ let erasableSyntaxOnlyPlugin;
1340
+ let erasableSyntaxOnlyRules;
1341
+ if (enableErasableSyntaxOnly) {
1342
+ await ensurePackages(["eslint-plugin-erasable-syntax-only"]);
1343
+ const erasableSyntaxOnly = await interopDefault(import('eslint-plugin-erasable-syntax-only'));
1344
+ erasableSyntaxOnlyPlugin = erasableSyntaxOnly;
1345
+ erasableSyntaxOnlyRules = erasableSyntaxOnly.configs.recommended.rules;
1346
+ }
1305
1347
  return tseslint.config(
1306
1348
  {
1307
1349
  name: "fabdeh/typescript/setup",
@@ -1326,7 +1368,8 @@ function typescript(options = {}) {
1326
1368
  ignores: [`${GLOB_MARKDOWN}/**`],
1327
1369
  plugins: {
1328
1370
  "@typescript-eslint": tseslint.plugin,
1329
- "unused-imports": unusedImports
1371
+ "unused-imports": unusedImports,
1372
+ ...erasableSyntaxOnlyPlugin ? { "erasable-syntax-only": erasableSyntaxOnlyPlugin } : {}
1330
1373
  },
1331
1374
  rules: {
1332
1375
  ...tseslint.configs.strictTypeChecked.find((c) => c.name === "typescript-eslint/eslint-recommended")?.rules,
@@ -1393,6 +1436,7 @@ function typescript(options = {}) {
1393
1436
  "@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }],
1394
1437
  "@typescript-eslint/unified-signatures": "error",
1395
1438
  "@typescript-eslint/no-unused-vars": "off",
1439
+ ...erasableSyntaxOnlyRules,
1396
1440
  ...overrides
1397
1441
  }
1398
1442
  }
@@ -1560,6 +1604,7 @@ async function vitest(options = {}) {
1560
1604
  "vitest/prefer-todo": "error",
1561
1605
  "vitest/prefer-vi-mocked": "error",
1562
1606
  "vitest/require-top-level-describe": "error",
1607
+ ...getJsDocRules("off", true, "both"),
1563
1608
  ...overrides
1564
1609
  }
1565
1610
  });
@@ -1632,7 +1677,7 @@ function mergePrettierOptions(options, overrides = {}) {
1632
1677
  /* eslint-enable @typescript-eslint/no-unsafe-assignment */
1633
1678
  };
1634
1679
  }
1635
- async function formatters(options = {}, stylistic = {}) {
1680
+ async function formatters(options = {}, stylistic = {}, hasAngularTemplateParser = false) {
1636
1681
  if (options === true) {
1637
1682
  const isPrettierPluginXmlInScope = isPackageInScope("@prettier/plugin-xml");
1638
1683
  options = {
@@ -1729,8 +1774,10 @@ async function formatters(options = {}, stylistic = {}) {
1729
1774
  if (options.html) {
1730
1775
  configs.push({
1731
1776
  name: "fabdeh/formatter/html",
1732
- languageOptions: {
1733
- parser: formatPlugin.parserPlain
1777
+ ...hasAngularTemplateParser ? {} : {
1778
+ languageOptions: {
1779
+ parser: formatPlugin.parserPlain
1780
+ }
1734
1781
  },
1735
1782
  files: [GLOB_HTML],
1736
1783
  rules: {
@@ -1845,17 +1892,21 @@ const FLAT_CONFIG_PROPS = [
1845
1892
  "extends"
1846
1893
  ];
1847
1894
  const NGRX_PACKAGES = ["@ngrx/store", "@ngrx/effects", "@ngrx/signals", "@ngrx/operators"];
1848
- async function createConfig(options = {}, ...userConfigs) {
1895
+ async function defineConfig(options = {}, ...userConfigs) {
1849
1896
  const {
1850
1897
  angular: enableAngular = isPackageExists("@angular/core"),
1851
1898
  gitignore: enableGitignore = true,
1899
+ jsdoc: enableJsdoc = true,
1852
1900
  ngrx: enableNgrx = NGRX_PACKAGES.some((p) => isPackageExists(p)),
1853
1901
  regexp: enableRegexp = true,
1854
- tailwindcss: enableTailwind = isPackageExists("tailwindcss"),
1902
+ tailwindcss: enableTailwind = false,
1855
1903
  typescript: enableTypescript = isPackageExists("typescript"),
1856
1904
  unicorn: enableUnicorn = true,
1857
1905
  vitest: enableVitest = isPackageExists("vitest")
1858
1906
  } = options;
1907
+ if (enableNgrx && !enableAngular) {
1908
+ throw new Error("NgRx rules can only be enabled if Angular rules are also enabled.");
1909
+ }
1859
1910
  const stylisticOptions = options.stylistic === false ? false : typeof options.stylistic === "object" ? options.stylistic : {};
1860
1911
  const configs = [];
1861
1912
  if (enableGitignore) {
@@ -1877,11 +1928,12 @@ async function createConfig(options = {}, ...userConfigs) {
1877
1928
  ignores(options.ignores),
1878
1929
  javascript({ overrides: options.javascript?.overrides }),
1879
1930
  comments(),
1880
- // TODO: add node rules ???
1881
- jsdoc({ stylistic: stylisticOptions }),
1882
1931
  imports({ stylistic: stylisticOptions }),
1883
1932
  perfectionist()
1884
1933
  );
1934
+ if (enableJsdoc) {
1935
+ configs.push(jsdoc({ stylistic: stylisticOptions }));
1936
+ }
1885
1937
  if (enableUnicorn) {
1886
1938
  const unicornOptions = resolveSubOptions(options, "unicorn");
1887
1939
  configs.push(unicorn(unicornOptions));
@@ -1946,7 +1998,11 @@ async function createConfig(options = {}, ...userConfigs) {
1946
1998
  configs.push(markdown(markdownOptions));
1947
1999
  }
1948
2000
  if (options.formatters) {
1949
- configs.push(formatters(options.formatters, typeof stylisticOptions === "boolean" ? {} : stylisticOptions));
2001
+ configs.push(formatters(
2002
+ options.formatters,
2003
+ typeof stylisticOptions === "boolean" ? {} : stylisticOptions,
2004
+ Boolean(enableAngular)
2005
+ ));
1950
2006
  }
1951
2007
  if ("files" in options) {
1952
2008
  throw new Error('[@fabdeh/eslint-config] The first argument should not contain the "files" property as the options are supposed to be global. Place it in the second or later config instead.');
@@ -1960,4 +2016,4 @@ async function createConfig(options = {}, ...userConfigs) {
1960
2016
  return tseslint.config(...await Promise.all(configs), ...await Promise.all(userConfigs));
1961
2017
  }
1962
2018
 
1963
- export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, createConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, regexp, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
2019
+ export { GLOB_HTML, GLOB_JS, GLOB_SRC, GLOB_TESTS, GLOB_TS, STYLISTIC_CONFIG_DEFAULT, angular, comments, defineConfig, ensurePackages, findNearestPackageJsonName, getWorkspaceRoot, ignores, imports, interopDefault, isPackageInScope, javascript, jsdoc, jsonc, markdown, ngrx, perfectionist, regexp, resolveSubOptions, sortPackageJson, sortTsConfig, stylistic, tailwindcss, toml, typescript, unicorn, vitest, yaml };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@fabdeh/eslint-config",
3
3
  "type": "module",
4
- "version": "0.2.3",
5
- "packageManager": "pnpm@10.4.1",
4
+ "version": "0.4.0",
5
+ "packageManager": "pnpm@10.6.5+sha512.cdf928fca20832cd59ec53826492b7dc25dc524d4370b6b4adbf65803d32efaa6c1c88147c0ae4e8d579a6c9eec715757b50d4fa35eea179d868eada4ed043af",
6
6
  "description": "My personal eslint config preset",
7
7
  "author": {
8
8
  "name": "Fabien Dehopré",
@@ -54,17 +54,25 @@
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@prettier/plugin-xml": "^3.4.1",
57
- "eslint": "^9.20.0",
57
+ "eslint": "^9.21.0",
58
+ "eslint-plugin-erasable-syntax-only": "^0.3.0",
58
59
  "eslint-plugin-format": "^1.0.1",
60
+ "eslint-plugin-tailwindcss": "^3.18.0",
59
61
  "prettier-plugin-slidev": "^1.0.5"
60
62
  },
61
63
  "peerDependenciesMeta": {
62
64
  "@prettier/plugin-xml": {
63
65
  "optional": true
64
66
  },
67
+ "eslint-plugin-erasable-syntax-only": {
68
+ "optional": true
69
+ },
65
70
  "eslint-plugin-format": {
66
71
  "optional": true
67
72
  },
73
+ "eslint-plugin-tailwindcss": {
74
+ "optional": true
75
+ },
68
76
  "prettier-plugin-slidev": {
69
77
  "optional": true
70
78
  }
@@ -73,43 +81,42 @@
73
81
  "@antfu/install-pkg": "^1.0.0",
74
82
  "@clack/prompts": "^0.10.0",
75
83
  "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1",
76
- "@eslint/js": "^9.20.0",
77
- "@eslint/markdown": "^6.2.2",
84
+ "@eslint/js": "^9.22.0",
85
+ "@eslint/markdown": "^6.3.0",
78
86
  "@ngrx/eslint-plugin": "^19.0.1",
79
- "@stylistic/eslint-plugin": "^3.1.0",
80
- "@typescript-eslint/eslint-plugin": "^8.24.1",
81
- "@typescript-eslint/parser": "^8.24.1",
82
- "@typescript-eslint/utils": "^8.24.1",
83
- "@vitest/eslint-plugin": "^1.1.31",
84
- "angular-eslint": "^19.1.0",
87
+ "@stylistic/eslint-plugin": "^4.2.0",
88
+ "@typescript-eslint/eslint-plugin": "^8.26.1",
89
+ "@typescript-eslint/parser": "^8.26.1",
90
+ "@typescript-eslint/utils": "^8.26.1",
91
+ "@vitest/eslint-plugin": "^1.1.38",
92
+ "angular-eslint": "^19.2.1",
85
93
  "eslint-config-flat-gitignore": "^2.1.0",
86
94
  "eslint-flat-config-utils": "^2.0.1",
87
95
  "eslint-merge-processors": "^2.0.0",
88
- "eslint-plugin-import-x": "^4.6.1",
96
+ "eslint-plugin-import-x": "^4.9.0",
89
97
  "eslint-plugin-jest-dom": "^5.5.0",
90
- "eslint-plugin-jsdoc": "^50.6.3",
98
+ "eslint-plugin-jsdoc": "^50.6.8",
91
99
  "eslint-plugin-jsonc": "^2.19.1",
92
- "eslint-plugin-perfectionist": "^4.9.0",
100
+ "eslint-plugin-perfectionist": "^4.10.1",
93
101
  "eslint-plugin-prefer-arrow-functions": "^3.6.2",
94
102
  "eslint-plugin-regexp": "^2.7.0",
95
- "eslint-plugin-tailwindcss": "^3.18.0",
96
103
  "eslint-plugin-testing-library": "^7.1.1",
97
104
  "eslint-plugin-toml": "^0.12.0",
98
105
  "eslint-plugin-unicorn": "^57.0.0",
99
106
  "eslint-plugin-unused-imports": "^4.1.4",
100
107
  "eslint-plugin-yml": "^1.17.0",
101
- "globals": "^15.15.0",
108
+ "globals": "^16.0.0",
102
109
  "jsonc-eslint-parser": "^2.4.0",
103
- "local-pkg": "^1.0.0",
110
+ "local-pkg": "^1.1.1",
104
111
  "toml-eslint-parser": "^0.10.0",
105
- "typescript-eslint": "^8.24.1",
106
- "yaml-eslint-parser": "^1.2.3"
112
+ "typescript-eslint": "^8.26.1",
113
+ "yaml-eslint-parser": "^1.3.0"
107
114
  },
108
115
  "devDependencies": {
109
- "@angular/core": "^19.1.7",
110
- "@commitlint/cli": "^19.7.1",
111
- "@commitlint/config-conventional": "^19.7.1",
112
- "@commitlint/cz-commitlint": "^19.6.1",
116
+ "@angular/core": "^19.2.2",
117
+ "@commitlint/cli": "^19.8.0",
118
+ "@commitlint/config-conventional": "^19.8.0",
119
+ "@commitlint/cz-commitlint": "^19.8.0",
113
120
  "@fabdeh/eslint-config": "workspace:*",
114
121
  "@ngrx/effects": "^19.0.1",
115
122
  "@ngrx/operators": "^19.0.1",
@@ -119,12 +126,14 @@
119
126
  "@testing-library/angular": "^17.3.6",
120
127
  "@testing-library/jest-dom": "^6.6.3",
121
128
  "@types/fs-extra": "^11.0.4",
122
- "@types/node": "^22.13.4",
123
- "bumpp": "^10.0.3",
124
- "changelogithub": "^13.12.1",
129
+ "@types/node": "^22.13.10",
130
+ "bumpp": "^10.1.0",
131
+ "changelogithub": "^13.13.0",
125
132
  "commitizen": "^4.3.1",
126
- "eslint": "^9.20.1",
133
+ "eslint": "^9.22.0",
134
+ "eslint-plugin-erasable-syntax-only": "^0.3.0",
127
135
  "eslint-plugin-format": "^1.0.1",
136
+ "eslint-plugin-tailwindcss": "^3.18.0",
128
137
  "execa": "^9.5.2",
129
138
  "fast-glob": "^3.3.3",
130
139
  "fs-extra": "^11.3.0",
@@ -135,9 +144,9 @@
135
144
  "prettier-plugin-slidev": "^1.0.5",
136
145
  "simple-git-hooks": "^2.11.1",
137
146
  "tailwindcss": "^3.4.17",
138
- "typescript": "^5.7.3",
139
- "unbuild": "^3.3.1",
140
- "vitest": "^3.0.6"
147
+ "typescript": "^5.8.2",
148
+ "unbuild": "^3.5.0",
149
+ "vitest": "^3.0.9"
141
150
  },
142
151
  "pnpm": {
143
152
  "overrides": {