@ncontiero/eslint-config 8.0.0-beta.2 → 8.0.0-beta.3

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
@@ -1,19 +1,18 @@
1
1
  # @ncontiero/eslint-config
2
2
 
3
- Nicolas's ESLint config preset for JavaScript, TypeScript, and Prettier.
3
+ [![Version](https://img.shields.io/npm/v/@ncontiero/eslint-config?color6C47FF)](https://www.npmjs.com/package/@ncontiero/eslint-config)
4
+ [![License](https://img.shields.io/badge/licence-MIT-6C47FF)](https://github.com/ncontiero/eslint-config/blob/master/LICENSE)
4
5
 
5
- [![Version](https://img.shields.io/npm/v/@ncontiero/eslint-config)](https://www.npmjs.com/package/@ncontiero/eslint-config)
6
- [![License](https://img.shields.io/badge/licence-MIT-blue)](https://github.com/ncontiero/eslint-config/blob/master/LICENSE)
6
+ Nicolas's ESLint config preset for JavaScript, TypeScript, and Prettier.
7
7
 
8
8
  ## Features
9
9
 
10
- - Double quotes, with semi.
11
10
  - Format with Prettier.
12
- - Sort imports, `package.json`, `tsconfig.json`...
13
11
  - Reasonable defaults, best practices, only one line of config.
14
- - Designed to work with TypeScript out-of-box.
15
- - Support JSON(5), YAML, TOML, Markdown, HTML with [HTML Eslint](https://html-eslint.org/)...
16
- - [ESLint Flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new), compose easily!
12
+ - Designed to work with TypeScript and JSX. Out-of-box.
13
+ - Support JSON(5), YAML, TOML, Markdown, HTML with [HTML Eslint](https://html-eslint.org/).
14
+ - [ESLint Flat config](https://eslint.org/docs/latest/use/configure/configuration-files), compose easily!
15
+ - Sort imports, `package.json`, `tsconfig.json`...
17
16
  - Ignores common files like `dist`, `node_modules`, `coverage`, and files in `.gitignore`.
18
17
  - Optional [React](https://react.dev/), [NextJs](https://nextjs.org/), [TailwindCSS](https://tailwindcss.com/), [TanStack Query](https://tanstack.com/query/) support.
19
18
  - Requires ESLint v9.20.0+.
@@ -34,20 +33,7 @@ npm i -D eslint @ncontiero/eslint-config
34
33
  // eslint.config.mjs
35
34
  import { ncontiero } from "@ncontiero/eslint-config";
36
35
 
37
- export default ncontiero(
38
- // Features: it'll detect installed dependency and enable necessary features automatically
39
- {
40
- prettier: true,
41
- markdown: true,
42
- react: true, // auto detection
43
- nextjs: false, // auto detection
44
- tailwindcss: false, // auto detection
45
- reactQuery: false, // auto detection
46
- },
47
- {
48
- /* your custom config */
49
- },
50
- );
36
+ export default ncontiero();
51
37
  ```
52
38
 
53
39
  3. Add script for package.json:
@@ -164,6 +150,25 @@ export default ncontiero(
164
150
  );
165
151
  ```
166
152
 
153
+ ### Plugins Renaming
154
+
155
+ Since flat config requires us to explicitly provide the plugin names (instead of the mandatory convention from npm package name), we renamed some plugins to make the overall scope more consistent and easier to write.
156
+
157
+ | New Prefix | Original Prefix | Source Plugin |
158
+ | ---------- | ---------------------- | ------------------------------------------------------------------------------------------ |
159
+ | `ts/*` | `@typescript-eslint/*` | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint) |
160
+ | `react/*` | `@eslint-react/*` | [@eslint-react/eslint-plugin](https://github.com/Rel1cx/eslint-react) |
161
+
162
+ When you want to override rules, or disable them inline, you need to update to the new prefix:
163
+
164
+ ```diff
165
+ -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
166
+ +// eslint-disable-next-line ts/consistent-type-definitions
167
+ type foo = { bar: 2 }
168
+ ```
169
+
170
+ This preset will automatically rename the plugins also for your custom configs. You can use the original prefix to override the rules directly, but the TypeScript will complain about the unknown rules, so you need to use the new prefix instead.
171
+
167
172
  ### Rules Overrides
168
173
 
169
174
  Certain rules would only be enabled in specific files, for example, `ts/*` rules would only be enabled in `.ts`. We also provided the overrides options in each integration to make it easier:
@@ -213,6 +218,59 @@ npm i -D @tanstack/eslint-plugin-query
213
218
 
214
219
  > Require @tanstack/eslint-plugin-query >= 5.50.0
215
220
 
221
+ ### Optional Rules
222
+
223
+ This config also provides some optional plugins/rules for extended usage.
224
+
225
+ #### `command`
226
+
227
+ Powered by [`eslint-plugin-command`](https://github.com/antfu/eslint-plugin-command). It is not a typical rule for linting, but an on-demand micro-codemod tool that triggers by specific comments.
228
+
229
+ For a few triggers, for example:
230
+
231
+ - `/// to-function` - converts an arrow function to a normal function
232
+ - `/// to-arrow` - converts a normal function to an arrow function
233
+ - `/// to-for-each` - converts a for-in/for-of loop to `.forEach()`
234
+ - `/// to-for-of` - converts a `.forEach()` to a for-of loop
235
+ - `/// keep-sorted` - sorts an object/array/interface
236
+ - ... etc. - refer to the [documentation](https://github.com/antfu/eslint-plugin-command#built-in-commands)
237
+
238
+ You can add the trigger comment one line above the code you want to transform, for example (note the triple slash):
239
+
240
+ <!-- eslint-skip -->
241
+
242
+ ```ts
243
+ /// to-function
244
+ const foo = (msg: string): void => {
245
+ console.log(msg);
246
+ };
247
+ ```
248
+
249
+ Will be transformed to this when you hit save with your editor or run `eslint --fix`:
250
+
251
+ ```ts
252
+ function foo(msg: string): void {
253
+ console.log(msg);
254
+ }
255
+ ```
256
+
257
+ The command comments are usually one-off and will be removed along with the transformation.
258
+
259
+ ### Type Aware Rules
260
+
261
+ You can optionally enable the [type aware rules](https://typescript-eslint.io/linting/typed-linting/) by passing the options object to the `typescript` config:
262
+
263
+ ```js
264
+ // eslint.config.js
265
+ import { ncontiero } from "@ncontiero/eslint-config";
266
+
267
+ export default ncontiero({
268
+ typescript: {
269
+ tsconfigPath: "tsconfig.json",
270
+ },
271
+ });
272
+ ```
273
+
216
274
  ## References and inspirations
217
275
 
218
276
  - [@antfu/eslint-config](https://github.com/antfu/eslint-config) - Anthony's ESLint config preset.
package/dist/index.d.mts CHANGED
@@ -5,46 +5,6 @@ import { Options as PrettierOptions } from "prettier";
5
5
 
6
6
  //#region src/typegen.d.ts
7
7
  interface RuleOptions {
8
- /**
9
- * Exhaustive deps rule for useQuery
10
- * @see https://tanstack.com/query/latest/docs/eslint/exhaustive-deps
11
- */
12
- '@tanstack/query/exhaustive-deps'?: Linter.RuleEntry<TanstackQueryExhaustiveDeps>;
13
- /**
14
- * Ensure correct order of inference sensitive properties for infinite queries
15
- * @see https://tanstack.com/query/latest/docs/eslint/infinite-query-property-order
16
- */
17
- '@tanstack/query/infinite-query-property-order'?: Linter.RuleEntry<[]>;
18
- /**
19
- * Ensure correct order of inference-sensitive properties in useMutation()
20
- * @see https://tanstack.com/query/latest/docs/eslint/mutation-property-order
21
- */
22
- '@tanstack/query/mutation-property-order'?: Linter.RuleEntry<[]>;
23
- /**
24
- * Disallows rest destructuring in queries
25
- * @see https://tanstack.com/query/latest/docs/eslint/no-rest-destructuring
26
- */
27
- '@tanstack/query/no-rest-destructuring'?: Linter.RuleEntry<[]>;
28
- /**
29
- * Disallow putting the result of query hooks directly in a React hook dependency array
30
- * @see https://tanstack.com/query/latest/docs/eslint/no-unstable-deps
31
- */
32
- '@tanstack/query/no-unstable-deps'?: Linter.RuleEntry<[]>;
33
- /**
34
- * Ensures queryFn returns a non-undefined value
35
- * @see https://tanstack.com/query/latest/docs/eslint/no-void-query-fn
36
- */
37
- '@tanstack/query/no-void-query-fn'?: Linter.RuleEntry<[]>;
38
- /**
39
- * Prefer using queryOptions() to co-locate queryKey and queryFn
40
- * @see https://tanstack.com/query/latest/docs/eslint/prefer-query-options
41
- */
42
- '@tanstack/query/prefer-query-options'?: Linter.RuleEntry<[]>;
43
- /**
44
- * Makes sure that QueryClient is stable
45
- * @see https://tanstack.com/query/latest/docs/eslint/stable-query-client
46
- */
47
- '@tanstack/query/stable-query-client'?: Linter.RuleEntry<[]>;
48
8
  /**
49
9
  * Enforce getter and setter pairs in objects and classes
50
10
  * @see https://eslint.org/docs/latest/rules/accessor-pairs
@@ -273,6 +233,86 @@ interface RuleOptions {
273
233
  * @see https://eslint.org/docs/latest/rules/dot-notation
274
234
  */
275
235
  'dot-notation'?: Linter.RuleEntry<DotNotation>;
236
+ /**
237
+ * Disallow dependencies in favor of more performant or secure alternatives
238
+ */
239
+ 'e18e/ban-dependencies'?: Linter.RuleEntry<E18EBanDependencies>;
240
+ /**
241
+ * Prefer optimized alternatives to `indexOf()` equality checks
242
+ */
243
+ 'e18e/no-indexof-equality'?: Linter.RuleEntry<[]>;
244
+ /**
245
+ * Prefer Array.prototype.at() over length-based indexing
246
+ */
247
+ 'e18e/prefer-array-at'?: Linter.RuleEntry<[]>;
248
+ /**
249
+ * Prefer Array.prototype.fill() over Array.from or map with constant values
250
+ */
251
+ 'e18e/prefer-array-fill'?: Linter.RuleEntry<[]>;
252
+ /**
253
+ * Prefer Array.from(iterable, mapper) over [...iterable].map(mapper) to avoid intermediate array allocation
254
+ */
255
+ 'e18e/prefer-array-from-map'?: Linter.RuleEntry<[]>;
256
+ /**
257
+ * Prefer Array.some() over Array.find() when checking for element existence
258
+ */
259
+ 'e18e/prefer-array-some'?: Linter.RuleEntry<[]>;
260
+ /**
261
+ * Prefer Array.prototype.toReversed() over copying and reversing arrays
262
+ */
263
+ 'e18e/prefer-array-to-reversed'?: Linter.RuleEntry<[]>;
264
+ /**
265
+ * Prefer Array.prototype.toSorted() over copying and sorting arrays
266
+ */
267
+ 'e18e/prefer-array-to-sorted'?: Linter.RuleEntry<[]>;
268
+ /**
269
+ * Prefer Array.prototype.toSpliced() over copying and splicing arrays
270
+ */
271
+ 'e18e/prefer-array-to-spliced'?: Linter.RuleEntry<[]>;
272
+ /**
273
+ * Prefer Date.now() over new Date().getTime() and +new Date()
274
+ */
275
+ 'e18e/prefer-date-now'?: Linter.RuleEntry<[]>;
276
+ /**
277
+ * Prefer the exponentiation operator ** over Math.pow()
278
+ */
279
+ 'e18e/prefer-exponentiation-operator'?: Linter.RuleEntry<[]>;
280
+ /**
281
+ * Prefer .includes() over indexOf() comparisons for arrays and strings
282
+ */
283
+ 'e18e/prefer-includes'?: Linter.RuleEntry<[]>;
284
+ /**
285
+ * Prefer inline equality checks over temporary object creation for simple comparisons
286
+ */
287
+ 'e18e/prefer-inline-equality'?: Linter.RuleEntry<[]>;
288
+ /**
289
+ * Prefer nullish coalescing operator (?? and ??=) over verbose null checks
290
+ */
291
+ 'e18e/prefer-nullish-coalescing'?: Linter.RuleEntry<[]>;
292
+ /**
293
+ * Prefer Object.hasOwn() over Object.prototype.hasOwnProperty.call() and obj.hasOwnProperty()
294
+ */
295
+ 'e18e/prefer-object-has-own'?: Linter.RuleEntry<[]>;
296
+ /**
297
+ * prefer `RegExp.test()` over `String.match()` and `RegExp.exec()` when only checking for match existence
298
+ */
299
+ 'e18e/prefer-regex-test'?: Linter.RuleEntry<[]>;
300
+ /**
301
+ * Prefer spread syntax over Array.concat(), Array.from(), Object.assign({}, ...), and Function.apply()
302
+ */
303
+ 'e18e/prefer-spread-syntax'?: Linter.RuleEntry<[]>;
304
+ /**
305
+ * Prefer defining regular expressions at module scope to avoid re-compilation on every function call
306
+ */
307
+ 'e18e/prefer-static-regex'?: Linter.RuleEntry<[]>;
308
+ /**
309
+ * Prefer passing function and arguments directly to setTimeout/setInterval instead of wrapping in an arrow function or using bind
310
+ */
311
+ 'e18e/prefer-timer-args'?: Linter.RuleEntry<[]>;
312
+ /**
313
+ * Prefer URL.canParse() over try-catch blocks for URL validation
314
+ */
315
+ 'e18e/prefer-url-canparse'?: Linter.RuleEntry<[]>;
276
316
  /**
277
317
  * Require or disallow newline at the end of files
278
318
  * @see https://eslint.org/docs/latest/rules/eol-last
@@ -492,8 +532,14 @@ interface RuleOptions {
492
532
  /**
493
533
  * Disallow extra spacing around attributes
494
534
  * @see https://html-eslint.org/docs/rules/no-extra-spacing-attrs
535
+ * @deprecated
495
536
  */
496
537
  'html/no-extra-spacing-attrs'?: Linter.RuleEntry<HtmlNoExtraSpacingAttrs>;
538
+ /**
539
+ * Disallow extra spacing inside tags
540
+ * @see https://html-eslint.org/docs/rules/no-extra-spacing-tags
541
+ */
542
+ 'html/no-extra-spacing-tags'?: Linter.RuleEntry<HtmlNoExtraSpacingTags>;
497
543
  /**
498
544
  * Disallow unnecessary consecutive spaces
499
545
  * @see https://html-eslint.org/docs/rules/no-extra-spacing-text
@@ -3472,7 +3518,7 @@ interface RuleOptions {
3472
3518
  * Disallow using promises inside of callbacks.
3473
3519
  * @see https://github.com/eslint-community/eslint-plugin-promise/blob/main/docs/rules/no-promise-in-callback.md
3474
3520
  */
3475
- 'promise/no-promise-in-callback'?: Linter.RuleEntry<[]>;
3521
+ 'promise/no-promise-in-callback'?: Linter.RuleEntry<PromiseNoPromiseInCallback>;
3476
3522
  /**
3477
3523
  * Disallow return statements in `finally()`.
3478
3524
  * @see https://github.com/eslint-community/eslint-plugin-promise/blob/main/docs/rules/no-return-in-finally.md
@@ -3876,6 +3922,11 @@ interface RuleOptions {
3876
3922
  * @see https://eslint-react.xyz/docs/rules/no-unused-props
3877
3923
  */
3878
3924
  'react/no-unused-props'?: Linter.RuleEntry<[]>;
3925
+ /**
3926
+ * Warns about state variables that are defined but never used, or only used in effects.
3927
+ * @see https://eslint-react.xyz/docs/rules/no-unused-state
3928
+ */
3929
+ 'react/no-unused-state'?: Linter.RuleEntry<[]>;
3879
3930
  /**
3880
3931
  * Replaces usage of 'useContext' with 'use'.
3881
3932
  * @see https://eslint-react.xyz/docs/rules/no-use-context
@@ -4166,6 +4217,11 @@ interface RuleOptions {
4166
4217
  * @see https://eslint-react.xyz/docs/rules/no-unused-props
4167
4218
  */
4168
4219
  'react/x-no-unused-props'?: Linter.RuleEntry<[]>;
4220
+ /**
4221
+ * Warns about state variables that are defined but never used, or only used in effects.
4222
+ * @see https://eslint-react.xyz/docs/rules/no-unused-state
4223
+ */
4224
+ 'react/x-no-unused-state'?: Linter.RuleEntry<[]>;
4169
4225
  /**
4170
4226
  * Replaces usage of 'useContext' with 'use'.
4171
4227
  * @see https://eslint-react.xyz/docs/rules/no-use-context
@@ -6560,13 +6616,7 @@ interface RuleOptions {
6560
6616
  'yoda'?: Linter.RuleEntry<Yoda>;
6561
6617
  }
6562
6618
  /* ======= Declarations ======= */
6563
- // ----- @tanstack/query/exhaustive-deps -----
6564
- type TanstackQueryExhaustiveDeps = [] | [{
6565
- allowlist?: {
6566
- variables?: string[];
6567
- types?: string[];
6568
- };
6569
- }]; // ----- accessor-pairs -----
6619
+ // ----- accessor-pairs -----
6570
6620
  type AccessorPairs = [] | [{
6571
6621
  getWithoutSet?: boolean;
6572
6622
  setWithoutGet?: boolean;
@@ -6707,6 +6757,11 @@ type DotLocation = [] | [("object" | "property")]; // ----- dot-notation -----
6707
6757
  type DotNotation = [] | [{
6708
6758
  allowKeywords?: boolean;
6709
6759
  allowPattern?: string;
6760
+ }]; // ----- e18e/ban-dependencies -----
6761
+ type E18EBanDependencies = [] | [{
6762
+ presets?: string[];
6763
+ modules?: string[];
6764
+ allowed?: string[];
6710
6765
  }]; // ----- eol-last -----
6711
6766
  type EolLast = [] | [("always" | "never" | "unix" | "windows")]; // ----- eqeqeq -----
6712
6767
  type Eqeqeq = ([] | ["always"] | ["always", {
@@ -6807,6 +6862,12 @@ type HtmlNoExtraSpacingAttrs = [] | [{
6807
6862
  disallowMissing?: boolean;
6808
6863
  disallowTabs?: boolean;
6809
6864
  enforceBeforeSelfClose?: boolean;
6865
+ }]; // ----- html/no-extra-spacing-tags -----
6866
+ type HtmlNoExtraSpacingTags = [] | [{
6867
+ disallowInAssignment?: boolean;
6868
+ disallowMissing?: boolean;
6869
+ disallowTabs?: boolean;
6870
+ enforceBeforeSelfClose?: boolean;
6810
6871
  }]; // ----- html/no-extra-spacing-text -----
6811
6872
  type HtmlNoExtraSpacingText = [] | [{
6812
6873
  skip?: string[];
@@ -11936,6 +11997,9 @@ type PromiseCatchOrReturn = [] | [{
11936
11997
  type PromiseNoCallbackInPromise = [] | [{
11937
11998
  exceptions?: string[];
11938
11999
  timeoutsErr?: boolean;
12000
+ }]; // ----- promise/no-promise-in-callback -----
12001
+ type PromiseNoPromiseInCallback = [] | [{
12002
+ exemptDeclarations?: boolean;
11939
12003
  }]; // ----- promise/no-return-wrap -----
11940
12004
  type PromiseNoReturnWrap = [] | [{
11941
12005
  allowReject?: boolean;
@@ -12376,6 +12440,7 @@ type TailwindcssEnforceCanonicalClasses = [] | [{
12376
12440
  rootFontSize?: number;
12377
12441
  cwd?: string;
12378
12442
  collapse?: boolean;
12443
+ ignore?: string[];
12379
12444
  logical?: boolean;
12380
12445
  }]; // ----- tailwindcss/enforce-consistent-class-order -----
12381
12446
  type TailwindcssEnforceConsistentClassOrder = [] | [{
@@ -12972,6 +13037,7 @@ type TailwindcssEnforceConsistentLineWrapping = [] | [{
12972
13037
  preferSingleLine?: boolean;
12973
13038
  printWidth?: number;
12974
13039
  strictness?: ("strict" | "loose");
13040
+ tabWidth?: number;
12975
13041
  }]; // ----- tailwindcss/enforce-consistent-variable-syntax -----
12976
13042
  type TailwindcssEnforceConsistentVariableSyntax = [] | [{
12977
13043
  selectors?: ({
@@ -16375,7 +16441,7 @@ type Yoda = [] | [("always" | "never")] | [("always" | "never"), {
16375
16441
  exceptRange?: boolean;
16376
16442
  onlyEquality?: boolean;
16377
16443
  }]; // Names of all the configs
16378
- type ConfigNames = 'ncontiero/gitignore' | 'ncontiero/global-ignores' | 'ncontiero/javascript/rules' | 'ncontiero/javascript/cli-rules' | 'ncontiero/javascript/test-rules' | 'ncontiero/comments/rules' | 'ncontiero/jsdoc/setup' | 'ncontiero/jsdoc/rules' | 'ncontiero/imports/rules' | 'ncontiero/imports/allow-default-export' | 'ncontiero/node/setup' | 'ncontiero/node/rules' | 'ncontiero/promise/setup' | 'ncontiero/promise/rules' | 'ncontiero/command/rules' | 'ncontiero/perfectionist/rules' | 'ncontiero/de-morgan' | 'ncontiero/unicorn/rules' | 'ncontiero/typescript/setup' | 'ncontiero/typescript/parser' | 'ncontiero/typescript/rules' | 'ncontiero/typescript/dts-rules' | 'ncontiero/typescript/cjs-rules' | 'ncontiero/jsonc/recommended' | 'ncontiero/jsonc/recommended' | 'ncontiero/jsonc/recommended' | 'ncontiero/jsonc/rules' | 'ncontiero/sort/package-json' | 'ncontiero/sort/tsconfig' | 'ncontiero/yml/setup' | 'ncontiero/yml/rules' | 'ncontiero/yml/pnpm-workspace' | 'ncontiero/toml/setup' | 'ncontiero/toml/rules' | 'ncontiero/markdown/setup' | 'ncontiero/markdown/processor' | 'ncontiero/markdown/parser' | 'ncontiero/markdown/rules' | 'ncontiero/regexp/rules' | 'ncontiero/react/setup' | 'ncontiero/tanstack-query' | 'ncontiero/react/rules' | 'ncontiero/react/typescript' | 'ncontiero/nextjs/rules' | 'ncontiero/html/setup' | 'ncontiero/html/rules' | 'ncontiero/tailwindcss/setup' | 'ncontiero/tailwindcss/rules' | 'ncontiero/prettier/setup' | 'ncontiero/prettier/disables' | 'ncontiero/prettier/rules' | 'ncontiero/prettier/markdown' | 'ncontiero/prettier/css' | 'ncontiero/prettier/scss' | 'ncontiero/prettier/less';
16444
+ type ConfigNames = 'ncontiero/gitignore' | 'ncontiero/ignores' | 'ncontiero/javascript/rules' | 'ncontiero/javascript/cli-rules' | 'ncontiero/javascript/test-rules' | 'ncontiero/comments/rules' | 'ncontiero/jsdoc/setup' | 'ncontiero/jsdoc/rules' | 'ncontiero/imports/rules' | 'ncontiero/imports/allow-default-export' | 'ncontiero/node/setup' | 'ncontiero/node/rules' | 'ncontiero/promise/setup' | 'ncontiero/promise/rules' | 'ncontiero/command/rules' | 'ncontiero/perfectionist/rules' | 'ncontiero/de-morgan' | 'ncontiero/e18e/rules' | 'ncontiero/unicorn/rules' | 'ncontiero/jsx/setup' | 'ncontiero/typescript/setup' | 'ncontiero/typescript/parser' | 'ncontiero/typescript/rules' | 'ncontiero/typescript/dts-rules' | 'ncontiero/typescript/cjs-rules' | 'ncontiero/jsonc/recommended' | 'ncontiero/jsonc/recommended' | 'ncontiero/jsonc/recommended' | 'ncontiero/jsonc/rules' | 'ncontiero/sort/package-json' | 'ncontiero/sort/tsconfig' | 'ncontiero/yml/setup' | 'ncontiero/yml/rules' | 'ncontiero/yml/pnpm-workspace' | 'ncontiero/toml/setup' | 'ncontiero/toml/rules' | 'ncontiero/markdown/setup' | 'ncontiero/markdown/processor' | 'ncontiero/markdown/parser' | 'ncontiero/markdown/rules' | 'ncontiero/regexp/rules' | 'ncontiero/react/setup' | 'ncontiero/react/rules' | 'ncontiero/react/typescript' | 'ncontiero/nextjs/setup' | 'ncontiero/nextjs/rules' | 'ncontiero/html/setup' | 'ncontiero/html/rules' | 'ncontiero/tailwindcss/setup' | 'ncontiero/tailwindcss/rules' | 'ncontiero/prettier/setup' | 'ncontiero/prettier/disables' | 'ncontiero/prettier/rules' | 'ncontiero/prettier/markdown' | 'ncontiero/prettier/css' | 'ncontiero/prettier/scss' | 'ncontiero/prettier/less';
16379
16445
  //#endregion
16380
16446
  //#region src/types.d.ts
16381
16447
  type Awaitable<T> = T | Promise<T>;
@@ -16435,9 +16501,6 @@ interface OptionsHasNextJs {
16435
16501
  interface OptionsHasRegexp {
16436
16502
  regexp?: boolean;
16437
16503
  }
16438
- interface OptionsHasTanStackReactQuery {
16439
- reactQuery?: boolean;
16440
- }
16441
16504
  interface StyleConfig {
16442
16505
  indent?: number;
16443
16506
  semi?: boolean;
@@ -16484,6 +16547,39 @@ interface OptionsTailwindCSS extends OptionsOverrides {
16484
16547
  */
16485
16548
  cwd?: string;
16486
16549
  }
16550
+ interface OptionsE18e extends OptionsOverrides {
16551
+ /**
16552
+ * Include modernization rules
16553
+ *
16554
+ * @see https://github.com/e18e/eslint-plugin#modernization
16555
+ * @default true
16556
+ */
16557
+ modernization?: boolean;
16558
+ /**
16559
+ * Include module replacements rules
16560
+ *
16561
+ * @see https://github.com/e18e/eslint-plugin#module-replacements
16562
+ * @default false
16563
+ */
16564
+ moduleReplacements?: boolean;
16565
+ /**
16566
+ * Include performance improvements rules
16567
+ *
16568
+ * @see https://github.com/e18e/eslint-plugin#performance-improvements
16569
+ * @default true
16570
+ */
16571
+ performanceImprovements?: boolean;
16572
+ }
16573
+ interface OptionsJSXA11y extends OptionsOverrides {}
16574
+ interface OptionsJSX {
16575
+ /**
16576
+ * Enable JSX accessibility rules.
16577
+ *
16578
+ * Can be a boolean or an object for custom options and overrides.
16579
+ * @default false
16580
+ */
16581
+ a11y?: boolean | OptionsJSXA11y;
16582
+ }
16487
16583
  interface OptionsConfig {
16488
16584
  /**
16489
16585
  * Enable gitignore support.
@@ -16504,12 +16600,26 @@ interface OptionsConfig {
16504
16600
  * @default auto-detect based on the dependencies
16505
16601
  */
16506
16602
  typescript?: boolean | OptionsTypescript;
16603
+ /**
16604
+ * Enable JSX related rules.
16605
+ *
16606
+ * Passing an object to enable JSX accessibility rules.
16607
+ *
16608
+ * @default true
16609
+ */
16610
+ jsx?: boolean | OptionsJSX;
16507
16611
  /**
16508
16612
  * Options for eslint-plugin-unicorn.
16509
16613
  *
16510
16614
  * @default true
16511
16615
  */
16512
16616
  unicorn?: boolean | OptionsUnicorn;
16617
+ /**
16618
+ * Options for [@e18e/eslint-plugin](https://github.com/e18e/eslint-plugin)
16619
+ *
16620
+ * @default true
16621
+ */
16622
+ e18e?: boolean | OptionsE18e;
16513
16623
  /**
16514
16624
  * Enable JSONC support.
16515
16625
  *
@@ -16575,11 +16685,11 @@ interface OptionsConfig {
16575
16685
  */
16576
16686
  tailwindcss?: boolean | OptionsTailwindCSS;
16577
16687
  /**
16578
- * Enable TanStack React Query support.
16688
+ * Enable TanStack Query support.
16579
16689
  *
16580
16690
  * @default auto-detect based on the dependencies
16581
16691
  */
16582
- reactQuery?: boolean;
16692
+ tanstackQuery?: boolean | OptionsOverrides;
16583
16693
  }
16584
16694
  //#endregion
16585
16695
  //#region src/configs/command.d.ts
@@ -16591,11 +16701,14 @@ declare function comments(): FlatConfigItem[];
16591
16701
  //#region src/configs/de-morgan.d.ts
16592
16702
  declare function deMorgan(): FlatConfigItem[];
16593
16703
  //#endregion
16704
+ //#region src/configs/e18e.d.ts
16705
+ declare function e18e(options?: OptionsE18e): Promise<FlatConfigItem[]>;
16706
+ //#endregion
16594
16707
  //#region src/configs/html.d.ts
16595
16708
  declare function html(options: HTMLOptions): Promise<FlatConfigItem[]>;
16596
16709
  //#endregion
16597
16710
  //#region src/configs/ignores.d.ts
16598
- declare function ignores(userIgnores?: string[]): FlatConfigItem[];
16711
+ declare function ignores(userIgnores?: string[], ignoreTypeScript?: boolean): FlatConfigItem[];
16599
16712
  //#endregion
16600
16713
  //#region src/configs/imports.d.ts
16601
16714
  declare function imports(options?: OptionsHasNextJs): FlatConfigItem[];
@@ -16610,6 +16723,9 @@ declare function jsdoc(): Promise<FlatConfigItem[]>;
16610
16723
  //#region src/configs/jsonc.d.ts
16611
16724
  declare function jsonc(options?: OptionsFiles & OptionsOverrides & StyleOptions): Promise<FlatConfigItem[]>;
16612
16725
  //#endregion
16726
+ //#region src/configs/jsx.d.ts
16727
+ declare function jsx(options?: OptionsJSX): Promise<FlatConfigItem[]>;
16728
+ //#endregion
16613
16729
  //#region src/configs/markdown.d.ts
16614
16730
  declare function markdown(options?: OptionsFiles & OptionsOverrides): Promise<FlatConfigItem[]>;
16615
16731
  //#endregion
@@ -16634,7 +16750,7 @@ declare function prettier(options?: PrettierOptions): Promise<FlatConfigItem[]>;
16634
16750
  declare function promise(): Promise<FlatConfigItem[]>;
16635
16751
  //#endregion
16636
16752
  //#region src/configs/react.d.ts
16637
- declare function react(options?: OptionsTypeScriptParserOptions & OptionsTypeScriptWithTypes & OptionsOverrides & OptionsFiles & OptionsHasTanStackReactQuery): Promise<FlatConfigItem[]>;
16753
+ declare function react(options?: OptionsTypeScriptParserOptions & OptionsTypeScriptWithTypes & OptionsOverrides & OptionsFiles): Promise<FlatConfigItem[]>;
16638
16754
  //#endregion
16639
16755
  //#region src/configs/regexp.d.ts
16640
16756
  declare function regexp(options?: OptionsOverrides): FlatConfigItem[];
@@ -16647,6 +16763,9 @@ declare const sortPnpmWorkspace: () => FlatConfigItem[];
16647
16763
  //#region src/configs/tailwindcss.d.ts
16648
16764
  declare function tailwindcss(options?: OptionsTailwindCSS): Promise<FlatConfigItem[]>;
16649
16765
  //#endregion
16766
+ //#region src/configs/tanstack-query.d.ts
16767
+ declare function tanstackQuery(options?: OptionsFiles & OptionsOverrides): Promise<FlatConfigItem[]>;
16768
+ //#endregion
16650
16769
  //#region src/configs/toml.d.ts
16651
16770
  declare function toml(options?: OptionsOverrides & OptionsFiles & StyleOptions): Promise<FlatConfigItem[]>;
16652
16771
  //#endregion
@@ -16664,7 +16783,7 @@ declare const hasTypeScript: boolean;
16664
16783
  declare const hasReact: boolean;
16665
16784
  declare const hasNextJs: boolean;
16666
16785
  declare const hasTailwind: boolean;
16667
- declare const hasTanStackReactQuery: boolean;
16786
+ declare const hasTanStackQuery: boolean;
16668
16787
  //#endregion
16669
16788
  //#region src/factory.d.ts
16670
16789
  declare const defaultPluginRenaming: {
@@ -16789,4 +16908,4 @@ declare function composer({
16789
16908
  }: ComposerOptions): Promise<FlatConfigItem[]>;
16790
16909
  declare function toArray<T>(value: T | T[]): T[];
16791
16910
  //#endregion
16792
- export { Awaitable, ComposerOptions, type ConfigNames, FlatConfigItem, GLOB_ALL_SRC, GLOB_CSS, GLOB_DIST, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LOCKFILE, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_NODE_MODULES, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_YAML, HTMLOptions, OptionsConfig, OptionsFiles, OptionsHasNextJs, OptionsHasRegexp, OptionsHasTanStackReactQuery, OptionsHasTypeScript, OptionsOverrides, OptionsTailwindCSS, OptionsTypeScriptParserOptions, OptionsTypeScriptWithTypes, OptionsTypescript, OptionsUnicorn, type PrettierOptions, ResolvedOptions, Rules, StyleConfig, StyleOptions, combine, command, comments, composer, deMorgan, defaultPluginRenaming, ensurePackages, getOverrides, hasNextJs, hasReact, hasTailwind, hasTanStackReactQuery, hasTypeScript, html, ignores, imports, interopDefault, javascript, jsdoc, jsonc, markdown, ncontiero, nextJs, node, parserPlain, perfectionist, prettier, promise, react, regexp, renamePluginInConfigs, renameRules, resolveSubOptions, restrictedSyntaxJs, sortPackageJson, sortPnpmWorkspace, sortTsconfig, tailwindcss, toArray, toml, typescript, unicorn, yml };
16911
+ export { Awaitable, ComposerOptions, type ConfigNames, FlatConfigItem, GLOB_ALL_SRC, GLOB_CSS, GLOB_DIST, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LOCKFILE, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_NODE_MODULES, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_YAML, HTMLOptions, OptionsConfig, OptionsE18e, OptionsFiles, OptionsHasNextJs, OptionsHasRegexp, OptionsHasTypeScript, OptionsJSX, OptionsJSXA11y, OptionsOverrides, OptionsTailwindCSS, OptionsTypeScriptParserOptions, OptionsTypeScriptWithTypes, OptionsTypescript, OptionsUnicorn, type PrettierOptions, ResolvedOptions, Rules, StyleConfig, StyleOptions, combine, command, comments, composer, deMorgan, defaultPluginRenaming, e18e, ensurePackages, getOverrides, hasNextJs, hasReact, hasTailwind, hasTanStackQuery, hasTypeScript, html, ignores, imports, interopDefault, javascript, jsdoc, jsonc, jsx, markdown, ncontiero, nextJs, node, parserPlain, perfectionist, prettier, promise, react, regexp, renamePluginInConfigs, renameRules, resolveSubOptions, restrictedSyntaxJs, sortPackageJson, sortPnpmWorkspace, sortTsconfig, tailwindcss, tanstackQuery, toArray, toml, typescript, unicorn, yml };
package/dist/index.mjs CHANGED
@@ -43,78 +43,6 @@ function deMorgan() {
43
43
  }];
44
44
  }
45
45
  //#endregion
46
- //#region src/globs.ts
47
- const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
48
- const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
49
- const GLOB_JS = "**/*.?([cm])js";
50
- const GLOB_JSX = "**/*.?([cm])jsx";
51
- const GLOB_TS = "**/*.?([cm])ts";
52
- const GLOB_TSX = "**/*.?([cm])tsx";
53
- const GLOB_STYLE = "**/*.{c,le,sc}ss";
54
- const GLOB_CSS = "**/*.css";
55
- const GLOB_POSTCSS = "**/*.{p,post}css";
56
- const GLOB_LESS = "**/*.less";
57
- const GLOB_SCSS = "**/*.scss";
58
- const GLOB_JSON = "**/*.json";
59
- const GLOB_JSON5 = "**/*.json5";
60
- const GLOB_JSONC = "**/*.jsonc";
61
- const GLOB_MARKDOWN = "**/*.md";
62
- const GLOB_MARKDOWN_IN_MARKDOWN = "**/*.md/*.md";
63
- const GLOB_YAML = "**/*.y?(a)ml";
64
- const GLOB_TOML = "**/*.toml";
65
- const GLOB_HTML = "**/*.htm?(l)";
66
- const GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
67
- const GLOB_ALL_SRC = [
68
- GLOB_SRC,
69
- GLOB_STYLE,
70
- GLOB_JSON,
71
- GLOB_JSON5,
72
- GLOB_MARKDOWN,
73
- GLOB_YAML,
74
- GLOB_HTML
75
- ];
76
- const GLOB_NODE_MODULES = "**/node_modules";
77
- const GLOB_DIST = "**/dist";
78
- const GLOB_LOCKFILE = [
79
- "**/package-lock.json",
80
- "**/yarn.lock",
81
- "**/pnpm-lock.yaml",
82
- "**/bun.lockb"
83
- ];
84
- const GLOB_EXCLUDE = [
85
- GLOB_NODE_MODULES,
86
- GLOB_DIST,
87
- ...GLOB_LOCKFILE,
88
- "**/output",
89
- "**/coverage",
90
- "**/temp",
91
- "**/.temp",
92
- "**/tmp",
93
- "**/.tmp",
94
- "**/.history",
95
- "**/fixtures",
96
- "**/.git",
97
- "**/.vitepress/cache",
98
- "**/.nuxt",
99
- "**/.next",
100
- "**/.vercel",
101
- "**/.contentlayer",
102
- "**/.changeset",
103
- "**/.idea",
104
- "**/.cache",
105
- "**/.output",
106
- "**/.vite-inspect",
107
- "**/.yarn",
108
- "**/next-env.d.ts",
109
- "**/.nitro",
110
- "**/CHANGELOG*.md",
111
- "**/*.min.*",
112
- "**/LICENSE*",
113
- "**/__snapshots__",
114
- "**/auto-import?(s).d.ts",
115
- "**/components.d.ts"
116
- ];
117
- //#endregion
118
46
  //#region src/utils.ts
119
47
  const isCwdInScope = isPackageExists("@ncontiero/eslint-config");
120
48
  const parserPlain = {
@@ -211,6 +139,101 @@ function toArray(value) {
211
139
  return Array.isArray(value) ? value : [value];
212
140
  }
213
141
  //#endregion
142
+ //#region src/configs/e18e.ts
143
+ async function e18e(options = {}) {
144
+ const { modernization = true, moduleReplacements = false, overrides = {}, performanceImprovements = true } = options;
145
+ const pluginE18e = await interopDefault(import("@e18e/eslint-plugin"));
146
+ const { configs } = pluginE18e;
147
+ return [{
148
+ name: "ncontiero/e18e/rules",
149
+ plugins: { e18e: pluginE18e },
150
+ rules: {
151
+ ...modernization ? { ...configs.modernization.rules } : {},
152
+ ...moduleReplacements ? { ...configs.moduleReplacements.rules } : {},
153
+ ...performanceImprovements ? { ...configs.performanceImprovements.rules } : {},
154
+ "e18e/prefer-array-at": "off",
155
+ "e18e/prefer-array-from-map": "off",
156
+ "e18e/prefer-array-to-reversed": "off",
157
+ "e18e/prefer-array-to-sorted": "off",
158
+ "e18e/prefer-array-to-spliced": "off",
159
+ "e18e/prefer-spread-syntax": "off",
160
+ ...overrides
161
+ }
162
+ }];
163
+ }
164
+ //#endregion
165
+ //#region src/globs.ts
166
+ const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
167
+ const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
168
+ const GLOB_JS = "**/*.?([cm])js";
169
+ const GLOB_JSX = "**/*.?([cm])jsx";
170
+ const GLOB_TS = "**/*.?([cm])ts";
171
+ const GLOB_TSX = "**/*.?([cm])tsx";
172
+ const GLOB_STYLE = "**/*.{c,le,sc}ss";
173
+ const GLOB_CSS = "**/*.css";
174
+ const GLOB_POSTCSS = "**/*.{p,post}css";
175
+ const GLOB_LESS = "**/*.less";
176
+ const GLOB_SCSS = "**/*.scss";
177
+ const GLOB_JSON = "**/*.json";
178
+ const GLOB_JSON5 = "**/*.json5";
179
+ const GLOB_JSONC = "**/*.jsonc";
180
+ const GLOB_MARKDOWN = "**/*.md";
181
+ const GLOB_MARKDOWN_IN_MARKDOWN = "**/*.md/*.md";
182
+ const GLOB_YAML = "**/*.y?(a)ml";
183
+ const GLOB_TOML = "**/*.toml";
184
+ const GLOB_HTML = "**/*.htm?(l)";
185
+ const GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
186
+ const GLOB_ALL_SRC = [
187
+ GLOB_SRC,
188
+ GLOB_STYLE,
189
+ GLOB_JSON,
190
+ GLOB_JSON5,
191
+ GLOB_MARKDOWN,
192
+ GLOB_YAML,
193
+ GLOB_HTML
194
+ ];
195
+ const GLOB_NODE_MODULES = "**/node_modules";
196
+ const GLOB_DIST = "**/dist";
197
+ const GLOB_LOCKFILE = [
198
+ "**/package-lock.json",
199
+ "**/yarn.lock",
200
+ "**/pnpm-lock.yaml",
201
+ "**/bun.lockb"
202
+ ];
203
+ const GLOB_EXCLUDE = [
204
+ GLOB_NODE_MODULES,
205
+ GLOB_DIST,
206
+ ...GLOB_LOCKFILE,
207
+ "**/output",
208
+ "**/coverage",
209
+ "**/temp",
210
+ "**/.temp",
211
+ "**/tmp",
212
+ "**/.tmp",
213
+ "**/.history",
214
+ "**/fixtures",
215
+ "**/.git",
216
+ "**/.vitepress/cache",
217
+ "**/.nuxt",
218
+ "**/.next",
219
+ "**/.vercel",
220
+ "**/.contentlayer",
221
+ "**/.changeset",
222
+ "**/.idea",
223
+ "**/.cache",
224
+ "**/.output",
225
+ "**/.vite-inspect",
226
+ "**/.yarn",
227
+ "**/next-env.d.ts",
228
+ "**/.nitro",
229
+ "**/CHANGELOG*.md",
230
+ "**/*.min.*",
231
+ "**/LICENSE*",
232
+ "**/__snapshots__",
233
+ "**/auto-import?(s).d.ts",
234
+ "**/components.d.ts"
235
+ ];
236
+ //#endregion
214
237
  //#region src/configs/html.ts
215
238
  async function html(options) {
216
239
  const { overrides = {} } = options;
@@ -242,7 +265,7 @@ async function html(options) {
242
265
  "html/no-duplicate-id": "error",
243
266
  "html/no-duplicate-in-head": "error",
244
267
  "html/no-empty-headings": "warn",
245
- "html/no-extra-spacing-attrs": ["warn", {
268
+ "html/no-extra-spacing-tags": ["warn", {
246
269
  disallowInAssignment: true,
247
270
  disallowMissing: true,
248
271
  enforceBeforeSelfClose: true
@@ -288,10 +311,12 @@ async function html(options) {
288
311
  }
289
312
  //#endregion
290
313
  //#region src/configs/ignores.ts
291
- function ignores(userIgnores = []) {
314
+ function ignores(userIgnores = [], ignoreTypeScript = false) {
315
+ const ignores = [...GLOB_EXCLUDE, ...userIgnores];
316
+ if (ignoreTypeScript) ignores.push(GLOB_TS, GLOB_TSX);
292
317
  return [{
293
- ignores: [...GLOB_EXCLUDE, ...userIgnores],
294
- name: "ncontiero/global-ignores"
318
+ ignores,
319
+ name: "ncontiero/ignores"
295
320
  }];
296
321
  }
297
322
  //#endregion
@@ -558,6 +583,81 @@ async function jsonc(options = {}) {
558
583
  }];
559
584
  }
560
585
  //#endregion
586
+ //#region src/configs/jsx.ts
587
+ async function jsx(options = {}) {
588
+ const { a11y = false } = options;
589
+ const baseConfig = {
590
+ files: [GLOB_JSX, GLOB_TSX],
591
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
592
+ name: "ncontiero/jsx/setup",
593
+ plugins: {},
594
+ rules: {}
595
+ };
596
+ if (!a11y) return [baseConfig];
597
+ const jsxA11yPlugin = await interopDefault(import("eslint-plugin-jsx-a11y"));
598
+ const a11yConfig = jsxA11yPlugin.flatConfigs.recommended;
599
+ const overrides = typeof a11y === "object" && a11y.overrides ? a11y.overrides : {};
600
+ return [{
601
+ ...baseConfig,
602
+ ...a11yConfig,
603
+ files: baseConfig.files,
604
+ languageOptions: {
605
+ ...baseConfig.languageOptions,
606
+ ...a11yConfig.languageOptions
607
+ },
608
+ name: baseConfig.name,
609
+ plugins: {
610
+ ...baseConfig.plugins,
611
+ "jsx-a11y": jsxA11yPlugin
612
+ },
613
+ rules: {
614
+ ...baseConfig.rules,
615
+ ...a11yConfig.rules || {},
616
+ "jsx-a11y/anchor-is-valid": ["warn", {
617
+ aspects: [
618
+ "noHref",
619
+ "invalidHref",
620
+ "preferButton"
621
+ ],
622
+ components: ["Link"],
623
+ specialLink: [
624
+ "to",
625
+ "hrefLeft",
626
+ "hrefRight"
627
+ ]
628
+ }],
629
+ "jsx-a11y/control-has-associated-label": ["warn", {
630
+ controlComponents: [],
631
+ depth: 5,
632
+ ignoreElements: [
633
+ "audio",
634
+ "canvas",
635
+ "embed",
636
+ "input",
637
+ "textarea",
638
+ "tr",
639
+ "video"
640
+ ],
641
+ ignoreRoles: [
642
+ "grid",
643
+ "listbox",
644
+ "menu",
645
+ "menubar",
646
+ "radiogroup",
647
+ "row",
648
+ "tablist",
649
+ "toolbar",
650
+ "tree",
651
+ "treegrid"
652
+ ],
653
+ labelAttributes: ["label"]
654
+ }],
655
+ "jsx-a11y/lang": "warn",
656
+ ...overrides
657
+ }
658
+ }];
659
+ }
660
+ //#endregion
561
661
  //#region src/configs/markdown.ts
562
662
  async function markdown(options = {}) {
563
663
  const { files = [GLOB_MARKDOWN], overrides = {} } = options;
@@ -613,9 +713,15 @@ async function markdown(options = {}) {
613
713
  async function nextJs(options = {}) {
614
714
  const { files = [GLOB_SRC], overrides = {} } = options;
615
715
  return [{
716
+ name: "ncontiero/nextjs/setup",
717
+ plugins: { nextjs: await interopDefault(import("@next/eslint-plugin-next")) }
718
+ }, {
616
719
  files,
720
+ languageOptions: {
721
+ parserOptions: { ecmaFeatures: { jsx: true } },
722
+ sourceType: "module"
723
+ },
617
724
  name: "ncontiero/nextjs/rules",
618
- plugins: { nextjs: await interopDefault(import("@next/eslint-plugin-next")) },
619
725
  rules: {
620
726
  "nextjs/google-font-display": "warn",
621
727
  "nextjs/google-font-preconnect": "warn",
@@ -639,7 +745,8 @@ async function nextJs(options = {}) {
639
745
  "nextjs/no-typos": "warn",
640
746
  "nextjs/no-unwanted-polyfillio": "warn",
641
747
  ...overrides
642
- }
748
+ },
749
+ settings: { react: { version: "detect" } }
643
750
  }];
644
751
  }
645
752
  //#endregion
@@ -808,18 +915,13 @@ const ReactRouterPackages = [
808
915
  ];
809
916
  const NextJsPackages = ["next"];
810
917
  async function react(options = {}) {
811
- const { files = [GLOB_SRC], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [`${GLOB_MARKDOWN}/**`], overrides = {}, reactQuery, tsconfigPath } = options;
812
- if (reactQuery) ensurePackages(["@tanstack/eslint-plugin-query"]);
918
+ const { files = [GLOB_SRC], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [`${GLOB_MARKDOWN}/**`], overrides = {}, tsconfigPath } = options;
813
919
  const isTypeAware = !!tsconfigPath;
814
920
  const typeAwareRules = {
815
921
  "react/no-leaked-conditional-rendering": "error",
816
922
  "react/no-unused-props": "warn"
817
923
  };
818
- const [pluginA11y, pluginReact, pluginReactRefresh] = await Promise.all([
819
- interopDefault(import("eslint-plugin-jsx-a11y")),
820
- interopDefault(import("@eslint-react/eslint-plugin")),
821
- interopDefault(import("eslint-plugin-react-refresh"))
822
- ]);
924
+ const [pluginReact, pluginReactRefresh] = await Promise.all([interopDefault(import("@eslint-react/eslint-plugin")), interopDefault(import("eslint-plugin-react-refresh"))]);
823
925
  const isAllowConstantExport = ReactRefreshAllowPackages.some((i) => isPackageExists(i));
824
926
  const isUsingReactRouter = ReactRouterPackages.some((i) => isPackageExists(i));
825
927
  const isUsingNextJs = NextJsPackages.some((i) => isPackageExists(i));
@@ -827,15 +929,10 @@ async function react(options = {}) {
827
929
  {
828
930
  name: "ncontiero/react/setup",
829
931
  plugins: {
830
- "jsx-a11y": pluginA11y,
831
932
  react: pluginReact,
832
933
  "react-refresh": pluginReactRefresh
833
934
  }
834
935
  },
835
- reactQuery ? {
836
- ...(await interopDefault(import("@tanstack/eslint-plugin-query"))).configs["flat/recommended"][0],
837
- name: "ncontiero/tanstack-query"
838
- } : {},
839
936
  {
840
937
  files,
841
938
  languageOptions: {
@@ -845,132 +942,6 @@ async function react(options = {}) {
845
942
  name: "ncontiero/react/rules",
846
943
  rules: {
847
944
  ...pluginReact.configs.recommended.rules,
848
- "jsx-a11y/alt-text": ["warn", {
849
- area: [],
850
- elements: [
851
- "img",
852
- "object",
853
- "area",
854
- "input[type=\"image\"]"
855
- ],
856
- img: [],
857
- "input[type=\"image\"]": [],
858
- object: []
859
- }],
860
- "jsx-a11y/anchor-has-content": ["warn", { components: [] }],
861
- "jsx-a11y/anchor-is-valid": ["warn", {
862
- aspects: [
863
- "noHref",
864
- "invalidHref",
865
- "preferButton"
866
- ],
867
- components: ["Link"],
868
- specialLink: ["to"]
869
- }],
870
- "jsx-a11y/aria-activedescendant-has-tabindex": ["warn"],
871
- "jsx-a11y/aria-props": ["warn"],
872
- "jsx-a11y/aria-proptypes": ["warn"],
873
- "jsx-a11y/aria-role": ["warn", { ignoreNonDOM: false }],
874
- "jsx-a11y/aria-unsupported-elements": ["warn"],
875
- "jsx-a11y/autocomplete-valid": ["off", { inputComponents: [] }],
876
- "jsx-a11y/click-events-have-key-events": ["warn"],
877
- "jsx-a11y/control-has-associated-label": ["warn", {
878
- controlComponents: [],
879
- depth: 5,
880
- ignoreElements: [
881
- "audio",
882
- "canvas",
883
- "embed",
884
- "input",
885
- "textarea",
886
- "tr",
887
- "video"
888
- ],
889
- ignoreRoles: [
890
- "grid",
891
- "listbox",
892
- "menu",
893
- "menubar",
894
- "radiogroup",
895
- "row",
896
- "tablist",
897
- "toolbar",
898
- "tree",
899
- "treegrid"
900
- ],
901
- labelAttributes: ["label"]
902
- }],
903
- "jsx-a11y/heading-has-content": ["warn", { components: [""] }],
904
- "jsx-a11y/html-has-lang": ["warn"],
905
- "jsx-a11y/iframe-has-title": ["warn"],
906
- "jsx-a11y/img-redundant-alt": ["warn"],
907
- "jsx-a11y/interactive-supports-focus": ["warn"],
908
- "jsx-a11y/label-has-associated-control": "warn",
909
- "jsx-a11y/lang": ["warn"],
910
- "jsx-a11y/media-has-caption": ["warn", {
911
- audio: [],
912
- track: [],
913
- video: []
914
- }],
915
- "jsx-a11y/mouse-events-have-key-events": ["warn"],
916
- "jsx-a11y/no-access-key": ["warn"],
917
- "jsx-a11y/no-autofocus": ["warn", { ignoreNonDOM: true }],
918
- "jsx-a11y/no-distracting-elements": ["warn", { elements: ["marquee", "blink"] }],
919
- "jsx-a11y/no-interactive-element-to-noninteractive-role": ["warn", { tr: ["none", "presentation"] }],
920
- "jsx-a11y/no-noninteractive-element-interactions": ["warn", { handlers: [
921
- "onClick",
922
- "onMouseDown",
923
- "onMouseUp",
924
- "onKeyPress",
925
- "onKeyDown",
926
- "onKeyUp"
927
- ] }],
928
- "jsx-a11y/no-noninteractive-element-to-interactive-role": ["warn", {
929
- li: [
930
- "menuitem",
931
- "option",
932
- "row",
933
- "tab",
934
- "treeitem"
935
- ],
936
- ol: [
937
- "listbox",
938
- "menu",
939
- "menubar",
940
- "radiogroup",
941
- "tablist",
942
- "tree",
943
- "treegrid"
944
- ],
945
- table: ["grid"],
946
- td: ["gridcell"],
947
- ul: [
948
- "listbox",
949
- "menu",
950
- "menubar",
951
- "radiogroup",
952
- "tablist",
953
- "tree",
954
- "treegrid"
955
- ]
956
- }],
957
- "jsx-a11y/no-noninteractive-tabindex": ["warn", {
958
- roles: ["tabpanel"],
959
- tags: []
960
- }],
961
- "jsx-a11y/no-redundant-roles": ["warn"],
962
- "jsx-a11y/no-static-element-interactions": ["off", { handlers: [
963
- "onClick",
964
- "onMouseDown",
965
- "onMouseUp",
966
- "onKeyPress",
967
- "onKeyDown",
968
- "onKeyUp"
969
- ] }],
970
- "jsx-a11y/role-has-required-aria-props": ["warn"],
971
- "jsx-a11y/role-supports-aria-props": ["warn"],
972
- "jsx-a11y/scope": ["warn"],
973
- "jsx-a11y/tabindex-no-positive": ["warn"],
974
945
  "react-refresh/only-export-components": ["warn", {
975
946
  allowConstantExport: isAllowConstantExport,
976
947
  allowExportNames: [...isUsingNextJs ? [
@@ -1011,6 +982,7 @@ async function react(options = {}) {
1011
982
  "react/no-missing-component-display-name": "warn",
1012
983
  "react/no-unstable-context-value": "warn",
1013
984
  "react/no-unstable-default-props": "warn",
985
+ "react/no-unused-state": "warn",
1014
986
  "react/refs": "warn",
1015
987
  ...overrides
1016
988
  }
@@ -1328,6 +1300,25 @@ async function tailwindcss(options = {}) {
1328
1300
  }];
1329
1301
  }
1330
1302
  //#endregion
1303
+ //#region src/configs/tanstack-query.ts
1304
+ async function tanstackQuery(options = {}) {
1305
+ const { files = [GLOB_SRC], overrides = {} } = options;
1306
+ ensurePackages(["@tanstack/eslint-plugin-query"]);
1307
+ const tanstackQueryPlugin = await interopDefault(import("@tanstack/eslint-plugin-query"));
1308
+ const config = tanstackQueryPlugin.configs.recommended;
1309
+ return [{
1310
+ name: "ncontiero/tanstack-query/setup",
1311
+ plugins: { "@tanstack/query": tanstackQueryPlugin }
1312
+ }, {
1313
+ files,
1314
+ name: "ncontiero/tanstack-query/rules",
1315
+ rules: {
1316
+ ...config.rules,
1317
+ ...overrides
1318
+ }
1319
+ }];
1320
+ }
1321
+ //#endregion
1331
1322
  //#region src/configs/toml.ts
1332
1323
  async function toml(options = {}) {
1333
1324
  const { files = [GLOB_TOML], overrides = {}, style = true } = options;
@@ -1675,7 +1666,13 @@ const hasTypeScript = isPackageExists("typescript");
1675
1666
  const hasReact = isPackageExists("react");
1676
1667
  const hasNextJs = isPackageExists("next");
1677
1668
  const hasTailwind = isPackageExists("tailwindcss");
1678
- const hasTanStackReactQuery = isPackageExists("@tanstack/react-query");
1669
+ const hasTanStackQuery = [
1670
+ "@tanstack/react-query",
1671
+ "@tanstack/preact-query",
1672
+ "@tanstack/vue-query",
1673
+ "@tanstack/solid-query",
1674
+ "@tanstack/svelte-query"
1675
+ ].some((i) => isPackageExists(i));
1679
1676
  //#endregion
1680
1677
  //#region src/factory.ts
1681
1678
  const flatConfigProps = [
@@ -1717,7 +1714,7 @@ function getStyleOptions(options) {
1717
1714
  * @returns Merged ESLint configurations based on provided options.
1718
1715
  */
1719
1716
  function ncontiero(options = {}, ...userConfigs) {
1720
- const { gitignore: enableGitignore = true, nextjs: enableNextJs = hasNextJs, react: enableReact = hasReact, reactQuery: enableTanStackReactQuery = hasTanStackReactQuery, regexp: enableRegexp = true, tailwindcss: enableTailwindCSS = hasTailwind, typescript: enableTypescript = hasTypeScript, unicorn: enableUnicorn = true } = options;
1717
+ const { e18e: enableE18e = true, gitignore: enableGitignore = true, jsx: enableJsx = true, nextjs: enableNextJs = hasNextJs, react: enableReact = hasReact, regexp: enableRegexp = true, tailwindcss: enableTailwindCSS = hasTailwind, tanstackQuery: enableTanStackQuery = hasTanStackQuery, typescript: enableTypescript = hasTypeScript, unicorn: enableUnicorn = true } = options;
1721
1718
  const prettierOptions = typeof options.prettier === "object" ? options.prettier : {};
1722
1719
  const styleOptions = getStyleOptions(prettierOptions);
1723
1720
  const configs = [];
@@ -1729,16 +1726,21 @@ function ncontiero(options = {}, ...userConfigs) {
1729
1726
  name: "ncontiero/gitignore",
1730
1727
  strict: false
1731
1728
  })]));
1732
- if (!enableTypescript) options.ignores ? options.ignores.push(GLOB_TS, GLOB_TSX) : options.ignores = [GLOB_TS, GLOB_TSX];
1733
1729
  const typescriptOptions = resolveSubOptions(options, "typescript");
1734
1730
  const tsconfigPath = "tsconfigPath" in typescriptOptions ? typescriptOptions.tsconfigPath : void 0;
1735
- configs.push(ignores(options.ignores), javascript({ overrides: getOverrides(options, "javascript") }), comments(), jsdoc(), imports({ nextJs: !!enableNextJs }), node(), promise(), command(), perfectionist(), deMorgan());
1731
+ configs.push(ignores(options.ignores, !enableTypescript), javascript({ overrides: getOverrides(options, "javascript") }), comments(), jsdoc(), imports({ nextJs: !!enableNextJs }), node(), promise(), command(), perfectionist(), deMorgan());
1732
+ if (enableE18e) configs.push(e18e(enableE18e === true ? {} : enableE18e));
1736
1733
  if (enableUnicorn) configs.push(unicorn(enableUnicorn === true ? { regexp: !!enableRegexp } : enableUnicorn));
1734
+ if (enableJsx) configs.push(jsx(enableJsx === true ? {} : enableJsx));
1737
1735
  if (enableTypescript) configs.push(typescript({
1738
1736
  ...typescriptOptions,
1739
1737
  overrides: getOverrides(options, "typescript"),
1740
1738
  tsconfigPath
1741
1739
  }));
1740
+ if (enableTanStackQuery) configs.push(tanstackQuery({
1741
+ ...resolveSubOptions(options, "tanstackQuery"),
1742
+ overrides: getOverrides(options, "tanstackQuery")
1743
+ }));
1742
1744
  if (options.jsonc ?? true) configs.push(jsonc({
1743
1745
  overrides: getOverrides(options, "jsonc"),
1744
1746
  style: styleOptions
@@ -1756,7 +1758,6 @@ function ncontiero(options = {}, ...userConfigs) {
1756
1758
  if (enableReact) configs.push(react({
1757
1759
  ...typescriptOptions,
1758
1760
  overrides: getOverrides(options, "react"),
1759
- reactQuery: !!enableTanStackReactQuery,
1760
1761
  tsconfigPath
1761
1762
  }));
1762
1763
  if (enableNextJs) configs.push(nextJs({ overrides: getOverrides(options, "nextjs") }));
@@ -1781,4 +1782,4 @@ function ncontiero(options = {}, ...userConfigs) {
1781
1782
  });
1782
1783
  }
1783
1784
  //#endregion
1784
- export { GLOB_ALL_SRC, GLOB_CSS, GLOB_DIST, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LOCKFILE, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_NODE_MODULES, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_YAML, combine, command, comments, composer, deMorgan, defaultPluginRenaming, ensurePackages, getOverrides, hasNextJs, hasReact, hasTailwind, hasTanStackReactQuery, hasTypeScript, html, ignores, imports, interopDefault, javascript, jsdoc, jsonc, markdown, ncontiero, nextJs, node, parserPlain, perfectionist, prettier, promise, react, regexp, renamePluginInConfigs, renameRules, resolveSubOptions, restrictedSyntaxJs, sortPackageJson, sortPnpmWorkspace, sortTsconfig, tailwindcss, toArray, toml, typescript, unicorn, yml };
1785
+ export { GLOB_ALL_SRC, GLOB_CSS, GLOB_DIST, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LOCKFILE, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_NODE_MODULES, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_YAML, combine, command, comments, composer, deMorgan, defaultPluginRenaming, e18e, ensurePackages, getOverrides, hasNextJs, hasReact, hasTailwind, hasTanStackQuery, hasTypeScript, html, ignores, imports, interopDefault, javascript, jsdoc, jsonc, jsx, markdown, ncontiero, nextJs, node, parserPlain, perfectionist, prettier, promise, react, regexp, renamePluginInConfigs, renameRules, resolveSubOptions, restrictedSyntaxJs, sortPackageJson, sortPnpmWorkspace, sortTsconfig, tailwindcss, tanstackQuery, toArray, toml, typescript, unicorn, yml };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ncontiero/eslint-config",
3
3
  "type": "module",
4
- "version": "8.0.0-beta.2",
4
+ "version": "8.0.0-beta.3",
5
5
  "packageManager": "pnpm@10.33.2",
6
6
  "description": "Nicolas's ESLint config.",
7
7
  "author": {
@@ -51,18 +51,19 @@
51
51
  }
52
52
  },
53
53
  "dependencies": {
54
+ "@e18e/eslint-plugin": "^0.4.1",
54
55
  "@eslint-community/eslint-plugin-eslint-comments": "^4.7.1",
55
- "@eslint-react/eslint-plugin": "5.5.1-beta.1",
56
+ "@eslint-react/eslint-plugin": "^5.7.2",
56
57
  "@eslint/markdown": "^8.0.1",
57
- "@html-eslint/eslint-plugin": "^0.59.0",
58
- "@html-eslint/parser": "^0.59.0",
58
+ "@html-eslint/eslint-plugin": "^0.60.0",
59
+ "@html-eslint/parser": "^0.60.0",
59
60
  "@next/eslint-plugin-next": "^16.2.4",
60
- "@typescript-eslint/eslint-plugin": "^8.59.0",
61
- "@typescript-eslint/parser": "^8.59.0",
61
+ "@typescript-eslint/eslint-plugin": "^8.59.2",
62
+ "@typescript-eslint/parser": "^8.59.2",
62
63
  "eslint-config-flat-gitignore": "^2.3.0",
63
64
  "eslint-merge-processors": "^2.0.0",
64
65
  "eslint-plugin-antfu": "^3.2.2",
65
- "eslint-plugin-better-tailwindcss": "4.4.1",
66
+ "eslint-plugin-better-tailwindcss": "4.5.0",
66
67
  "eslint-plugin-command": "^3.5.2",
67
68
  "eslint-plugin-de-morgan": "^2.1.1",
68
69
  "eslint-plugin-import-x": "^4.16.2",
@@ -72,14 +73,14 @@
72
73
  "eslint-plugin-n": "^17.24.0",
73
74
  "eslint-plugin-perfectionist": "^5.9.0",
74
75
  "eslint-plugin-prettier": "^5.5.5",
75
- "eslint-plugin-promise": "^7.2.1",
76
+ "eslint-plugin-promise": "^7.3.0",
76
77
  "eslint-plugin-react-refresh": "^0.5.2",
77
78
  "eslint-plugin-regexp": "^3.1.0",
78
79
  "eslint-plugin-toml": "^1.3.1",
79
80
  "eslint-plugin-unicorn": "^64.0.0",
80
81
  "eslint-plugin-unused-imports": "^4.4.1",
81
- "eslint-plugin-yml": "^3.3.1",
82
- "globals": "^17.5.0",
82
+ "eslint-plugin-yml": "^3.3.2",
83
+ "globals": "^17.6.0",
83
84
  "local-pkg": "^1.1.2",
84
85
  "prettier": "^3.8.3",
85
86
  "toml-eslint-parser": "^1.0.3",
@@ -87,18 +88,18 @@
87
88
  },
88
89
  "devDependencies": {
89
90
  "@changesets/cli": "^2.31.0",
90
- "@commitlint/cli": "^20.5.2",
91
- "@commitlint/config-conventional": "^20.5.0",
91
+ "@commitlint/cli": "^20.5.3",
92
+ "@commitlint/config-conventional": "^20.5.3",
92
93
  "@ncontiero/changelog-github": "^2.1.3",
93
94
  "@ncontiero/prettier-config": "^1.0.0",
94
- "@tanstack/eslint-plugin-query": "^5.100.5",
95
+ "@tanstack/eslint-plugin-query": "^5.100.9",
95
96
  "@types/eslint-plugin-jsx-a11y": "^6.10.1",
96
97
  "@types/node": "^25.6.0",
97
- "eslint": "^10.2.1",
98
+ "eslint": "^10.3.0",
98
99
  "eslint-typegen": "^2.3.1",
99
- "execa": "^9.6.1",
100
100
  "husky": "^9.1.7",
101
- "lint-staged": "^16.4.0",
101
+ "nano-staged": "^1.0.2",
102
+ "tinyexec": "^1.1.2",
102
103
  "tinyglobby": "^0.2.16",
103
104
  "tsdown": "^0.21.10",
104
105
  "tsx": "^4.21.0",
@@ -108,7 +109,7 @@
108
109
  "engines": {
109
110
  "node": ">=20.19.0"
110
111
  },
111
- "lint-staged": {
112
+ "nano-staged": {
112
113
  "*": "pnpm lint:fix"
113
114
  },
114
115
  "prettier": "@ncontiero/prettier-config"