@nelsonlaidev/eslint-config 3.7.1 → 4.0.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/dist/index.mjs CHANGED
@@ -6,12 +6,12 @@ import nextPlugin from "@next/eslint-plugin-next";
6
6
  import stylisticPlugin from "@stylistic/eslint-plugin";
7
7
  import typescriptPlugin from "@typescript-eslint/eslint-plugin";
8
8
  import vitestPlugin from "@vitest/eslint-plugin";
9
- import gitignorePlugin from "eslint-config-flat-gitignore";
10
9
  import tailwindcssPlugin from "eslint-plugin-better-tailwindcss";
11
10
  import commandPlugin from "eslint-plugin-command/config";
12
11
  import deMorganPlugin from "eslint-plugin-de-morgan";
13
- import importXPlugin from "eslint-plugin-import-x";
12
+ import { importX as importXPlugin } from "eslint-plugin-import-x";
14
13
  import importZodPlugin from "eslint-plugin-import-zod";
14
+ import jsdocPlugin from "eslint-plugin-jsdoc";
15
15
  import jsxA11yPlugin from "eslint-plugin-jsx-a11y";
16
16
  import nodePlugin from "eslint-plugin-n";
17
17
  import playwrightPlugin from "eslint-plugin-playwright";
@@ -22,29 +22,25 @@ import importSortPlugin from "eslint-plugin-simple-import-sort";
22
22
  import sonarjsPlugin from "eslint-plugin-sonarjs";
23
23
  import unicornPlugin from "eslint-plugin-unicorn";
24
24
  import unusedImportsPlugin from "eslint-plugin-unused-imports";
25
+ import gitignoreConfig from "eslint-config-flat-gitignore";
25
26
  import eslint from "@eslint/js";
26
27
  import globals from "globals";
27
28
  import { rules } from "eslint-config-prettier";
28
29
  import { getDefaultSelectors } from "eslint-plugin-better-tailwindcss/defaults";
29
- import parser from "@typescript-eslint/parser";
30
-
30
+ import { MatcherType, SelectorKind } from "eslint-plugin-better-tailwindcss/types";
31
+ import * as parserBase from "@typescript-eslint/parser";
31
32
  //#region src/configs/command.ts
32
33
  const command = () => [{
33
34
  ...commandPlugin(),
34
35
  name: "nelsonlaidev/command/rules"
35
36
  }];
36
-
37
37
  //#endregion
38
38
  //#region src/configs/comments.ts
39
39
  const comments = () => [{
40
40
  name: "nelsonlaidev/eslint-comments/rules",
41
41
  plugins: { "@eslint-community/eslint-comments": commentsPlugin },
42
- rules: {
43
- ...commentsPlugin.configs.recommended.rules,
44
- "@eslint-community/eslint-comments/no-unused-disable": "error"
45
- }
42
+ rules: { ...commentsPlugin.configs.recommended.rules }
46
43
  }];
47
-
48
44
  //#endregion
49
45
  //#region src/configs/de-morgan.ts
50
46
  const deMorgan = () => [{
@@ -52,18 +48,15 @@ const deMorgan = () => [{
52
48
  plugins: { "de-morgan": deMorganPlugin },
53
49
  rules: { ...deMorganPlugin.configs.recommended.rules }
54
50
  }];
55
-
56
51
  //#endregion
57
52
  //#region src/configs/gitignore.ts
58
- const gitignore = () => [gitignorePlugin({ name: "nelsonlaidev/gitignore" })];
59
-
53
+ const gitignore = () => [gitignoreConfig({ name: "nelsonlaidev/gitignore" })];
60
54
  //#endregion
61
55
  //#region src/configs/ignores.ts
62
56
  const ignores = (userIgnores = []) => [{
63
57
  name: "nelsonlaidev/ignores",
64
58
  ignores: ["**/routeTree.gen.ts", ...userIgnores]
65
59
  }];
66
-
67
60
  //#endregion
68
61
  //#region src/configs/import-sort.ts
69
62
  const importSort = () => [{
@@ -71,29 +64,34 @@ const importSort = () => [{
71
64
  plugins: { "import-sort": importSortPlugin },
72
65
  rules: {
73
66
  "import-sort/imports": ["error", { groups: [
67
+ ["^\\u0000"],
74
68
  [
75
- String.raw`^.*\u0000$`,
76
- String.raw`^node:.*\u0000$`,
77
- String.raw`^@?\w.*\u0000$`,
78
- String.raw`^\.\..*\u0000$`,
79
- String.raw`^\..*\u0000$`
69
+ "^node:.*\\u0000$",
70
+ "^@?\\w.*\\u0000$",
71
+ "^(@/|~/|[^.]).*\\u0000$",
72
+ "^\\.\\..*\\u0000$",
73
+ "^\\..*\\u0000$"
80
74
  ],
81
- [String.raw`^\u0000`],
82
75
  ["^node:"],
83
- [String.raw`^@?\w`],
84
- ["^[^.]"],
85
- [String.raw`^\.\.`],
86
- [String.raw`^\.`]
76
+ ["^@?\\w"],
77
+ [
78
+ "^@/",
79
+ "^~/",
80
+ "^[^.]"
81
+ ],
82
+ ["^\\.\\.", "^\\."]
87
83
  ] }],
88
84
  "import-sort/exports": "error"
89
85
  }
90
86
  }];
91
-
92
87
  //#endregion
93
88
  //#region src/configs/import-x.ts
94
- const importX = (options = {}) => [{
95
- name: "nelsonlaidev/import-x/rules",
89
+ const importX = () => [{
90
+ name: "nelsonlaidev/import-x/setup",
96
91
  plugins: { "import-x": importXPlugin },
92
+ settings: { ...importXPlugin.configs.typescript.settings }
93
+ }, {
94
+ name: "nelsonlaidev/import-x/rules",
97
95
  rules: {
98
96
  ...importXPlugin.configs.recommended.rules,
99
97
  ...importXPlugin.configs.typescript.rules,
@@ -105,35 +103,21 @@ const importX = (options = {}) => [{
105
103
  "import-x/no-commonjs": "error",
106
104
  "import-x/no-mutable-exports": "error",
107
105
  "import-x/no-named-default": "error",
108
- "import-x/no-namespace": ["error", { ignore: ["zod", ...options.noNamespace?.ignore ?? []] }],
109
106
  "import-x/no-relative-packages": "error",
110
107
  "import-x/no-self-import": "error",
111
108
  "import-x/no-extraneous-dependencies": "error",
112
109
  "import-x/no-absolute-path": "error",
113
110
  "import-x/no-webpack-loader-syntax": "error",
114
111
  "import-x/no-dynamic-require": "error",
115
- "import-x/no-unassigned-import": ["error", { allow: [
116
- "**/*.css",
117
- "**/*.scss",
118
- "**/*.less",
119
- "server-only",
120
- "client-only",
121
- "@total-typescript/ts-reset",
122
- "@testing-library/jest-dom/**",
123
- "@testing-library/jest-dom",
124
- "msw/{node,browser}",
125
- "dotenv/config",
126
- ...options.noUnassignedImport?.allow ?? []
127
- ] }],
128
112
  "import-x/no-useless-path-segments": "error",
129
113
  "import-x/no-import-module-exports": "error",
130
114
  "import-x/no-empty-named-blocks": "error",
131
115
  "import-x/no-deprecated": "error",
132
- "import-x/no-named-as-default": "off"
133
- },
134
- settings: { ...importXPlugin.configs.typescript.settings }
116
+ "import-x/no-duplicates": "error",
117
+ "import-x/no-named-as-default": "off",
118
+ "import-x/no-named-as-default-member": "off"
119
+ }
135
120
  }];
136
-
137
121
  //#endregion
138
122
  //#region src/configs/javascript.ts
139
123
  const javascript = () => [{
@@ -144,9 +128,7 @@ const javascript = () => [{
144
128
  ...globals.browser,
145
129
  ...globals.es2021,
146
130
  ...globals.node,
147
- document: "readonly",
148
- navigator: "readonly",
149
- window: "readonly"
131
+ document: "readonly"
150
132
  },
151
133
  parserOptions: {
152
134
  ecmaFeatures: { jsx: true },
@@ -161,95 +143,52 @@ const javascript = () => [{
161
143
  }
162
144
  }, {
163
145
  name: "nelsonlaidev/javascript/rules",
164
- plugins: { "unused-imports": unusedImportsPlugin },
165
146
  rules: {
166
147
  ...eslint.configs.recommended.rules,
167
- "accessor-pairs": "error",
168
148
  "array-callback-return": "error",
169
- "arrow-body-style": "error",
170
- "block-scoped-var": "error",
171
- complexity: "error",
172
- "default-case": "error",
173
- "default-case-last": "error",
174
149
  eqeqeq: "error",
175
- "func-names": "error",
176
- "max-classes-per-file": "error",
177
- "max-depth": "error",
178
- "max-nested-callbacks": "error",
179
- "new-cap": ["error", { capIsNew: false }],
180
150
  "no-alert": "error",
181
151
  "no-await-in-loop": "error",
182
- "no-bitwise": "error",
183
- "no-caller": "error",
184
- "no-console": ["error", { allow: ["warn", "error"] }],
185
- "no-constructor-return": "error",
186
- "no-else-return": "error",
187
- "no-eq-null": "error",
188
152
  "no-eval": "error",
189
- "no-extend-native": "error",
190
153
  "no-extra-bind": "error",
191
- "no-extra-label": "error",
192
- "no-implicit-coercion": "error",
193
154
  "no-label-var": "error",
194
155
  "no-labels": "error",
195
156
  "no-lone-blocks": "error",
196
- "no-lonely-if": "error",
197
- "no-multi-assign": "error",
198
- "no-multi-str": "error",
199
157
  "no-new": "error",
200
158
  "no-new-func": "error",
201
- "no-new-wrappers": "error",
202
- "no-object-constructor": "error",
203
159
  "no-param-reassign": "error",
204
160
  "no-plusplus": ["error", { allowForLoopAfterthoughts: true }],
205
161
  "no-promise-executor-return": "error",
206
- "no-restricted-globals": "error",
207
162
  "no-return-assign": "error",
208
163
  "no-script-url": "error",
209
164
  "no-self-compare": "error",
210
165
  "no-sequences": "error",
211
166
  "no-template-curly-in-string": "error",
212
- "no-unassigned-vars": "error",
213
167
  "no-unneeded-ternary": "error",
214
168
  "no-useless-call": "error",
215
169
  "no-useless-computed-key": "error",
216
170
  "no-useless-concat": "error",
217
171
  "no-useless-rename": "error",
218
172
  "no-useless-return": "error",
173
+ "no-var": "error",
219
174
  "no-void": ["error", { allowAsStatement: true }],
220
- "no-warning-comments": "error",
221
- "operator-assignment": "error",
222
- "prefer-destructuring": ["error", {
223
- VariableDeclarator: {
224
- array: false,
225
- object: true
226
- },
227
- AssignmentExpression: {
228
- array: false,
229
- object: false
230
- }
231
- }],
232
- "prefer-exponentiation-operator": "error",
233
- "prefer-numeric-literals": "error",
234
175
  "prefer-object-has-own": "error",
235
176
  "prefer-object-spread": "error",
236
177
  "prefer-template": "error",
237
178
  "preserve-caught-error": "error",
238
- radix: "error",
239
- "symbol-description": "error",
240
- "unicode-bom": "error",
241
- yoda: "error",
242
- "no-unused-vars": "off",
243
- "unused-imports/no-unused-imports": "error",
244
- "unused-imports/no-unused-vars": ["error", {
245
- vars: "all",
246
- varsIgnorePattern: "^_",
247
- args: "after-used",
248
- argsIgnorePattern: "^_"
249
- }]
179
+ "symbol-description": "error"
180
+ }
181
+ }];
182
+ //#endregion
183
+ //#region src/configs/jsdoc.ts
184
+ const jsdoc = () => [{
185
+ name: "nelsonlaidev/jsdoc/rules",
186
+ plugins: { jsdoc: jsdocPlugin },
187
+ rules: {
188
+ "jsdoc/check-tag-names": "error",
189
+ "jsdoc/empty-tags": "error"
250
190
  }
251
191
  }];
252
-
253
192
  //#endregion
254
193
  //#region src/globs.ts
255
194
  const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
@@ -258,19 +197,29 @@ const GLOB_JS = "**/*.?([cm])js";
258
197
  const GLOB_JSX = "**/*.?([cm])jsx";
259
198
  const GLOB_TS = "**/*.?([cm])ts";
260
199
  const GLOB_TSX = "**/*.?([cm])tsx";
261
-
262
200
  //#endregion
263
- //#region src/configs/jsx.ts
264
- const jsx = (options) => [{
265
- name: "nelsonlaidev/jsx/setup",
201
+ //#region src/configs/jsx-a11y.ts
202
+ const jsxA11y = (options = {}) => [{
203
+ name: "nelsonlaidev/jsx-a11y/setup",
266
204
  files: [GLOB_JSX, GLOB_TSX],
267
- languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } }
205
+ plugins: { "jsx-a11y": jsxA11yPlugin },
206
+ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
207
+ settings: { "jsx-a11y": {
208
+ ...options.a11y,
209
+ components: {
210
+ Button: "button",
211
+ Image: "img",
212
+ Input: "input",
213
+ Textarea: "textarea",
214
+ Link: "a",
215
+ ...options.a11y?.components
216
+ }
217
+ } }
268
218
  }, {
269
- name: "nelsonlaidev/jsx/rules",
219
+ name: "nelsonlaidev/jsx-a11y/rules",
270
220
  files: [GLOB_JSX, GLOB_TSX],
271
- plugins: { "jsx-a11y": jsxA11yPlugin },
272
221
  rules: {
273
- ...jsxA11yPlugin.flatConfigs.recommended.rules,
222
+ ...jsxA11yPlugin.configs.recommended.rules,
274
223
  "jsx-a11y/lang": "error",
275
224
  "jsx-a11y/no-aria-hidden-on-focusable": "error",
276
225
  "jsx-a11y/anchor-is-valid": ["error", {
@@ -282,20 +231,8 @@ const jsx = (options) => [{
282
231
  "preferButton"
283
232
  ]
284
233
  }]
285
- },
286
- settings: { "jsx-a11y": {
287
- ...options.a11y,
288
- components: {
289
- Button: "button",
290
- Image: "img",
291
- Input: "input",
292
- Textarea: "textarea",
293
- Link: "a",
294
- ...options.a11y?.components
295
- }
296
- } }
234
+ }
297
235
  }];
298
-
299
236
  //#endregion
300
237
  //#region src/configs/nelsonlaidev.ts
301
238
  const nelsonlaidev = () => [{
@@ -303,14 +240,12 @@ const nelsonlaidev = () => [{
303
240
  plugins: { "@nelsonlaidev": nelsonlaidevPlugin },
304
241
  rules: {
305
242
  "@nelsonlaidev/lucide-icon-suffix": "error",
306
- "@nelsonlaidev/lucide-prefer-loader-icon": "error",
307
- "@nelsonlaidev/lucide-prefer-trash2-icon": "error",
243
+ "@nelsonlaidev/lucide-restrict-import": "error",
308
244
  "@nelsonlaidev/shadcn-cn-wrap-variants": "error",
309
245
  "@nelsonlaidev/shadcn-cva-variants-suffix": "error",
310
246
  "@nelsonlaidev/shadcn-prefer-spinner": "error"
311
247
  }
312
248
  }];
313
-
314
249
  //#endregion
315
250
  //#region src/configs/nextjs.ts
316
251
  const nextjs = () => [{
@@ -318,208 +253,90 @@ const nextjs = () => [{
318
253
  plugins: { "@next/next": nextPlugin },
319
254
  rules: { ...nextPlugin.configs["core-web-vitals"].rules }
320
255
  }];
321
-
322
256
  //#endregion
323
257
  //#region src/configs/node.ts
324
258
  const node = () => [{
325
259
  name: "nelsonlaidev/node/rules",
326
260
  plugins: { n: nodePlugin },
327
261
  rules: {
328
- "n/handle-callback-err": ["error", "^(err|error)$"],
329
262
  "n/no-deprecated-api": "error",
330
263
  "n/no-exports-assign": "error",
331
- "n/no-new-require": "error",
332
264
  "n/no-path-concat": "error",
265
+ "n/prefer-node-protocol": "error",
333
266
  "n/prefer-promises/fs": "error",
334
- "n/process-exit-as-throw": "error"
267
+ "n/prefer-promises/dns": "error"
335
268
  }
336
269
  }];
337
-
338
- //#endregion
339
- //#region src/defaults.ts
340
- const DEFAULT_ROOT_FONT_SIZE = 16;
341
- const CANONICAL_CLASSES_DEFAULT_OPTIONS = {
342
- rootFontSize: DEFAULT_ROOT_FONT_SIZE,
343
- collapse: true,
344
- logical: true
345
- };
346
- const CONSISTENT_CLASS_ORDER_DEFAULT_OPTIONS = {
347
- order: "official",
348
- detectComponentClasses: false,
349
- componentClassOrder: "preserve",
350
- componentClassPosition: "start",
351
- unknownClassOrder: "preserve",
352
- unknownClassPosition: "start"
353
- };
354
- const NO_RESTRICTED_CLASSES_DEFAULT_OPTIONS = { restrict: [] };
355
- const NO_UNKNOWN_CLASSES_DEFAULT_OPTIONS = {
356
- ignore: [],
357
- detectComponentClasses: false
358
- };
359
- const NO_UNNECESSARY_WHITESPACE_DEFAULT_OPTIONS = { allowMultiline: true };
360
- const EXPECT_EXPECT_DEFAULT_OPTIONS = {
361
- assertFunctionNames: [],
362
- assertFunctionPatterns: []
363
- };
364
- const MAX_NESTED_DESCRIBE_DEFAULT_OPTIONS = { max: 5 };
365
- const MISSING_PLAYWRIGHT_AWAIT_DEFAULT_OPTIONS = { customMatchers: [] };
366
- const NO_SKIPPED_TEST_DEFAULT_OPTIONS = { allowConditional: false };
367
- const VALID_EXPECT_DEFAULT_OPTIONS = {
368
- minArgs: 1,
369
- maxArgs: 2
370
- };
371
- const VALID_TITLE_DEFAULT_OPTIONS = {
372
- ignoreSpaces: false,
373
- ignoreTypeOfStepName: true,
374
- ignoreTypeOfTestName: false,
375
- ignoreTypeOfDescribeName: false,
376
- disallowedWords: [],
377
- mustNotMatch: {},
378
- mustMatch: {}
379
- };
380
- const VALID_TEST_TAGS_DEFAULT_OPTIONS = {
381
- allowedTags: [],
382
- disallowedTags: []
383
- };
384
-
385
270
  //#endregion
386
271
  //#region src/configs/playwright.ts
387
272
  const playwright = (options) => [{
388
273
  name: "nelsonlaidev/playwright/setup",
274
+ files: options.files,
275
+ plugins: { playwright: playwrightPlugin },
389
276
  languageOptions: { globals: globals["shared-node-browser"] }
390
277
  }, {
391
278
  name: "nelsonlaidev/playwright/rules",
392
279
  files: options.files,
393
- plugins: { playwright: playwrightPlugin },
394
- settings: { playwright: {
395
- globalAliases: options.globalAliases,
396
- messages: options.messages
397
- } },
398
280
  rules: {
399
281
  ...playwrightPlugin.configs.recommended.rules,
400
282
  "playwright/expect-expect": ["error", {
401
- ...EXPECT_EXPECT_DEFAULT_OPTIONS,
402
- ...options.expectExpect,
403
- assertFunctionNames: [...options.expectExpect?.assertFunctionNames ?? []],
404
- assertFunctionPatterns: [...options.expectExpect?.assertFunctionPatterns ?? []]
405
- }],
406
- "playwright/max-nested-describe": ["error", {
407
- ...MAX_NESTED_DESCRIBE_DEFAULT_OPTIONS,
408
- ...options.maxNestedDescribe
409
- }],
410
- "playwright/missing-playwright-await": ["error", {
411
- ...MISSING_PLAYWRIGHT_AWAIT_DEFAULT_OPTIONS,
412
- ...options.missingPlaywrightAwait,
413
- customMatchers: [...options.missingPlaywrightAwait?.customMatchers ?? []]
414
- }],
415
- "playwright/no-skipped-test": ["error", {
416
- ...NO_SKIPPED_TEST_DEFAULT_OPTIONS,
417
- ...options.noSkippedTest
418
- }],
419
- "playwright/valid-expect": ["error", {
420
- ...VALID_EXPECT_DEFAULT_OPTIONS,
421
- ...options.validExpect
422
- }],
423
- "playwright/valid-title": ["error", {
424
- ...VALID_TITLE_DEFAULT_OPTIONS,
425
- ...options.validTitle,
426
- disallowedWords: [...options.validTitle?.disallowedWords ?? []]
427
- }],
428
- "playwright/valid-test-tags": ["error", {
429
- ...VALID_TEST_TAGS_DEFAULT_OPTIONS,
430
- ...options.validTestTags,
431
- allowedTags: [...options.validTestTags?.allowedTags ?? []],
432
- disallowedTags: [...options.validTestTags?.disallowedTags ?? []]
433
- }],
434
- "playwright/no-commented-out-tests": "error",
435
- "playwright/no-duplicate-hooks": "error",
436
- "playwright/no-get-by-title": "error",
437
- "playwright/no-nth-methods": "error",
438
- "playwright/no-raw-locators": "error",
439
- "playwright/no-restricted-locators": "error",
440
- "playwright/no-restricted-matchers": "error",
441
- "playwright/no-slowed-test": "error",
442
- "playwright/prefer-comparison-matcher": "error",
443
- "playwright/prefer-equality-matcher": "error",
444
- "playwright/prefer-hooks-in-order": "error",
445
- "playwright/prefer-hooks-on-top": "error",
446
- "playwright/prefer-locator": "error",
447
- "playwright/prefer-lowercase-title": "error",
448
- "playwright/prefer-native-locators": "error",
449
- "playwright/prefer-strict-equal": "error",
450
- "playwright/prefer-to-be": "error",
451
- "playwright/prefer-to-contain": "error",
452
- "playwright/prefer-to-have-count": "error",
453
- "playwright/prefer-to-have-length": "error",
454
- "playwright/require-hook": "error",
455
- "playwright/require-to-throw-message": "error",
456
- "playwright/require-top-level-describe": "error"
283
+ assertFunctionNames: options.assertFunctionNames ?? [],
284
+ assertFunctionPatterns: options.assertFunctionPatterns ?? []
285
+ }]
457
286
  }
458
287
  }];
459
-
460
288
  //#endregion
461
289
  //#region src/configs/prettier.ts
462
290
  const prettier = () => [{
463
291
  name: "nelsonlaidev/prettier/rules",
464
292
  rules
465
293
  }];
466
-
467
294
  //#endregion
468
295
  //#region src/configs/promise.ts
469
296
  const promise = () => [{
470
297
  name: "nelsonlaidev/promise/rules",
471
298
  plugins: { promise: promisePlugin },
472
299
  rules: {
473
- "promise/always-return": "error",
474
- "promise/avoid-new": "error",
475
- "promise/catch-or-return": "error",
476
- "promise/no-callback-in-promise": "error",
300
+ ...promisePlugin.configs.recommended.rules,
477
301
  "promise/no-multiple-resolved": "error",
478
- "promise/no-nesting": "error",
479
- "promise/no-new-statics": "error",
480
- "promise/no-promise-in-callback": "error",
481
- "promise/no-return-in-finally": "error",
482
- "promise/no-return-wrap": "error",
483
- "promise/param-names": "error",
484
302
  "promise/prefer-await-to-callbacks": "error",
485
303
  "promise/prefer-await-to-then": "error",
486
304
  "promise/prefer-catch": "error",
487
- "promise/spec-only": "error",
488
- "promise/valid-params": "error"
305
+ "promise/spec-only": "error"
489
306
  }
490
307
  }];
491
-
492
308
  //#endregion
493
309
  //#region src/configs/react.ts
494
- const react = () => [{
495
- name: "nelsonlaidev/react/rules",
496
- files: [GLOB_SRC],
497
- plugins: {
498
- ...reactPlugin.configs.all.plugins,
499
- "react-hooks": reactHooksPlugin
310
+ const react = () => [
311
+ {
312
+ name: "nelsonlaidev/react/setup",
313
+ files: [GLOB_SRC],
314
+ plugins: {
315
+ ...reactPlugin.configs.all.plugins,
316
+ "react-hooks": reactHooksPlugin
317
+ },
318
+ settings: { ...reactPlugin.configs.all.settings }
500
319
  },
501
- rules: {
502
- ...reactPlugin.configs.all.rules,
503
- ...reactHooksPlugin.configs["recommended-latest"].rules,
504
- "@eslint-react/jsx-dollar": "error",
505
- "@eslint-react/naming-convention/filename": ["error", {
506
- rule: "kebab-case",
507
- excepts: [
508
- "index",
509
- String.raw`/^_/`,
510
- String.raw`/^\$/`,
511
- String.raw`/^[0-9]+$/`,
512
- String.raw`/^\[[^\]]+\]$/`
513
- ]
514
- }],
515
- "@eslint-react/no-array-index-key": "off",
516
- "@eslint-react/naming-convention/use-state": "off",
517
- "@eslint-react/hooks-extra/no-direct-set-state-in-use-effect": "off",
518
- "react-hooks/set-state-in-effect": "off",
519
- "react-hooks/static-components": "off"
320
+ {
321
+ name: "nelsonlaidev/react/rules",
322
+ files: [GLOB_SRC],
323
+ rules: {
324
+ ...reactHooksPlugin.configs["recommended-latest"].rules,
325
+ ...reactPlugin.configs.all.rules,
326
+ ...reactPlugin.configs["disable-conflict-eslint-plugin-react-hooks"].rules,
327
+ "@eslint-react/immutability": "error",
328
+ "@eslint-react/refs": "error"
329
+ }
330
+ },
331
+ {
332
+ name: "nelsonlaidev/react/typescript-rules",
333
+ files: [GLOB_TS, GLOB_TSX],
334
+ rules: {
335
+ "@eslint-react/no-leaked-conditional-rendering": "error",
336
+ "@eslint-react/no-unused-props": "error"
337
+ }
520
338
  }
521
- }];
522
-
339
+ ];
523
340
  //#endregion
524
341
  //#region src/configs/regexp.ts
525
342
  const regexp = () => [{
@@ -527,7 +344,6 @@ const regexp = () => [{
527
344
  plugins: { regexp: regexpPlugin },
528
345
  rules: { ...regexpPlugin.configs.recommended.rules }
529
346
  }];
530
-
531
347
  //#endregion
532
348
  //#region src/configs/sonarjs.ts
533
349
  const sonarjs = () => [{
@@ -540,10 +356,12 @@ const sonarjs = () => [{
540
356
  "sonarjs/arguments-order": "off",
541
357
  "sonarjs/pseudo-random": "off",
542
358
  "sonarjs/function-return-type": "off",
543
- "sonarjs/prefer-read-only-props": "off"
359
+ "sonarjs/prefer-read-only-props": "off",
360
+ "sonarjs/argument-type": "off",
361
+ "sonarjs/cognitive-complexity": "off",
362
+ "sonarjs/jsx-no-leaked-render": "off"
544
363
  }
545
364
  }];
546
-
547
365
  //#endregion
548
366
  //#region src/configs/stylistic.ts
549
367
  const stylistic = () => [{
@@ -551,59 +369,70 @@ const stylistic = () => [{
551
369
  plugins: { "@stylistic": stylisticPlugin },
552
370
  rules: { "@stylistic/multiline-comment-style": ["error", "separate-lines"] }
553
371
  }];
554
-
555
372
  //#endregion
556
373
  //#region src/configs/tailwindcss.ts
374
+ const createSelectors = (names, kind) => names.map((name) => ({
375
+ name,
376
+ kind,
377
+ match: [{ type: MatcherType.String }, { type: MatcherType.ObjectValue }]
378
+ }));
557
379
  const tailwindcss = (options) => {
558
- const shouldEnableShorthandRule = !options.canonicalClasses || options.canonicalClasses.logical === false;
380
+ const disableShorthand = options.canonical?.logical ?? true;
559
381
  return [{
560
- name: "nelsonlaidev/tailwindcss/rules",
382
+ name: "nelsonlaidev/tailwindcss/setup",
561
383
  plugins: { "better-tailwindcss": tailwindcssPlugin },
384
+ settings: { "better-tailwindcss": {
385
+ entryPoint: options.entryPoint,
386
+ tailwindConfig: options.tailwindConfig,
387
+ tsconfig: options.tsconfig,
388
+ detectComponentClasses: options.detectComponentClasses ?? false,
389
+ rootFontSize: options.rootFontSize ?? 16,
390
+ messageStyle: options.messageStyle,
391
+ selectors: [
392
+ ...getDefaultSelectors(),
393
+ ...createSelectors(["classNames", ".+ClassNames"], SelectorKind.Attribute),
394
+ ...createSelectors([".+ClassName", ".+ClassNames"], SelectorKind.Variable),
395
+ ...options.selectors ?? []
396
+ ]
397
+ } }
398
+ }, {
399
+ name: "nelsonlaidev/tailwindcss/rules",
400
+ files: [GLOB_SRC],
562
401
  rules: {
563
402
  "better-tailwindcss/enforce-canonical-classes": ["error", {
564
- ...CANONICAL_CLASSES_DEFAULT_OPTIONS,
565
- ...options.canonicalClasses
403
+ collapse: options.canonical?.collapse ?? true,
404
+ logical: options.canonical?.logical ?? true
566
405
  }],
567
406
  "better-tailwindcss/enforce-consistent-important-position": "off",
568
407
  "better-tailwindcss/enforce-consistent-variable-syntax": "off",
569
- "better-tailwindcss/enforce-shorthand-classes": shouldEnableShorthandRule ? "error" : "off",
408
+ "better-tailwindcss/enforce-shorthand-classes": disableShorthand ? "off" : "error",
570
409
  "better-tailwindcss/enforce-consistent-class-order": ["error", {
571
- ...CONSISTENT_CLASS_ORDER_DEFAULT_OPTIONS,
572
- ...options.consistentClassOrder
410
+ order: options.classOrder?.order ?? "official",
411
+ componentClassOrder: options.classOrder?.componentOrder ?? "preserve",
412
+ componentClassPosition: options.classOrder?.componentPosition ?? "start",
413
+ unknownClassOrder: options.classOrder?.unknownOrder ?? "preserve",
414
+ unknownClassPosition: options.classOrder?.unknownPosition ?? "start"
573
415
  }],
574
416
  "better-tailwindcss/no-conflicting-classes": "error",
575
417
  "better-tailwindcss/no-deprecated-classes": "error",
576
418
  "better-tailwindcss/no-duplicate-classes": "error",
577
- "better-tailwindcss/no-restricted-classes": ["error", {
578
- ...NO_RESTRICTED_CLASSES_DEFAULT_OPTIONS,
579
- ...options.noRestrictedClasses,
580
- restrict: [...options.noRestrictedClasses?.restrict ?? []]
581
- }],
582
- "better-tailwindcss/no-unknown-classes": ["error", {
583
- ...NO_UNKNOWN_CLASSES_DEFAULT_OPTIONS,
584
- ...options.noUnknownClasses,
585
- ignore: [...options.noUnknownClasses?.ignore ?? []]
586
- }],
587
- "better-tailwindcss/no-unnecessary-whitespace": ["error", {
588
- ...NO_UNNECESSARY_WHITESPACE_DEFAULT_OPTIONS,
589
- ...options.noUnnecessaryWhitespace
590
- }]
591
- },
592
- settings: { "better-tailwindcss": {
593
- ...options,
594
- rootFontSize: options.rootFontSize ?? DEFAULT_ROOT_FONT_SIZE,
595
- selectors: [...getDefaultSelectors(), ...options.selectors ?? []]
596
- } }
419
+ "better-tailwindcss/no-restricted-classes": ["error", { restrict: options.restrict ?? [] }],
420
+ "better-tailwindcss/no-unknown-classes": ["error", { ignore: options.ignore ?? [] }],
421
+ "better-tailwindcss/no-unnecessary-whitespace": ["error", { allowMultiline: options.whitespace?.allowMultiline ?? true }]
422
+ }
597
423
  }];
598
424
  };
599
-
600
425
  //#endregion
601
426
  //#region src/configs/typescript.ts
602
427
  const typescript = () => [
603
428
  {
604
429
  name: "nelsonlaidev/typescript/setup",
430
+ files: [GLOB_TS, GLOB_TSX],
605
431
  languageOptions: {
606
- parser,
432
+ parser: {
433
+ meta: parserBase.meta,
434
+ parseForESLint: parserBase.parseForESLint
435
+ },
607
436
  parserOptions: {
608
437
  projectService: true,
609
438
  tsconfigRootDir: process.cwd()
@@ -649,8 +478,7 @@ const typescript = () => [
649
478
  package: "@tanstack/router-core",
650
479
  name: "Redirect"
651
480
  }] }],
652
- "@typescript-eslint/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }],
653
- "@typescript-eslint/no-unused-vars": "off"
481
+ "@typescript-eslint/no-empty-object-type": ["error", { allowInterfaces: "with-single-extends" }]
654
482
  }
655
483
  },
656
484
  {
@@ -662,7 +490,6 @@ const typescript = () => [
662
490
  }
663
491
  }
664
492
  ];
665
-
666
493
  //#endregion
667
494
  //#region src/configs/unicorn.ts
668
495
  const unicorn = () => [{
@@ -677,24 +504,41 @@ const unicorn = () => [{
677
504
  "unicorn/prefer-string-raw": "off"
678
505
  }
679
506
  }];
680
-
507
+ //#endregion
508
+ //#region src/configs/unused-imports.ts
509
+ const unusedImports = () => [{
510
+ name: "nelsonlaidev/unused-imports/rules",
511
+ plugins: { "unused-imports": unusedImportsPlugin },
512
+ rules: {
513
+ "no-unused-vars": "off",
514
+ "@typescript-eslint/no-unused-vars": "off",
515
+ "unused-imports/no-unused-imports": "error",
516
+ "unused-imports/no-unused-vars": ["error", {
517
+ vars: "all",
518
+ varsIgnorePattern: "^_",
519
+ args: "after-used",
520
+ argsIgnorePattern: "^_"
521
+ }]
522
+ }
523
+ }];
681
524
  //#endregion
682
525
  //#region src/configs/vitest.ts
683
526
  const vitest = (options) => [{
684
- name: "nelsonlaidev/vitest/rules",
527
+ name: "nelsonlaidev/vitest/setup",
685
528
  files: options.files,
686
529
  plugins: { vitest: vitestPlugin },
530
+ settings: { vitest: { typecheck: true } },
531
+ languageOptions: { globals: { ...vitestPlugin.environments.env.globals } }
532
+ }, {
533
+ name: "nelsonlaidev/vitest/rules",
534
+ files: options.files,
687
535
  rules: {
688
- ...vitestPlugin.configs.all.rules,
689
- "vitest/max-expects": "off",
536
+ ...vitestPlugin.configs.recommended.rules,
690
537
  "vitest/consistent-test-it": ["error", { fn: "test" }],
691
538
  "vitest/prefer-mock-return-shorthand": "error",
692
539
  "vitest/warn-todo": "error"
693
- },
694
- settings: { vitest: { typecheck: true } },
695
- languageOptions: { globals: { ...vitestPlugin.environments.env.globals } }
540
+ }
696
541
  }];
697
-
698
542
  //#endregion
699
543
  //#region src/configs/zod.ts
700
544
  const zod = () => [{
@@ -702,7 +546,25 @@ const zod = () => [{
702
546
  plugins: { "import-zod": importZodPlugin },
703
547
  rules: { "import-zod/prefer-zod-namespace": "error" }
704
548
  }];
705
-
549
+ //#endregion
550
+ //#region src/utils.ts
551
+ function normalizeRuleValue(value) {
552
+ if (Array.isArray(value)) {
553
+ const [level, ...rest] = value;
554
+ return level === "warn" || level === 1 ? ["error", ...rest] : value;
555
+ }
556
+ return value === "warn" || value === 1 ? "error" : value;
557
+ }
558
+ function makeAllErrors(configs) {
559
+ return configs.map((config) => {
560
+ if (!config.rules) return config;
561
+ const rules = Object.fromEntries(Object.entries(config.rules).map(([rule, rawValue]) => [rule, normalizeRuleValue(rawValue)]));
562
+ return {
563
+ ...config,
564
+ rules
565
+ };
566
+ });
567
+ }
706
568
  //#endregion
707
569
  //#region src/base.ts
708
570
  const isReactInstalled = isPackageExists("react");
@@ -713,16 +575,18 @@ const defineConfig = (options = {}, ...userConfigs) => {
713
575
  ...gitignore(),
714
576
  ...ignores(options.ignores),
715
577
  ...javascript(),
578
+ ...jsdoc(),
716
579
  ...sonarjs(),
717
580
  ...importSort(),
718
581
  ...deMorgan(),
719
582
  ...comments(),
720
583
  ...node(),
721
- ...importX(options.importX),
584
+ ...importX(),
722
585
  ...command(),
723
586
  ...unicorn(),
724
- ...jsx(options.jsx ?? {}),
587
+ ...jsxA11y(options.jsxA11y),
725
588
  ...typescript(),
589
+ ...unusedImports(),
726
590
  ...regexp(),
727
591
  ...stylistic(),
728
592
  ...zod(),
@@ -730,7 +594,7 @@ const defineConfig = (options = {}, ...userConfigs) => {
730
594
  ...nelsonlaidev()
731
595
  ];
732
596
  const isNextjsEnabled = options.nextjs ?? isNextjsInstalled;
733
- const isReactEnabled = (options.react ?? isReactInstalled) || isNextjsEnabled;
597
+ const isReactEnabled = options.react ?? isReactInstalled;
734
598
  const isPrettierEnabled = options.prettier ?? isPrettierInstalled;
735
599
  if (options.vitest) configs.push(...vitest(options.vitest));
736
600
  if (options.playwright) configs.push(...playwright(options.playwright));
@@ -739,9 +603,9 @@ const defineConfig = (options = {}, ...userConfigs) => {
739
603
  if (options.tailwindcss) configs.push(...tailwindcss(options.tailwindcss));
740
604
  configs.push(...userConfigs);
741
605
  if (isPrettierEnabled) configs.push(...prettier());
742
- return configs;
606
+ return makeAllErrors(configs);
743
607
  };
744
-
745
608
  //#endregion
746
609
  export { GLOB_JS, GLOB_JSX, GLOB_SRC, GLOB_SRC_EXT, GLOB_TS, GLOB_TSX, defineConfig };
610
+
747
611
  //# sourceMappingURL=index.mjs.map