@fabdeh/eslint-config 0.2.3 → 0.3.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 +258 -6
- package/dist/index.d.mts +26 -9
- package/dist/index.mjs +66 -24
- package/package.json +16 -7
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
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), [
|
|
13
|
-
|
|
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
|
|
@@ -49,8 +49,8 @@ For example:
|
|
|
49
49
|
```json
|
|
50
50
|
{
|
|
51
51
|
"scripts": {
|
|
52
|
-
"lint": "eslint .",
|
|
53
|
-
"lint:
|
|
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
|
-
//
|
|
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": [
|
|
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 © 2025-PRESENT [Fabien Dehopré](https://github.com/FabienDehopre)
|
package/dist/index.d.mts
CHANGED
|
@@ -170,9 +170,9 @@ interface UnicornOptions {
|
|
|
170
170
|
allRecommended?: boolean;
|
|
171
171
|
}
|
|
172
172
|
/**
|
|
173
|
-
* An alias for the `StylisticCustomizeOptions` type without the `
|
|
173
|
+
* An alias for the `StylisticCustomizeOptions` type without the `pluginName` property.
|
|
174
174
|
*/
|
|
175
|
-
type StylisticConfig = Omit<StylisticCustomizeOptions, '
|
|
175
|
+
type StylisticConfig = Omit<StylisticCustomizeOptions, 'pluginName'>;
|
|
176
176
|
/**
|
|
177
177
|
* Interface representing the stylistic options.
|
|
178
178
|
*/
|
|
@@ -191,6 +191,14 @@ interface TypeScriptParserOptions {
|
|
|
191
191
|
*/
|
|
192
192
|
parserOptions?: TSESLint.FlatConfig.ParserOptions;
|
|
193
193
|
}
|
|
194
|
+
interface TypeScriptErasableSyntaxOnlyOptions {
|
|
195
|
+
/**
|
|
196
|
+
* Indicates whether the erasable syntax only rules should be enabled or not.
|
|
197
|
+
*
|
|
198
|
+
* @default false
|
|
199
|
+
*/
|
|
200
|
+
enableErasableSyntaxOnly?: boolean;
|
|
201
|
+
}
|
|
194
202
|
/**
|
|
195
203
|
* Options for configuring Angular-specific linting rules.
|
|
196
204
|
*/
|
|
@@ -289,6 +297,13 @@ interface RegExpOptions {
|
|
|
289
297
|
*/
|
|
290
298
|
level?: 'error' | 'warn';
|
|
291
299
|
}
|
|
300
|
+
interface TailwindcssParserPerGlobOptions {
|
|
301
|
+
/**
|
|
302
|
+
* Provides a specific ESLint parser per glob pattern.
|
|
303
|
+
* This is only needed if you want to lint tailwindcss without using Angular and TypeScript.
|
|
304
|
+
*/
|
|
305
|
+
parsers?: Record<string, TSESLint.FlatConfig.Parser>;
|
|
306
|
+
}
|
|
292
307
|
/**
|
|
293
308
|
* Options for creating an ESLint configuration.
|
|
294
309
|
*
|
|
@@ -313,7 +328,7 @@ interface CreateConfigOptions {
|
|
|
313
328
|
*
|
|
314
329
|
* @default auto-detected
|
|
315
330
|
*/
|
|
316
|
-
typescript?: boolean | (OverridesOptions & TypeScriptParserOptions);
|
|
331
|
+
typescript?: boolean | (OverridesOptions & TypeScriptErasableSyntaxOnlyOptions & TypeScriptParserOptions);
|
|
317
332
|
/**
|
|
318
333
|
* Enable stylistic rules.
|
|
319
334
|
*
|
|
@@ -355,9 +370,9 @@ interface CreateConfigOptions {
|
|
|
355
370
|
/**
|
|
356
371
|
* Options for the TailwindCSS linting rules.
|
|
357
372
|
*
|
|
358
|
-
* @default
|
|
373
|
+
* @default false
|
|
359
374
|
*/
|
|
360
|
-
tailwindcss?: OverridesOptions |
|
|
375
|
+
tailwindcss?: boolean | (FilesOptions & OverridesOptions) | (OverridesOptions & TailwindcssParserPerGlobOptions);
|
|
361
376
|
/**
|
|
362
377
|
* Enable JSONC support.
|
|
363
378
|
*
|
|
@@ -543,8 +558,10 @@ declare function ngrx(options?: NgrxOptions): Promise<ConfigArray>;
|
|
|
543
558
|
declare function perfectionist(): Promise<ConfigArray>;
|
|
544
559
|
|
|
545
560
|
/**
|
|
561
|
+
* Configure the recommended regexp rules.
|
|
546
562
|
*
|
|
547
|
-
* @param options
|
|
563
|
+
* @param options - The options
|
|
564
|
+
* @returns The ESLint configuration for regexp linting
|
|
548
565
|
*/
|
|
549
566
|
declare function regexp(options?: OverridesOptions & RegExpOptions): ConfigArray;
|
|
550
567
|
|
|
@@ -596,7 +613,7 @@ declare function stylistic(options?: StylisticOptions): Promise<ConfigArray>;
|
|
|
596
613
|
* },
|
|
597
614
|
* });
|
|
598
615
|
*/
|
|
599
|
-
declare function tailwindcss(options?: OverridesOptions): Promise<ConfigArray>;
|
|
616
|
+
declare function tailwindcss(options?: (FilesOptions & OverridesOptions) | (OverridesOptions & TailwindcssParserPerGlobOptions)): Promise<ConfigArray>;
|
|
600
617
|
|
|
601
618
|
/**
|
|
602
619
|
* Generates an ESLint configuration for TOML files.
|
|
@@ -619,7 +636,7 @@ declare function toml(options?: FilesOptions & OverridesOptions & StylisticOptio
|
|
|
619
636
|
* @param options.overrides - Additional rule overrides.
|
|
620
637
|
* @returns A ConfigArray containing the TypeScript ESLint configuration.
|
|
621
638
|
*/
|
|
622
|
-
declare function typescript(options?: OverridesOptions & StylisticOptions & TypeScriptParserOptions): ConfigArray
|
|
639
|
+
declare function typescript(options?: OverridesOptions & StylisticOptions & TypeScriptErasableSyntaxOnlyOptions & TypeScriptParserOptions): Promise<ConfigArray>;
|
|
623
640
|
|
|
624
641
|
/**
|
|
625
642
|
* Generates a configuration array for the Unicorn plugin with the specified options.
|
|
@@ -758,4 +775,4 @@ type ResolvedOptions<T> = T extends boolean ? never : NonNullable<T>;
|
|
|
758
775
|
*/
|
|
759
776
|
declare function resolveSubOptions<K extends keyof CreateConfigOptions>(options: CreateConfigOptions, key: K): ResolvedOptions<CreateConfigOptions[K]>;
|
|
760
777
|
|
|
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 };
|
|
778
|
+
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 TailwindcssParserPerGlobOptions, type TestingOptions, type TypeScriptErasableSyntaxOnlyOptions, 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 };
|
package/dist/index.mjs
CHANGED
|
@@ -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
|
|
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",
|
|
@@ -1190,9 +1190,12 @@ const STYLISTIC_CONFIG_DEFAULT = {
|
|
|
1190
1190
|
quoteProps: "as-needed"
|
|
1191
1191
|
};
|
|
1192
1192
|
async function stylistic(options = {}) {
|
|
1193
|
-
const stylisticOptions = {
|
|
1193
|
+
const stylisticOptions = {
|
|
1194
|
+
...STYLISTIC_CONFIG_DEFAULT,
|
|
1195
|
+
...typeof options.stylistic === "boolean" ? {} : options.stylistic
|
|
1196
|
+
};
|
|
1194
1197
|
const stylisticPlugin = await interopDefault(import('@stylistic/eslint-plugin'));
|
|
1195
|
-
const config = stylisticPlugin.configs.customize(
|
|
1198
|
+
const config = stylisticPlugin.configs.customize(stylisticOptions);
|
|
1196
1199
|
return tseslint.config({
|
|
1197
1200
|
name: "fabdeh/stylistic/rules",
|
|
1198
1201
|
files: [GLOB_SRC],
|
|
@@ -1208,22 +1211,45 @@ async function stylistic(options = {}) {
|
|
|
1208
1211
|
});
|
|
1209
1212
|
}
|
|
1210
1213
|
|
|
1214
|
+
function isTailwindcssParserPerGlobOptions(options) {
|
|
1215
|
+
return "parsers" in options && options.parsers !== void 0;
|
|
1216
|
+
}
|
|
1211
1217
|
async function tailwindcss(options = {}) {
|
|
1218
|
+
await ensurePackages(["eslint-plugin-tailwindcss"]);
|
|
1212
1219
|
const tailwindcssPlugin = await interopDefault(import('eslint-plugin-tailwindcss'));
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1220
|
+
let files;
|
|
1221
|
+
let parserConfigs;
|
|
1222
|
+
const { overrides = {} } = options;
|
|
1223
|
+
if (isTailwindcssParserPerGlobOptions(options)) {
|
|
1224
|
+
const parsers = options.parsers ?? {};
|
|
1225
|
+
files = { files: [...new Set(Object.keys(parsers))] };
|
|
1226
|
+
parserConfigs = Object.entries(parsers).map(([glob, parser], index) => ({
|
|
1227
|
+
name: `fabdeh/tailwindcss/parser-${index + 1}`,
|
|
1228
|
+
file: [glob],
|
|
1229
|
+
languageOptions: {
|
|
1230
|
+
parser
|
|
1231
|
+
}
|
|
1232
|
+
}));
|
|
1233
|
+
} else {
|
|
1234
|
+
files = { files: options.files ?? [GLOB_SRC, GLOB_HTML] };
|
|
1235
|
+
parserConfigs = [];
|
|
1236
|
+
}
|
|
1237
|
+
return tseslint.config(
|
|
1238
|
+
...parserConfigs,
|
|
1239
|
+
{
|
|
1240
|
+
name: "fabdeh/tailwindcss/rules",
|
|
1241
|
+
plugins: { tailwindcss: tailwindcssPlugin },
|
|
1242
|
+
...files,
|
|
1243
|
+
rules: {
|
|
1244
|
+
"tailwindcss/classnames-order": "error",
|
|
1245
|
+
"tailwindcss/enforces-negative-arbitrary-values": "error",
|
|
1246
|
+
"tailwindcss/enforces-shorthand": "error",
|
|
1247
|
+
"tailwindcss/no-contradicting-classname": "error",
|
|
1248
|
+
"tailwindcss/no-unnecessary-arbitrary-value": "error",
|
|
1249
|
+
...overrides
|
|
1250
|
+
}
|
|
1225
1251
|
}
|
|
1226
|
-
|
|
1252
|
+
);
|
|
1227
1253
|
}
|
|
1228
1254
|
|
|
1229
1255
|
async function toml(options = {}) {
|
|
@@ -1300,8 +1326,16 @@ const memberOrdering = {
|
|
|
1300
1326
|
]
|
|
1301
1327
|
};
|
|
1302
1328
|
|
|
1303
|
-
function typescript(options = {}) {
|
|
1304
|
-
const { stylistic = true, parserOptions = {}, overrides = {} } = options;
|
|
1329
|
+
async function typescript(options = {}) {
|
|
1330
|
+
const { stylistic = true, parserOptions = {}, overrides = {}, enableErasableSyntaxOnly = false } = options;
|
|
1331
|
+
let erasableSyntaxOnlyPlugin;
|
|
1332
|
+
let erasableSyntaxOnlyRules;
|
|
1333
|
+
if (enableErasableSyntaxOnly) {
|
|
1334
|
+
await ensurePackages(["eslint-plugin-erasable-syntax-only"]);
|
|
1335
|
+
const erasableSyntaxOnly = await interopDefault(import('eslint-plugin-erasable-syntax-only'));
|
|
1336
|
+
erasableSyntaxOnlyPlugin = erasableSyntaxOnly;
|
|
1337
|
+
erasableSyntaxOnlyRules = erasableSyntaxOnly.configs.recommended.rules;
|
|
1338
|
+
}
|
|
1305
1339
|
return tseslint.config(
|
|
1306
1340
|
{
|
|
1307
1341
|
name: "fabdeh/typescript/setup",
|
|
@@ -1326,7 +1360,8 @@ function typescript(options = {}) {
|
|
|
1326
1360
|
ignores: [`${GLOB_MARKDOWN}/**`],
|
|
1327
1361
|
plugins: {
|
|
1328
1362
|
"@typescript-eslint": tseslint.plugin,
|
|
1329
|
-
"unused-imports": unusedImports
|
|
1363
|
+
"unused-imports": unusedImports,
|
|
1364
|
+
...erasableSyntaxOnlyPlugin ? { "erasable-syntax-only": erasableSyntaxOnlyPlugin } : {}
|
|
1330
1365
|
},
|
|
1331
1366
|
rules: {
|
|
1332
1367
|
...tseslint.configs.strictTypeChecked.find((c) => c.name === "typescript-eslint/eslint-recommended")?.rules,
|
|
@@ -1393,6 +1428,7 @@ function typescript(options = {}) {
|
|
|
1393
1428
|
"@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }],
|
|
1394
1429
|
"@typescript-eslint/unified-signatures": "error",
|
|
1395
1430
|
"@typescript-eslint/no-unused-vars": "off",
|
|
1431
|
+
...erasableSyntaxOnlyRules,
|
|
1396
1432
|
...overrides
|
|
1397
1433
|
}
|
|
1398
1434
|
}
|
|
@@ -1632,7 +1668,7 @@ function mergePrettierOptions(options, overrides = {}) {
|
|
|
1632
1668
|
/* eslint-enable @typescript-eslint/no-unsafe-assignment */
|
|
1633
1669
|
};
|
|
1634
1670
|
}
|
|
1635
|
-
async function formatters(options = {}, stylistic = {}) {
|
|
1671
|
+
async function formatters(options = {}, stylistic = {}, hasAngularTemplateParser = false) {
|
|
1636
1672
|
if (options === true) {
|
|
1637
1673
|
const isPrettierPluginXmlInScope = isPackageInScope("@prettier/plugin-xml");
|
|
1638
1674
|
options = {
|
|
@@ -1729,8 +1765,10 @@ async function formatters(options = {}, stylistic = {}) {
|
|
|
1729
1765
|
if (options.html) {
|
|
1730
1766
|
configs.push({
|
|
1731
1767
|
name: "fabdeh/formatter/html",
|
|
1732
|
-
|
|
1733
|
-
|
|
1768
|
+
...hasAngularTemplateParser ? {} : {
|
|
1769
|
+
languageOptions: {
|
|
1770
|
+
parser: formatPlugin.parserPlain
|
|
1771
|
+
}
|
|
1734
1772
|
},
|
|
1735
1773
|
files: [GLOB_HTML],
|
|
1736
1774
|
rules: {
|
|
@@ -1851,7 +1889,7 @@ async function createConfig(options = {}, ...userConfigs) {
|
|
|
1851
1889
|
gitignore: enableGitignore = true,
|
|
1852
1890
|
ngrx: enableNgrx = NGRX_PACKAGES.some((p) => isPackageExists(p)),
|
|
1853
1891
|
regexp: enableRegexp = true,
|
|
1854
|
-
tailwindcss: enableTailwind =
|
|
1892
|
+
tailwindcss: enableTailwind = false,
|
|
1855
1893
|
typescript: enableTypescript = isPackageExists("typescript"),
|
|
1856
1894
|
unicorn: enableUnicorn = true,
|
|
1857
1895
|
vitest: enableVitest = isPackageExists("vitest")
|
|
@@ -1946,7 +1984,11 @@ async function createConfig(options = {}, ...userConfigs) {
|
|
|
1946
1984
|
configs.push(markdown(markdownOptions));
|
|
1947
1985
|
}
|
|
1948
1986
|
if (options.formatters) {
|
|
1949
|
-
configs.push(formatters(
|
|
1987
|
+
configs.push(formatters(
|
|
1988
|
+
options.formatters,
|
|
1989
|
+
typeof stylisticOptions === "boolean" ? {} : stylisticOptions,
|
|
1990
|
+
Boolean(enableAngular)
|
|
1991
|
+
));
|
|
1950
1992
|
}
|
|
1951
1993
|
if ("files" in options) {
|
|
1952
1994
|
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.');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabdeh/eslint-config",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"packageManager": "pnpm@10.4.1",
|
|
6
6
|
"description": "My personal eslint config preset",
|
|
7
7
|
"author": {
|
|
@@ -55,16 +55,24 @@
|
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@prettier/plugin-xml": "^3.4.1",
|
|
57
57
|
"eslint": "^9.20.0",
|
|
58
|
+
"eslint-plugin-erasable-syntax-only": "^0.2.1",
|
|
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,10 +81,10 @@
|
|
|
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.
|
|
84
|
+
"@eslint/js": "^9.21.0",
|
|
77
85
|
"@eslint/markdown": "^6.2.2",
|
|
78
86
|
"@ngrx/eslint-plugin": "^19.0.1",
|
|
79
|
-
"@stylistic/eslint-plugin": "^
|
|
87
|
+
"@stylistic/eslint-plugin": "^4.0.1",
|
|
80
88
|
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
|
81
89
|
"@typescript-eslint/parser": "^8.24.1",
|
|
82
90
|
"@typescript-eslint/utils": "^8.24.1",
|
|
@@ -92,13 +100,12 @@
|
|
|
92
100
|
"eslint-plugin-perfectionist": "^4.9.0",
|
|
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": "^
|
|
108
|
+
"globals": "^16.0.0",
|
|
102
109
|
"jsonc-eslint-parser": "^2.4.0",
|
|
103
110
|
"local-pkg": "^1.0.0",
|
|
104
111
|
"toml-eslint-parser": "^0.10.0",
|
|
@@ -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.
|
|
129
|
+
"@types/node": "^22.13.5",
|
|
123
130
|
"bumpp": "^10.0.3",
|
|
124
131
|
"changelogithub": "^13.12.1",
|
|
125
132
|
"commitizen": "^4.3.1",
|
|
126
|
-
"eslint": "^9.
|
|
133
|
+
"eslint": "^9.21.0",
|
|
134
|
+
"eslint-plugin-erasable-syntax-only": "^0.2.1",
|
|
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",
|