@eslint-sets/eslint-config 6.2.0 → 6.3.0-beta.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.
Files changed (53) hide show
  1. package/README.md +0 -2
  2. package/dist/cli/index.js +0 -0
  3. package/dist/configs/command.d.ts +2 -2
  4. package/dist/configs/command.d.ts.map +1 -1
  5. package/dist/configs/{eslint-comments.d.ts → comments.d.ts} +3 -3
  6. package/dist/configs/comments.d.ts.map +1 -0
  7. package/dist/configs/disables.d.ts.map +1 -1
  8. package/dist/configs/formatters.d.ts +53 -13
  9. package/dist/configs/formatters.d.ts.map +1 -1
  10. package/dist/configs/imports.d.ts +1 -1
  11. package/dist/configs/imports.d.ts.map +1 -1
  12. package/dist/configs/index.d.ts +4 -6
  13. package/dist/configs/index.d.ts.map +1 -1
  14. package/dist/configs/javascript.d.ts.map +1 -1
  15. package/dist/configs/jsdoc.d.ts +12 -0
  16. package/dist/configs/jsdoc.d.ts.map +1 -0
  17. package/dist/configs/jsonc.d.ts.map +1 -1
  18. package/dist/configs/jsx.d.ts +18 -0
  19. package/dist/configs/jsx.d.ts.map +1 -0
  20. package/dist/configs/markdown.d.ts +11 -1
  21. package/dist/configs/markdown.d.ts.map +1 -1
  22. package/dist/configs/node.d.ts.map +1 -1
  23. package/dist/configs/perfectionist.d.ts.map +1 -1
  24. package/dist/configs/react.d.ts +7 -2
  25. package/dist/configs/react.d.ts.map +1 -1
  26. package/dist/configs/stylistic.d.ts +5 -25
  27. package/dist/configs/stylistic.d.ts.map +1 -1
  28. package/dist/configs/test.d.ts +3 -4
  29. package/dist/configs/test.d.ts.map +1 -1
  30. package/dist/configs/toml.d.ts.map +1 -1
  31. package/dist/configs/typescript.d.ts.map +1 -1
  32. package/dist/configs/unicorn.d.ts.map +1 -1
  33. package/dist/configs/vue.d.ts +18 -0
  34. package/dist/configs/vue.d.ts.map +1 -1
  35. package/dist/configs/yaml.d.ts +1 -1
  36. package/dist/configs/yaml.d.ts.map +1 -1
  37. package/dist/constants.d.ts +21 -4
  38. package/dist/constants.d.ts.map +1 -1
  39. package/dist/index.js +974 -794
  40. package/dist/plugins.d.ts +12 -0
  41. package/dist/plugins.d.ts.map +1 -1
  42. package/dist/types.d.ts +12 -11
  43. package/dist/types.d.ts.map +1 -1
  44. package/package.json +157 -149
  45. package/dist/configs/e18e.d.ts +0 -12
  46. package/dist/configs/e18e.d.ts.map +0 -1
  47. package/dist/configs/eslint-comments.d.ts.map +0 -1
  48. package/dist/configs/jsx-a11y.d.ts +0 -11
  49. package/dist/configs/jsx-a11y.d.ts.map +0 -1
  50. package/dist/configs/no-only-tests.d.ts +0 -12
  51. package/dist/configs/no-only-tests.d.ts.map +0 -1
  52. package/dist/configs/vue-a11y.d.ts +0 -12
  53. package/dist/configs/vue-a11y.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -4,10 +4,12 @@
4
4
  import { isPackageExists } from "local-pkg";
5
5
 
6
6
  // src/constants.ts
7
- var GLOB_SRC = "**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}";
8
- var GLOB_JS = "**/*.{js,mjs,cjs,jsx}";
9
- var GLOB_TS = "**/*.{ts,mts,cts,tsx}";
10
- var GLOB_TSX = "**/*.tsx";
7
+ var GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
8
+ var GLOB_SRC = `**/*.${GLOB_SRC_EXT}`;
9
+ var GLOB_JS = "**/*.?([cm])js";
10
+ var GLOB_JSX = "**/*.?([cm])jsx";
11
+ var GLOB_TS = "**/*.?([cm])ts";
12
+ var GLOB_TSX = "**/*.?([cm])tsx";
11
13
  var GLOB_VUE = "**/*.vue";
12
14
  var GLOB_REACT = "**/*.{jsx,tsx,js,ts}";
13
15
  var GLOB_SVELTE = "**/*.svelte";
@@ -16,10 +18,13 @@ var GLOB_JSON5 = "**/*.json5";
16
18
  var GLOB_JSONC = "**/*.jsonc";
17
19
  var GLOB_YAML = "**/*.{yml,yaml}";
18
20
  var GLOB_MD = "**/*.md";
21
+ var GLOB_MD_IN_MD = "**/*.md/*.md";
22
+ var GLOB_MD_CODE = "**/*.md/**/*.?([cm])[jt]s?(x)";
19
23
  var GLOB_HTML = "**/*.html";
20
24
  var GLOB_TESTS = "**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}";
21
25
  var GLOB_ALL = "**/*";
22
26
  var GLOB_ASTRO = "**/*.astro";
27
+ var GLOB_ASTRO_TS = "**/*.astro/*.ts";
23
28
  var GLOB_CONFIG_FILES = "**/*.config.{js,ts,mjs,mts,cjs,cts}";
24
29
  var GLOB_COMMAND_FILES = [
25
30
  "**/scripts/**/*.{js,ts,mjs,mts,cjs,cts}",
@@ -68,6 +73,19 @@ var ASTRO_PACKAGES = ["astro"];
68
73
  var ANGULAR_PACKAGES = ["@angular/core", "@angular-eslint/eslint-plugin"];
69
74
  var UNOCSS_PACKAGES = ["@unocss/eslint-plugin", "unocss"];
70
75
  var REACT_COMPILER_PACKAGES = ["babel-plugin-react-compiler"];
76
+ var REMIX_PACKAGES = [
77
+ "@remix-run/node",
78
+ "@remix-run/react",
79
+ "@remix-run/serve",
80
+ "@remix-run/dev"
81
+ ];
82
+ var REACT_ROUTER_PACKAGES = [
83
+ "@react-router/node",
84
+ "@react-router/react",
85
+ "@react-router/serve",
86
+ "@react-router/dev"
87
+ ];
88
+ var REACT_REFRESH_ALLOW_CONSTANT_EXPORT_PACKAGES = ["vite"];
71
89
  var EDITOR_ENV_KEYS = [
72
90
  "VSCODE_PID",
73
91
  "VSCODE_CWD",
@@ -116,6 +134,15 @@ function hasAngular() {
116
134
  function hasUnoCSS() {
117
135
  return UNOCSS_PACKAGES.some((pkg) => isPackageExists(pkg));
118
136
  }
137
+ function hasRemix() {
138
+ return REMIX_PACKAGES.some((pkg) => isPackageExists(pkg));
139
+ }
140
+ function hasReactRouter() {
141
+ return REACT_ROUTER_PACKAGES.some((pkg) => isPackageExists(pkg));
142
+ }
143
+ function hasVite() {
144
+ return REACT_REFRESH_ALLOW_CONSTANT_EXPORT_PACKAGES.some((pkg) => isPackageExists(pkg));
145
+ }
119
146
  function hasPackage(name) {
120
147
  return isPackageExists(name);
121
148
  }
@@ -301,7 +328,7 @@ async function angular(options = {}) {
301
328
  {
302
329
  name: "eslint-sets/angular/setup",
303
330
  plugins: {
304
- angular: angularPlugin,
331
+ "angular": angularPlugin,
305
332
  "angular-template": angularTemplatePlugin
306
333
  }
307
334
  },
@@ -387,288 +414,355 @@ async function astro(options = {}) {
387
414
  }
388
415
 
389
416
  // src/configs/command.ts
390
- var GLOB_COMMAND_FILES2 = [
391
- "**/scripts/**/*.{js,ts,mjs,mts,cjs,cts}",
392
- "**/bin/**/*.{js,ts,mjs,mts,cjs,cts}",
393
- "**/cli/**/*.{js,ts,mjs,mts,cjs,cts}",
394
- "**/tasks/**/*.{js,ts,mjs,mts,cjs,cts}",
395
- "**/tools/**/*.{js,ts,mjs,mts,cjs,cts}"
396
- ];
397
- function command() {
417
+ async function command() {
418
+ const commandPlugin = await loadPlugin("eslint-plugin-command/config");
419
+ if (!commandPlugin) {
420
+ return [];
421
+ }
422
+ return [
423
+ {
424
+ ...commandPlugin,
425
+ name: "eslint-sets/command"
426
+ }
427
+ ];
428
+ }
429
+
430
+ // src/configs/comments.ts
431
+ import eslintCommentsPlugin from "@eslint-community/eslint-plugin-eslint-comments";
432
+ function comments(options = {}) {
433
+ const { overrides = {} } = options;
398
434
  return [
399
435
  {
400
- files: GLOB_COMMAND_FILES2,
401
- name: "eslint-sets/command",
436
+ files: [GLOB_SRC],
437
+ name: "eslint-sets/comments",
438
+ plugins: {
439
+ "eslint-comments": eslintCommentsPlugin
440
+ },
402
441
  rules: {
403
- "import-x/no-default-export": "off",
404
- // Disable import checks for scripts
405
- "import-x/no-unresolved": "off",
406
- // Allow shebang in scripts (n/hashbang handles this)
407
- "n/hashbang": "off",
408
- // Allow console in scripts
409
- "no-console": "off",
410
- // Allow process.env in scripts
411
- "no-process-env": "off",
412
- // Allow process.exit in scripts
413
- "no-process-exit": "off",
414
- "perfectionist/sort-exports": "off",
415
- // Relax perfectionist for scripts
416
- "perfectionist/sort-imports": "off",
417
- // Disable type checks for scripts
418
- "ts/no-explicit-any": "off",
419
- // Allow top-level await in ESM scripts
420
- "ts/no-floating-promises": "off",
421
- // Allow synchronous methods in scripts
422
- "ts/no-misused-promises": "off",
423
- "ts/no-unsafe-assignment": "off",
424
- "ts/no-unsafe-call": "off",
425
- "ts/no-unsafe-member-access": "off",
426
- "ts/no-unsafe-return": "off",
427
- // Allow unused expressions (for side-effect scripts)
428
- "ts/no-unused-expressions": "off",
429
- // Allow require in scripts
430
- "ts/no-var-requires": "off",
431
- "unicorn/no-useless-await": "off",
432
- "unicorn/prefer-module": "off",
433
- "unicorn/prefer-top-level-await": "off"
442
+ // Require ESLint directive comments to be meaningful
443
+ "eslint-comments/no-aggregating-enable": "error",
444
+ "eslint-comments/no-duplicate-disable": "error",
445
+ "eslint-comments/no-unlimited-disable": "error",
446
+ "eslint-comments/no-unused-enable": "error",
447
+ // User overrides
448
+ ...overrides
434
449
  }
435
450
  }
436
451
  ];
437
452
  }
438
453
 
439
454
  // src/configs/disables.ts
440
- var GLOB_CONFIG_FILES2 = [
441
- "**/*.config.{js,ts,mjs,mts,cjs,cts}",
442
- "**/.*rc.{js,ts,mjs,mts,cjs,cts,json}",
443
- "**/.eslint*.{js,ts,mjs,mts,cjs,cts,json}",
444
- "**/.prettier*.{js,ts,mjs,mts,cjs,cts,json}",
445
- "**/tsconfig*.json",
446
- "**/package.json",
447
- "**/Dockerfile*"
448
- ];
449
455
  function disables() {
450
456
  return [
451
457
  {
452
- files: GLOB_CONFIG_FILES2,
453
- name: "eslint-sets/disables/config-files",
458
+ files: [`**/scripts/${GLOB_SRC}`],
459
+ name: "eslint-sets/disables/scripts",
454
460
  rules: {
455
- "import-x/no-default-export": "off",
456
- "import-x/no-named-as-default": "off",
457
- "import-x/no-named-as-default-member": "off",
458
461
  "no-console": "off",
459
- "perfectionist/sort-exports": "off",
460
- "perfectionist/sort-imports": "off",
461
- "perfectionist/sort-named-exports": "off",
462
- "perfectionist/sort-named-imports": "off",
463
- "ts/no-explicit-any": "off",
464
- "ts/no-unsafe-assignment": "off",
465
- "ts/no-unsafe-call": "off",
466
- "ts/no-unsafe-member-access": "off",
467
- "ts/no-unsafe-return": "off",
468
- "ts/no-var-requires": "off",
469
- "unicorn/prefer-module": "off",
470
- "unicorn/prefer-node-protocol": "off"
462
+ "ts/explicit-function-return-type": "off"
471
463
  }
472
464
  },
473
465
  {
474
- files: ["**/*.json"],
475
- name: "eslint-sets/disables/json-files",
466
+ files: [`**/cli/${GLOB_SRC}`, `**/cli.${GLOB_SRC_EXT}`],
467
+ name: "eslint-sets/disables/cli",
476
468
  rules: {
477
- "jsonc/sort-keys": "off"
469
+ "no-console": "off"
478
470
  }
479
471
  },
480
472
  {
481
- files: ["**/*.cjs"],
482
- name: "eslint-sets/disables/cjs-files",
473
+ files: ["**/bin/**/*", `**/bin.${GLOB_SRC_EXT}`],
474
+ name: "eslint-sets/disables/bin",
475
+ rules: {}
476
+ },
477
+ {
478
+ files: ["**/*.d.?([cm])ts"],
479
+ name: "eslint-sets/disables/dts",
483
480
  rules: {
484
- "import-x/no-default-export": "off",
485
- "ts/no-var-requires": "off",
486
- "unicorn/prefer-module": "off"
481
+ "eslint-comments/no-unlimited-disable": "off",
482
+ "no-restricted-syntax": "off",
483
+ "unused-imports/no-unused-vars": "off"
487
484
  }
488
485
  },
489
486
  {
490
- files: ["**/*.d.ts"],
491
- name: "eslint-sets/disables/dts-files",
487
+ files: ["**/*.js", "**/*.cjs"],
488
+ name: "eslint-sets/disables/cjs",
492
489
  rules: {
493
- "import-x/no-default-export": "off",
494
- "import-x/no-unresolved": "off",
495
- "no-unused-vars": "off",
496
- "ts/no-explicit-any": "off",
497
- "ts/no-unsafe-assignment": "off",
498
- "ts/no-unsafe-call": "off",
499
- "ts/no-unsafe-member-access": "off",
500
- "ts/no-unsafe-return": "off",
501
- "ts/no-unused-vars": "off",
502
- "ts/triple-slash-reference": "off",
503
- "unicorn/filename-case": "off"
490
+ "ts/no-require-imports": "off"
504
491
  }
505
492
  },
506
493
  {
507
- files: ["**/.env*"],
508
- name: "eslint-sets/disables/env-files",
494
+ files: [`**/*.config.${GLOB_SRC_EXT}`, `**/*.config.*.${GLOB_SRC_EXT}`],
495
+ name: "eslint-sets/disables/config-files",
509
496
  rules: {
510
- "no-process-env": "off"
497
+ "no-console": "off",
498
+ "ts/explicit-function-return-type": "off"
511
499
  }
512
500
  }
513
501
  ];
514
502
  }
515
503
 
516
- // src/configs/e18e.ts
517
- async function e18e(options = {}) {
518
- const { overrides = {} } = options;
519
- const plugin = await loadPlugin("@e18e/eslint-plugin");
520
- if (!plugin) {
504
+ // src/configs/formatters.ts
505
+ import { isPackageExists as isPackageExists2 } from "local-pkg";
506
+ function mergePrettierOptions(options, overrides) {
507
+ return {
508
+ ...options,
509
+ ...overrides,
510
+ plugins: [
511
+ ...overrides.plugins || [],
512
+ ...options.plugins || []
513
+ ]
514
+ };
515
+ }
516
+ async function formatters(options = {}, stylistic2 = {}) {
517
+ if (options === true) {
518
+ const hasXmlPlugin = isPackageExists2("@prettier/plugin-xml");
519
+ options = {
520
+ astro: isPackageExists2("prettier-plugin-astro"),
521
+ css: true,
522
+ graphql: true,
523
+ html: true,
524
+ markdown: true,
525
+ slidev: isPackageExists2("@slidev/cli"),
526
+ svg: hasXmlPlugin,
527
+ xml: hasXmlPlugin
528
+ };
529
+ }
530
+ const {
531
+ astro: astroOption,
532
+ css: cssOption = true,
533
+ dprintOptions = {},
534
+ graphql: graphqlOption = true,
535
+ html: htmlOption = true,
536
+ markdown: markdownOption,
537
+ prettierOptions: customPrettierOptions = {},
538
+ slidev: slidevOption,
539
+ svg: svgOption,
540
+ xml: xmlOption
541
+ } = options;
542
+ if (slidevOption && markdownOption !== true && markdownOption !== "prettier") {
543
+ throw new Error("`slidev` option only works when `markdown` is enabled with `prettier`");
544
+ }
545
+ const hasFormatters = cssOption || htmlOption || xmlOption || svgOption || graphqlOption || markdownOption || astroOption;
546
+ if (!hasFormatters) {
521
547
  return [];
522
548
  }
523
- return [
549
+ const formatPlugin = await loadPlugin("eslint-plugin-format");
550
+ if (!formatPlugin) {
551
+ return [];
552
+ }
553
+ const { indent = 2, quotes = "single" } = stylistic2;
554
+ const prettierOptions = {
555
+ endOfLine: "auto",
556
+ printWidth: 120,
557
+ semi: false,
558
+ singleQuote: quotes === "single",
559
+ tabWidth: typeof indent === "number" ? indent : 2,
560
+ trailingComma: "all",
561
+ useTabs: indent === "tab",
562
+ ...customPrettierOptions
563
+ };
564
+ const prettierXmlOptions = {
565
+ xmlQuoteAttributes: "double",
566
+ xmlSelfClosingSpace: true,
567
+ xmlSortAttributesByKey: false,
568
+ xmlWhitespaceSensitivity: "ignore"
569
+ };
570
+ const dprintConfig = {
571
+ indentWidth: typeof indent === "number" ? indent : 2,
572
+ quoteStyle: quotes === "single" ? "preferSingle" : "preferDouble",
573
+ useTabs: indent === "tab",
574
+ ...dprintOptions
575
+ };
576
+ const configs = [
524
577
  {
525
- files: [GLOB_SRC],
526
- name: "eslint-sets/e18e",
578
+ name: "eslint-sets/formatters/setup",
527
579
  plugins: {
528
- e18e: plugin
529
- },
530
- rules: {
531
- "e18e/no-legacy-object-iteration": "warn",
532
- // e18e modernization rules
533
- "e18e/prefer-array-flat": "warn",
534
- "e18e/prefer-array-flat-map": "warn",
535
- "e18e/prefer-array-from-async": "warn",
536
- "e18e/prefer-object-from-entries": "warn",
537
- "e18e/prefer-spread": "warn",
538
- "e18e/prefer-string-replace-all": "warn",
539
- // User overrides
540
- ...overrides
580
+ format: formatPlugin
541
581
  }
542
582
  }
543
583
  ];
544
- }
545
-
546
- // src/configs/eslint-comments.ts
547
- async function eslintComments(options = {}) {
548
- const { overrides = {} } = options;
549
- const plugin = await loadPlugin(
550
- "@eslint-community/eslint-plugin-eslint-comments"
551
- );
552
- if (!plugin) {
553
- return [];
584
+ if (cssOption) {
585
+ configs.push(
586
+ {
587
+ files: ["**/*.css", "**/*.postcss"],
588
+ languageOptions: {
589
+ parser: null
590
+ // plain parser
591
+ },
592
+ name: "eslint-sets/formatters/css",
593
+ rules: {
594
+ "format/prettier": [
595
+ "error",
596
+ mergePrettierOptions(prettierOptions, { parser: "css" })
597
+ ]
598
+ }
599
+ },
600
+ {
601
+ files: ["**/*.scss"],
602
+ languageOptions: {
603
+ parser: null
604
+ },
605
+ name: "eslint-sets/formatters/scss",
606
+ rules: {
607
+ "format/prettier": [
608
+ "error",
609
+ mergePrettierOptions(prettierOptions, { parser: "scss" })
610
+ ]
611
+ }
612
+ },
613
+ {
614
+ files: ["**/*.less"],
615
+ languageOptions: {
616
+ parser: null
617
+ },
618
+ name: "eslint-sets/formatters/less",
619
+ rules: {
620
+ "format/prettier": [
621
+ "error",
622
+ mergePrettierOptions(prettierOptions, { parser: "less" })
623
+ ]
624
+ }
625
+ }
626
+ );
554
627
  }
555
- return [
556
- {
557
- files: [GLOB_SRC],
558
- name: "eslint-sets/eslint-comments",
559
- plugins: {
560
- "@eslint-community/eslint-comments": plugin
628
+ if (htmlOption) {
629
+ configs.push({
630
+ files: [GLOB_HTML],
631
+ languageOptions: {
632
+ parser: null
561
633
  },
634
+ name: "eslint-sets/formatters/html",
562
635
  rules: {
563
- // Require ESLint directive comments to be meaningful
564
- "@eslint-community/eslint-comments/disable-enable-pair": "error",
565
- "@eslint-community/eslint-comments/no-aggregating-enable": "error",
566
- "@eslint-community/eslint-comments/no-duplicate-disable": "error",
567
- "@eslint-community/eslint-comments/no-unlimited-disable": "error",
568
- "@eslint-community/eslint-comments/no-unused-disable": "error",
569
- "@eslint-community/eslint-comments/no-unused-enable": "error",
570
- "@eslint-community/eslint-comments/require-description": "off",
571
- // User overrides
572
- ...overrides
573
- }
574
- }
575
- ];
576
- }
577
-
578
- // src/configs/formatters.ts
579
- async function formatters(options = {}) {
580
- const {
581
- css = "prettier",
582
- graphql,
583
- html = "prettier",
584
- markdown: markdown2,
585
- overrides = {},
586
- svg,
587
- xml
588
- } = options;
589
- const configs = [];
590
- const hasFormatters = css !== "none" || html !== "none" || xml || svg || graphql || markdown2;
591
- if (hasFormatters) {
592
- const formatPlugin = await loadPlugin("eslint-plugin-format");
593
- if (formatPlugin) {
594
- if (css === "prettier") {
595
- configs.push({
596
- files: ["**/*.css", "**/*.scss", "**/*.less", "**/*.sass"],
597
- name: "eslint-sets/formatters/css",
598
- plugins: {
599
- format: formatPlugin
600
- },
601
- rules: {
602
- "format/prettier": ["error", { parser: "css" }]
603
- }
604
- });
636
+ "format/prettier": [
637
+ "error",
638
+ mergePrettierOptions(prettierOptions, { parser: "html" })
639
+ ]
605
640
  }
606
- if (html === "prettier") {
607
- configs.push({
608
- files: ["**/*.html"],
609
- name: "eslint-sets/formatters/html",
610
- plugins: {
611
- format: formatPlugin
612
- },
613
- rules: {
614
- "format/prettier": ["error", { parser: "html" }]
615
- }
616
- });
641
+ });
642
+ }
643
+ if (xmlOption) {
644
+ configs.push({
645
+ files: ["**/*.xml"],
646
+ languageOptions: {
647
+ parser: null
648
+ },
649
+ name: "eslint-sets/formatters/xml",
650
+ rules: {
651
+ "format/prettier": [
652
+ "error",
653
+ mergePrettierOptions({ ...prettierXmlOptions, ...prettierOptions }, {
654
+ parser: "xml",
655
+ plugins: ["@prettier/plugin-xml"]
656
+ })
657
+ ]
617
658
  }
618
- if (xml === "prettier") {
619
- configs.push({
620
- files: ["**/*.xml"],
621
- name: "eslint-sets/formatters/xml",
622
- plugins: {
623
- format: formatPlugin
624
- },
625
- rules: {
626
- "format/prettier": ["error", { parser: "xml" }]
627
- }
628
- });
659
+ });
660
+ }
661
+ if (svgOption) {
662
+ configs.push({
663
+ files: ["**/*.svg"],
664
+ languageOptions: {
665
+ parser: null
666
+ },
667
+ name: "eslint-sets/formatters/svg",
668
+ rules: {
669
+ "format/prettier": [
670
+ "error",
671
+ mergePrettierOptions({ ...prettierXmlOptions, ...prettierOptions }, {
672
+ parser: "xml",
673
+ plugins: ["@prettier/plugin-xml"]
674
+ })
675
+ ]
629
676
  }
630
- if (svg === "prettier") {
631
- configs.push({
632
- files: ["**/*.svg"],
633
- name: "eslint-sets/formatters/svg",
634
- plugins: {
635
- format: formatPlugin
636
- },
637
- rules: {
638
- "format/prettier": ["error", { parser: "html" }]
677
+ });
678
+ }
679
+ if (markdownOption) {
680
+ const formatter = markdownOption === true ? "prettier" : markdownOption;
681
+ const slidevFiles = !slidevOption ? [] : slidevOption === true ? ["**/slides.md"] : slidevOption.files || [];
682
+ configs.push({
683
+ files: [GLOB_MD],
684
+ ignores: slidevFiles,
685
+ languageOptions: {
686
+ parser: null
687
+ },
688
+ name: "eslint-sets/formatters/markdown",
689
+ rules: {
690
+ [`format/${formatter}`]: [
691
+ "error",
692
+ formatter === "prettier" ? mergePrettierOptions(prettierOptions, {
693
+ embeddedLanguageFormatting: "off",
694
+ parser: "markdown"
695
+ }) : {
696
+ ...dprintConfig,
697
+ language: "markdown"
639
698
  }
640
- });
699
+ ]
641
700
  }
642
- if (graphql === "prettier") {
643
- configs.push({
644
- files: ["**/*.graphql", "**/*.gql"],
645
- name: "eslint-sets/formatters/graphql",
646
- plugins: {
647
- format: formatPlugin
648
- },
649
- rules: {
650
- "format/prettier": ["error", { parser: "graphql" }]
651
- }
652
- });
701
+ });
702
+ if (slidevOption) {
703
+ configs.push({
704
+ files: slidevFiles.length > 0 ? slidevFiles : ["**/slides.md"],
705
+ languageOptions: {
706
+ parser: null
707
+ },
708
+ name: "eslint-sets/formatters/slidev",
709
+ rules: {
710
+ "format/prettier": [
711
+ "error",
712
+ mergePrettierOptions(prettierOptions, {
713
+ embeddedLanguageFormatting: "off",
714
+ parser: "slidev",
715
+ plugins: ["prettier-plugin-slidev"]
716
+ })
717
+ ]
718
+ }
719
+ });
720
+ }
721
+ }
722
+ if (astroOption) {
723
+ configs.push({
724
+ files: [GLOB_ASTRO],
725
+ languageOptions: {
726
+ parser: null
727
+ },
728
+ name: "eslint-sets/formatters/astro",
729
+ rules: {
730
+ "format/prettier": [
731
+ "error",
732
+ mergePrettierOptions(prettierOptions, {
733
+ parser: "astro",
734
+ plugins: ["prettier-plugin-astro"]
735
+ })
736
+ ]
653
737
  }
654
- if (markdown2 === "prettier") {
655
- configs.push({
656
- files: ["**/*.md"],
657
- name: "eslint-sets/formatters/markdown",
658
- plugins: {
659
- format: formatPlugin
660
- },
661
- rules: {
662
- "format/prettier": ["error", { parser: "markdown" }]
663
- }
664
- });
738
+ });
739
+ configs.push({
740
+ files: [GLOB_ASTRO, GLOB_ASTRO_TS],
741
+ name: "eslint-sets/formatters/astro/disables",
742
+ rules: {
743
+ "style/arrow-parens": "off",
744
+ "style/block-spacing": "off",
745
+ "style/comma-dangle": "off",
746
+ "style/indent": "off",
747
+ "style/no-multi-spaces": "off",
748
+ "style/quotes": "off",
749
+ "style/semi": "off"
665
750
  }
666
- }
751
+ });
667
752
  }
668
- if (Object.keys(overrides).length > 0) {
753
+ if (graphqlOption) {
669
754
  configs.push({
670
- name: "eslint-sets/formatters/custom",
671
- rules: overrides
755
+ files: ["**/*.graphql", "**/*.gql"],
756
+ languageOptions: {
757
+ parser: null
758
+ },
759
+ name: "eslint-sets/formatters/graphql",
760
+ rules: {
761
+ "format/prettier": [
762
+ "error",
763
+ mergePrettierOptions(prettierOptions, { parser: "graphql" })
764
+ ]
765
+ }
672
766
  });
673
767
  }
674
768
  return configs;
@@ -683,43 +777,26 @@ function ignores(userIgnores = []) {
683
777
  }
684
778
 
685
779
  // src/configs/imports.ts
686
- import importPlugin from "eslint-plugin-import-x";
687
- import unusedImports from "eslint-plugin-unused-imports";
780
+ import importPlugin from "eslint-plugin-import-lite";
688
781
  function imports(options = {}) {
689
782
  const { overrides = {}, stylistic: stylistic2 = true } = options;
690
783
  return {
691
784
  files: [GLOB_SRC],
692
785
  name: "eslint-sets/imports",
693
786
  plugins: {
694
- "import-x": importPlugin,
695
- "unused-imports": unusedImports
787
+ import: importPlugin
696
788
  },
697
789
  rules: {
698
790
  // Essential import rules
699
- "import-x/first": "error",
700
- "import-x/no-duplicates": "error",
701
- "import-x/no-mutable-exports": "error",
702
- "import-x/no-named-default": "error",
703
- "import-x/no-self-import": "error",
704
- "import-x/no-webpack-loader-syntax": "error",
705
- // Note: import-x/order is disabled - sorting is handled by perfectionist/sort-imports
706
- "import-x/order": "off",
791
+ "import/first": "error",
792
+ "import/no-duplicates": "error",
793
+ "import/no-mutable-exports": "error",
794
+ "import/no-named-default": "error",
795
+ "import/consistent-type-specifier-style": ["error", "prefer-top-level"],
707
796
  // Stylistic rules
708
797
  ...stylistic2 ? {
709
- "import-x/newline-after-import": ["error", { count: 1 }]
798
+ "import/newline-after-import": ["error", { count: 1 }]
710
799
  } : {},
711
- // Unused imports handling (essential)
712
- "unused-imports/no-unused-imports": "error",
713
- "unused-imports/no-unused-vars": [
714
- "error",
715
- {
716
- args: "after-used",
717
- argsIgnorePattern: "^_",
718
- ignoreRestSiblings: true,
719
- vars: "all",
720
- varsIgnorePattern: "^_"
721
- }
722
- ],
723
800
  // User overrides
724
801
  ...overrides
725
802
  }
@@ -728,6 +805,7 @@ function imports(options = {}) {
728
805
 
729
806
  // src/configs/javascript.ts
730
807
  import js from "@eslint/js";
808
+ import unusedImports from "eslint-plugin-unused-imports";
731
809
  import globals from "globals";
732
810
  function javascript(options = {}) {
733
811
  const { isInEditor = false, overrides = {} } = options;
@@ -754,6 +832,9 @@ function javascript(options = {}) {
754
832
  reportUnusedDisableDirectives: true
755
833
  },
756
834
  name: "eslint-sets/javascript",
835
+ plugins: {
836
+ "unused-imports": unusedImports
837
+ },
757
838
  rules: {
758
839
  ...js.configs.recommended.rules,
759
840
  // Basic rules
@@ -763,11 +844,11 @@ function javascript(options = {}) {
763
844
  "constructor-super": "error",
764
845
  "default-case-last": "error",
765
846
  "dot-notation": ["error", { allowKeywords: true }],
766
- eqeqeq: ["error", "smart"],
767
- indent: "off",
847
+ "eqeqeq": ["error", "smart"],
848
+ "indent": "off",
768
849
  // Let Prettier handle
769
850
  "new-cap": ["error", { capIsNew: false, newIsCap: true, properties: true }],
770
- "no-alert": "warn",
851
+ "no-alert": "error",
771
852
  "no-array-constructor": "error",
772
853
  "no-async-promise-executor": "error",
773
854
  "no-caller": "error",
@@ -775,10 +856,10 @@ function javascript(options = {}) {
775
856
  "no-class-assign": "error",
776
857
  "no-compare-neg-zero": "error",
777
858
  "no-cond-assign": ["error", "always"],
778
- "no-console": ["warn", { allow: ["warn", "error", "info"] }],
859
+ "no-console": ["error", { allow: ["warn", "error"] }],
779
860
  "no-const-assign": "error",
780
861
  "no-control-regex": "error",
781
- "no-debugger": "warn",
862
+ "no-debugger": "error",
782
863
  "no-delete-var": "error",
783
864
  "no-dupe-args": "error",
784
865
  "no-dupe-class-members": "error",
@@ -799,7 +880,7 @@ function javascript(options = {}) {
799
880
  "no-implied-eval": "error",
800
881
  "no-import-assign": "error",
801
882
  "no-invalid-regexp": "error",
802
- "no-irregular-whitespace": "warn",
883
+ "no-irregular-whitespace": "error",
803
884
  "no-iterator": "error",
804
885
  "no-labels": ["error", { allowLoop: false, allowSwitch: false }],
805
886
  "no-lone-blocks": "error",
@@ -835,7 +916,11 @@ function javascript(options = {}) {
835
916
  { message: "Use `Object.getOwnPropertyDescriptor` instead.", property: "__lookupGetter__" },
836
917
  { message: "Use `Object.getOwnPropertyDescriptor` instead.", property: "__lookupSetter__" }
837
918
  ],
838
- "no-restricted-syntax": ["error", "DebuggerStatement", "LabeledStatement", "WithStatement"],
919
+ "no-restricted-syntax": [
920
+ "error",
921
+ "TSEnumDeclaration[const=true]",
922
+ "TSExportAssignment"
923
+ ],
839
924
  "no-self-assign": ["error", { props: true }],
840
925
  "no-self-compare": "error",
841
926
  "no-sequences": "error",
@@ -881,17 +966,9 @@ function javascript(options = {}) {
881
966
  "no-useless-rename": "error",
882
967
  "no-useless-return": "error",
883
968
  "no-var": "error",
884
- "no-void": "error",
885
969
  "no-with": "error",
886
970
  "object-shorthand": ["error", "always", { avoidQuotes: true, ignoreConstructors: false }],
887
- "one-var": [
888
- "warn",
889
- {
890
- const: "never",
891
- let: "always",
892
- var: "always"
893
- }
894
- ],
971
+ "one-var": ["error", { initialized: "never" }],
895
972
  "operator-linebreak": "off",
896
973
  "prefer-arrow-callback": [
897
974
  "error",
@@ -901,7 +978,7 @@ function javascript(options = {}) {
901
978
  }
902
979
  ],
903
980
  "prefer-const": [
904
- "error",
981
+ isInEditor ? "warn" : "error",
905
982
  {
906
983
  destructuring: "all",
907
984
  ignoreReadBeforeAssign: true
@@ -913,25 +990,68 @@ function javascript(options = {}) {
913
990
  "prefer-rest-params": "error",
914
991
  "prefer-spread": "error",
915
992
  "prefer-template": "error",
916
- // Note: sort-imports is disabled - sorting is handled by perfectionist/sort-imports
917
- "sort-imports": "off",
918
- "space-before-function-paren": "off",
919
993
  "symbol-description": "error",
920
994
  "unicode-bom": ["error", "never"],
995
+ "unused-imports/no-unused-imports": isInEditor ? "warn" : "error",
996
+ "unused-imports/no-unused-vars": [
997
+ "error",
998
+ {
999
+ args: "after-used",
1000
+ argsIgnorePattern: "^_",
1001
+ ignoreRestSiblings: true,
1002
+ vars: "all",
1003
+ varsIgnorePattern: "^_"
1004
+ }
1005
+ ],
921
1006
  "use-isnan": ["error", { enforceForIndexOf: true, enforceForSwitchCase: true }],
922
1007
  "valid-typeof": ["error", { requireStringLiterals: true }],
923
1008
  "vars-on-top": "error",
924
- yoda: ["error", "never"],
925
- // Disable in editor for performance
926
- ...isInEditor ? {
927
- "no-unused-vars": "off"
928
- } : {},
1009
+ "yoda": ["error", "never"],
929
1010
  // User overrides
930
1011
  ...overrides
931
1012
  }
932
1013
  };
933
1014
  }
934
1015
 
1016
+ // src/configs/jsdoc.ts
1017
+ async function jsdoc(options = {}) {
1018
+ const { overrides = {} } = options;
1019
+ const jsdocPlugin = await loadPlugin("eslint-plugin-jsdoc");
1020
+ if (!jsdocPlugin) {
1021
+ return [];
1022
+ }
1023
+ return [
1024
+ {
1025
+ files: [GLOB_SRC],
1026
+ name: "eslint-sets/jsdoc",
1027
+ plugins: {
1028
+ jsdoc: jsdocPlugin
1029
+ },
1030
+ rules: {
1031
+ "jsdoc/check-access": "warn",
1032
+ "jsdoc/check-alignment": "warn",
1033
+ "jsdoc/check-param-names": "warn",
1034
+ "jsdoc/check-property-names": "warn",
1035
+ "jsdoc/check-types": "warn",
1036
+ "jsdoc/empty-tags": "warn",
1037
+ "jsdoc/implements-on-classes": "warn",
1038
+ "jsdoc/multiline-blocks": "warn",
1039
+ "jsdoc/no-defaults": "warn",
1040
+ "jsdoc/no-multi-asterisks": "warn",
1041
+ "jsdoc/require-param-name": "warn",
1042
+ "jsdoc/require-property": "warn",
1043
+ "jsdoc/require-property-description": "warn",
1044
+ "jsdoc/require-property-name": "warn",
1045
+ "jsdoc/require-returns-check": "warn",
1046
+ "jsdoc/require-returns-description": "warn",
1047
+ "jsdoc/require-yields-check": "warn",
1048
+ // User overrides
1049
+ ...overrides
1050
+ }
1051
+ }
1052
+ ];
1053
+ }
1054
+
935
1055
  // src/configs/jsonc.ts
936
1056
  import jsoncPlugin from "eslint-plugin-jsonc";
937
1057
  import jsoncParser from "jsonc-eslint-parser";
@@ -980,6 +1100,8 @@ function jsonc(options = {}) {
980
1100
  "jsonc/no-useless-escape": "error",
981
1101
  "jsonc/space-unary-ops": "error",
982
1102
  "jsonc/valid-json-number": "error",
1103
+ // Vue custom block
1104
+ "jsonc/vue-custom-block/no-parsing-error": "error",
983
1105
  // Stylistic rules (conditional)
984
1106
  ...stylistic2 ? {
985
1107
  "jsonc/array-bracket-spacing": ["error", "never"],
@@ -1000,91 +1122,153 @@ function jsonc(options = {}) {
1000
1122
  ];
1001
1123
  }
1002
1124
 
1003
- // src/configs/jsx-a11y.ts
1004
- async function jsxA11y(options = {}) {
1005
- const { overrides = {} } = options;
1006
- const plugin = await loadPlugin("eslint-plugin-jsx-a11y");
1007
- if (!plugin) {
1008
- return [];
1125
+ // src/configs/jsx.ts
1126
+ async function jsx(options = {}) {
1127
+ const { a11y = false, overrides = {} } = options;
1128
+ const baseConfig = {
1129
+ files: [GLOB_JSX, GLOB_TSX],
1130
+ languageOptions: {
1131
+ parserOptions: {
1132
+ ecmaFeatures: {
1133
+ jsx: true
1134
+ }
1135
+ }
1136
+ },
1137
+ name: "eslint-sets/jsx",
1138
+ plugins: {},
1139
+ rules: {
1140
+ ...overrides
1141
+ }
1142
+ };
1143
+ if (!a11y) {
1144
+ return [baseConfig];
1145
+ }
1146
+ const jsxA11yPlugin = await loadPlugin("eslint-plugin-jsx-a11y");
1147
+ if (!jsxA11yPlugin) {
1148
+ return [baseConfig];
1009
1149
  }
1150
+ const a11yConfig = jsxA11yPlugin.flatConfigs?.recommended || {};
1151
+ const a11yRules = {
1152
+ ...a11yConfig.rules || {},
1153
+ ...typeof a11y === "object" && a11y.overrides ? a11y.overrides : {}
1154
+ };
1010
1155
  return [
1011
1156
  {
1012
- files: [GLOB_TSX],
1013
- name: "eslint-sets/jsx-a11y",
1157
+ ...baseConfig,
1158
+ ...a11yConfig,
1159
+ files: baseConfig.files,
1160
+ languageOptions: {
1161
+ ...baseConfig.languageOptions,
1162
+ ...a11yConfig.languageOptions || {}
1163
+ },
1164
+ name: baseConfig.name,
1014
1165
  plugins: {
1015
- "jsx-a11y": plugin
1166
+ ...baseConfig.plugins,
1167
+ "jsx-a11y": jsxA11yPlugin
1016
1168
  },
1017
1169
  rules: {
1018
- // Recommended rules
1019
- ...plugin.configs.recommended.rules,
1020
- // Accessibility rules
1021
- "jsx-a11y/accessible-emoji": "off",
1022
- // Deprecated
1023
- "jsx-a11y/alt-text": "error",
1024
- "jsx-a11y/anchor-ambiguous-text": "off",
1025
- "jsx-a11y/anchor-has-content": "error",
1026
- "jsx-a11y/anchor-is-valid": "error",
1027
- "jsx-a11y/aria-activedescendant-has-tabindex": "error",
1028
- "jsx-a11y/aria-props": "error",
1029
- "jsx-a11y/aria-proptypes": "error",
1030
- "jsx-a11y/aria-role": "error",
1031
- "jsx-a11y/aria-unsupported-elements": "error",
1032
- "jsx-a11y/autocomplete-valid": "error",
1033
- "jsx-a11y/click-events-have-key-events": "warn",
1034
- "jsx-a11y/control-has-associated-label": "warn",
1035
- "jsx-a11y/heading-has-content": "error",
1036
- "jsx-a11y/html-has-lang": "error",
1037
- "jsx-a11y/iframe-has-title": "error",
1038
- "jsx-a11y/img-redundant-alt": "warn",
1039
- "jsx-a11y/interactive-supports-focus": "error",
1040
- "jsx-a11y/label-has-associated-control": "error",
1041
- "jsx-a11y/lang": "error",
1042
- "jsx-a11y/media-has-caption": "warn",
1043
- "jsx-a11y/mouse-events-have-key-events": "error",
1044
- "jsx-a11y/no-access-key": "error",
1045
- "jsx-a11y/no-aria-hidden-on-focusable": "error",
1046
- "jsx-a11y/no-autofocus": "warn",
1047
- "jsx-a11y/no-distracting-elements": "warn",
1048
- "jsx-a11y/no-interactive-element-to-noninteractive-role": "error",
1049
- "jsx-a11y/no-noninteractive-element-interactions": "warn",
1050
- "jsx-a11y/no-noninteractive-element-to-interactive-role": "error",
1051
- "jsx-a11y/no-noninteractive-tabindex": "error",
1052
- "jsx-a11y/no-onchange": "off",
1053
- // Deprecated
1054
- "jsx-a11y/no-redundant-roles": "error",
1055
- "jsx-a11y/no-static-element-interactions": "warn",
1056
- "jsx-a11y/prefer-tag-over-role": "warn",
1057
- "jsx-a11y/role-has-required-aria-props": "error",
1058
- "jsx-a11y/role-supports-aria-props": "error",
1059
- "jsx-a11y/scope": "error",
1060
- "jsx-a11y/tabindex-no-positive": "error",
1061
- // User overrides
1062
- ...overrides
1170
+ ...baseConfig.rules,
1171
+ ...a11yRules
1063
1172
  }
1064
1173
  }
1065
1174
  ];
1066
1175
  }
1067
1176
 
1068
1177
  // src/configs/markdown.ts
1178
+ import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
1069
1179
  async function markdown(options = {}) {
1070
- const { overrides = {} } = options;
1180
+ const {
1181
+ gfm = true,
1182
+ overrides = {},
1183
+ overridesMarkdown = {}
1184
+ } = options;
1071
1185
  const plugin = await loadPlugin("@eslint/markdown");
1072
1186
  if (plugin) {
1073
1187
  return [
1074
1188
  {
1075
- files: [GLOB_MD],
1076
- name: "eslint-sets/markdown",
1189
+ name: "eslint-sets/markdown/setup",
1077
1190
  plugins: {
1078
1191
  markdown: plugin
1192
+ }
1193
+ },
1194
+ {
1195
+ files: [GLOB_MD],
1196
+ ignores: [GLOB_MD_IN_MD],
1197
+ name: "eslint-sets/markdown/processor",
1198
+ // `eslint-plugin-markdown` only creates virtual files for code blocks,
1199
+ // but not the markdown file itself. We use `eslint-merge-processors` to
1200
+ // add a pass-through processor for the markdown file itself.
1201
+ processor: mergeProcessors([
1202
+ plugin.processors.markdown,
1203
+ processorPassThrough
1204
+ ])
1205
+ },
1206
+ {
1207
+ files: [GLOB_MD],
1208
+ language: gfm ? "markdown/gfm" : "markdown/commonmark",
1209
+ name: "eslint-sets/markdown/parser"
1210
+ },
1211
+ {
1212
+ files: [GLOB_MD],
1213
+ name: "eslint-sets/markdown/rules",
1214
+ rules: {
1215
+ ...plugin.configs?.recommended?.at?.(0)?.rules || {},
1216
+ "markdown/fenced-code-language": "off",
1217
+ // https://github.com/eslint/markdown/issues/294
1218
+ "markdown/no-missing-label-refs": "off",
1219
+ ...overridesMarkdown
1220
+ }
1221
+ },
1222
+ {
1223
+ files: [GLOB_MD],
1224
+ name: "eslint-sets/markdown/disables/markdown",
1225
+ rules: {
1226
+ // Disable rules that do not work with markdown sourcecode.
1227
+ "no-irregular-whitespace": "off",
1228
+ "perfectionist/sort-exports": "off",
1229
+ "perfectionist/sort-imports": "off",
1230
+ "regexp/no-legacy-features": "off",
1231
+ "regexp/no-missing-g-flag": "off",
1232
+ "regexp/no-useless-dollar-replacements": "off",
1233
+ "regexp/no-useless-flag": "off",
1234
+ "style/indent": "off"
1235
+ }
1236
+ },
1237
+ {
1238
+ files: [GLOB_MD_CODE],
1239
+ languageOptions: {
1240
+ parserOptions: {
1241
+ ecmaFeatures: {
1242
+ impliedStrict: true
1243
+ }
1244
+ }
1079
1245
  },
1246
+ name: "eslint-sets/markdown/disables/code",
1080
1247
  rules: {
1081
- "markdown/no-empty-definitions": "error",
1082
- // Markdown rules from @eslint/markdown
1083
- "markdown/no-html": "off",
1084
- "markdown/no-missing-atx-heading-space": "error",
1085
- "markdown/no-multiple-h1": "warn",
1086
- "markdown/require-alt-text": "warn",
1087
- // User overrides
1248
+ "no-alert": "off",
1249
+ "no-console": "off",
1250
+ "no-labels": "off",
1251
+ "no-lone-blocks": "off",
1252
+ "no-restricted-syntax": "off",
1253
+ "no-undef": "off",
1254
+ "no-unused-expressions": "off",
1255
+ "no-unused-labels": "off",
1256
+ "no-unused-vars": "off",
1257
+ "node/prefer-global/process": "off",
1258
+ "style/comma-dangle": "off",
1259
+ "style/eol-last": "off",
1260
+ "style/padding-line-between-statements": "off",
1261
+ "ts/consistent-type-imports": "off",
1262
+ "ts/explicit-function-return-type": "off",
1263
+ "ts/no-namespace": "off",
1264
+ "ts/no-redeclare": "off",
1265
+ "ts/no-require-imports": "off",
1266
+ "ts/no-unused-expressions": "off",
1267
+ "ts/no-unused-vars": "off",
1268
+ "ts/no-use-before-define": "off",
1269
+ "unicode-bom": "off",
1270
+ "unused-imports/no-unused-imports": "off",
1271
+ "unused-imports/no-unused-vars": "off",
1088
1272
  ...overrides
1089
1273
  }
1090
1274
  }
@@ -1145,95 +1329,60 @@ async function nextjs(options = {}) {
1145
1329
  ];
1146
1330
  }
1147
1331
 
1148
- // src/configs/no-only-tests.ts
1149
- async function noOnlyTests(options = {}) {
1150
- const { overrides = {} } = options;
1151
- const plugin = await loadPlugin("eslint-plugin-no-only-tests");
1152
- if (!plugin) {
1153
- return [];
1154
- }
1155
- return [
1156
- {
1157
- files: [GLOB_TESTS],
1158
- name: "eslint-sets/no-only-tests",
1159
- plugins: {
1160
- "no-only-tests": plugin
1161
- },
1162
- rules: {
1163
- "no-only-tests/no-only-tests": [
1164
- "error",
1165
- {
1166
- block: [
1167
- "describe",
1168
- "it",
1169
- "context",
1170
- "suite",
1171
- "test",
1172
- "spec",
1173
- "beforeEach",
1174
- "afterEach",
1175
- "before",
1176
- "after"
1177
- ],
1178
- focus: ["only", "skip"]
1179
- }
1180
- ],
1181
- // User overrides
1182
- ...overrides
1183
- }
1184
- }
1185
- ];
1186
- }
1187
-
1188
1332
  // src/configs/node.ts
1189
- import nPlugin from "eslint-plugin-n";
1190
- var nRecommendedRules = nPlugin.configs?.["flat/recommended"]?.rules || {};
1333
+ import nodePlugin from "eslint-plugin-n";
1334
+ var nodeRecommendedRules = renameRules(
1335
+ nodePlugin.configs?.["flat/recommended"]?.rules || {},
1336
+ "node",
1337
+ "n"
1338
+ );
1191
1339
  function node() {
1192
1340
  return [
1193
1341
  {
1194
1342
  files: [GLOB_SRC],
1195
1343
  name: "eslint-sets/node",
1196
1344
  plugins: {
1197
- n: nPlugin
1345
+ node: nodePlugin
1198
1346
  },
1199
1347
  rules: {
1200
- ...nRecommendedRules,
1348
+ ...nodeRecommendedRules,
1201
1349
  // Node.js specific rules
1202
- "n/callback-return": "off",
1203
- "n/exports-style": "off",
1204
- "n/file-extension-in-import": "off",
1205
- "n/global-require": "off",
1206
- "n/handle-callback-err": "error",
1207
- "n/hashbang": "error",
1208
- "n/no-callback-literal": "off",
1209
- "n/no-deprecated-api": "error",
1210
- "n/no-exports-assign": "error",
1211
- "n/no-extraneous-import": "off",
1212
- "n/no-extraneous-require": "off",
1213
- "n/no-missing-import": "off",
1214
- "n/no-missing-require": "off",
1215
- "n/no-mixed-requires": "off",
1216
- "n/no-new-require": "error",
1217
- "n/no-path-concat": "error",
1218
- "n/no-process-env": "off",
1350
+ "node/callback-return": "off",
1351
+ "node/exports-style": "off",
1352
+ "node/file-extension-in-import": "off",
1353
+ "node/global-require": "off",
1354
+ "node/handle-callback-err": "error",
1355
+ "node/hashbang": "error",
1356
+ "node/no-callback-literal": "off",
1357
+ "node/no-deprecated-api": "error",
1358
+ "node/no-exports-assign": "error",
1359
+ "node/no-extraneous-import": "off",
1360
+ "node/no-extraneous-require": "off",
1361
+ "node/no-missing-import": "off",
1362
+ "node/no-missing-require": "off",
1363
+ "node/no-mixed-requires": "off",
1364
+ "node/no-new-require": "error",
1365
+ "node/no-path-concat": "error",
1366
+ "node/no-process-env": "off",
1219
1367
  // Override recommended rules
1220
- "n/no-process-exit": "off",
1221
- "n/no-restricted-import": "off",
1222
- "n/no-restricted-require": "off",
1223
- "n/no-sync": "off",
1224
- "n/no-unpublished-import": "off",
1225
- "n/no-unpublished-require": "off",
1226
- "n/prefer-global/buffer": ["error", "always"],
1227
- "n/prefer-global/console": ["error", "always"],
1228
- "n/prefer-global/process": ["error", "always"],
1229
- "n/prefer-global/text-decoder": ["error", "always"],
1230
- "n/prefer-global/text-encoder": ["error", "always"],
1231
- "n/prefer-global/url": ["error", "always"],
1232
- "n/prefer-global/url-search-params": ["error", "always"],
1368
+ "node/no-process-exit": "off",
1369
+ "node/no-restricted-import": "off",
1370
+ "node/no-restricted-require": "off",
1371
+ "node/no-sync": "off",
1372
+ "node/no-unpublished-import": "off",
1373
+ "node/no-unpublished-require": "off",
1374
+ "node/prefer-global/buffer": ["error", "always"],
1375
+ "node/prefer-global/console": ["error", "always"],
1376
+ "node/prefer-global/process": ["error", "always"],
1377
+ "node/prefer-global/text-decoder": ["error", "always"],
1378
+ "node/prefer-global/text-encoder": ["error", "always"],
1379
+ "node/prefer-global/url": ["error", "always"],
1380
+ "node/prefer-global/url-search-params": ["error", "always"],
1233
1381
  // Use unicorn/prefer-node-protocol instead (configured in unicorn.ts)
1234
- "n/prefer-node-protocol": "off",
1235
- "n/prefer-promises/dns": "error",
1236
- "n/prefer-promises/fs": "error"
1382
+ "node/prefer-node-protocol": "off",
1383
+ "node/prefer-promises/dns": "error",
1384
+ "node/prefer-promises/fs": "error",
1385
+ "node/process-exit-as-throw": "error"
1237
1386
  }
1238
1387
  }
1239
1388
  ];
@@ -1300,13 +1449,6 @@ function perfectionist(options = {}) {
1300
1449
  type
1301
1450
  }
1302
1451
  ],
1303
- "perfectionist/sort-interfaces": [
1304
- "error",
1305
- {
1306
- order,
1307
- type
1308
- }
1309
- ],
1310
1452
  "perfectionist/sort-named-exports": [
1311
1453
  "error",
1312
1454
  {
@@ -1321,13 +1463,6 @@ function perfectionist(options = {}) {
1321
1463
  type
1322
1464
  }
1323
1465
  ],
1324
- "perfectionist/sort-objects": [
1325
- "error",
1326
- {
1327
- order,
1328
- type
1329
- }
1330
- ],
1331
1466
  // User overrides
1332
1467
  ...overrides
1333
1468
  }
@@ -1412,61 +1547,159 @@ function prettier(options = {}) {
1412
1547
  }
1413
1548
 
1414
1549
  // src/configs/react.ts
1550
+ function renameRules2(rules) {
1551
+ const result = {};
1552
+ for (const [key, value] of Object.entries(rules)) {
1553
+ const newKey = key.replace("@eslint-react/rsc/", "react-rsc/").replace("@eslint-react/dom/", "react-dom/").replace("@eslint-react/web-api/", "react-web-api/").replace("@eslint-react/naming-convention/", "react-naming-convention/").replace("@eslint-react/", "react/");
1554
+ if (value !== void 0) {
1555
+ result[newKey] = value;
1556
+ }
1557
+ }
1558
+ return result;
1559
+ }
1415
1560
  async function react(options = {}) {
1416
- const { overrides = {}, reactCompiler = hasReactCompiler() } = options;
1417
- const [reactPlugin, refreshPlugin] = await Promise.all([
1561
+ const {
1562
+ files = [GLOB_REACT],
1563
+ filesTypeAware = [GLOB_TS, GLOB_TSX],
1564
+ ignoresTypeAware = [`${GLOB_MD}/**`, GLOB_ASTRO_TS],
1565
+ overrides = {},
1566
+ tsconfigPath,
1567
+ reactCompiler = hasReactCompiler()
1568
+ } = options;
1569
+ const [
1570
+ pluginReact,
1571
+ pluginReactHooks,
1572
+ pluginReactHooksExtra,
1573
+ pluginReactRefresh
1574
+ ] = await Promise.all([
1418
1575
  loadPlugin("@eslint-react/eslint-plugin"),
1576
+ loadPlugin("eslint-plugin-react-hooks"),
1577
+ loadPlugin("eslint-plugin-react-hooks-extra"),
1419
1578
  loadPlugin("eslint-plugin-react-refresh")
1420
1579
  ]);
1421
- if (!reactPlugin) {
1580
+ if (!pluginReact) {
1422
1581
  return [];
1423
1582
  }
1424
- const recommendedConfig = reactPlugin.configs.recommended;
1425
- const plugins = {
1426
- ...recommendedConfig?.plugins || {},
1427
- ...refreshPlugin && { "react-refresh": refreshPlugin }
1583
+ const isTypeAware = !!tsconfigPath;
1584
+ const isAllowConstantExport = hasVite();
1585
+ const isUsingRemix = hasRemix();
1586
+ const isUsingReactRouter = hasReactRouter();
1587
+ const isUsingNext = hasNextjs();
1588
+ const allPlugins = pluginReact.configs.all.plugins;
1589
+ const recommendedRules = renameRules2(pluginReact.configs.recommended?.rules || {});
1590
+ const typeAwareRules = {
1591
+ "react/no-leaked-conditional-rendering": "warn",
1592
+ "react/no-implicit-key": "error"
1428
1593
  };
1429
1594
  const configs = [
1430
1595
  {
1431
- files: [GLOB_REACT],
1596
+ name: "eslint-sets/react/setup",
1597
+ plugins: {
1598
+ "react": allPlugins["@eslint-react"],
1599
+ "react-dom": allPlugins["@eslint-react/dom"],
1600
+ "react-hooks": pluginReactHooks,
1601
+ "react-hooks-extra": pluginReactHooksExtra,
1602
+ "react-naming-convention": allPlugins["@eslint-react/naming-convention"],
1603
+ "react-refresh": pluginReactRefresh,
1604
+ "react-rsc": allPlugins["@eslint-react/rsc"],
1605
+ "react-web-api": allPlugins["@eslint-react/web-api"]
1606
+ }
1607
+ },
1608
+ {
1609
+ files,
1432
1610
  languageOptions: {
1433
1611
  parserOptions: {
1434
1612
  ecmaFeatures: {
1435
1613
  jsx: true
1436
1614
  }
1437
- }
1615
+ },
1616
+ sourceType: "module"
1438
1617
  },
1439
- name: "eslint-sets/react",
1440
- plugins,
1618
+ name: "eslint-sets/react/rules",
1441
1619
  rules: {
1442
- // @eslint-react recommended rules
1443
- ...recommendedConfig?.rules || {},
1444
- // Adjust some rules
1445
- "@eslint-react/no-nested-component-definitions": "off",
1620
+ // Use recommended rules from @eslint-react/eslint-plugin (renamed)
1621
+ ...recommendedRules,
1622
+ // Additional rules
1623
+ "react/prefer-namespace-import": "error",
1624
+ // React hooks rules
1625
+ "react-hooks/rules-of-hooks": "error",
1626
+ "react-hooks/exhaustive-deps": "warn",
1627
+ // React Compiler rules
1628
+ ...reactCompiler ? {
1629
+ "react-hooks/config": "error",
1630
+ "react-hooks/error-boundaries": "error",
1631
+ "react-hooks/component-hook-factories": "error",
1632
+ "react-hooks/gating": "error",
1633
+ "react-hooks/globals": "error",
1634
+ "react-hooks/immutability": "error",
1635
+ "react-hooks/preserve-manual-memoization": "error",
1636
+ "react-hooks/purity": "error",
1637
+ "react-hooks/refs": "error",
1638
+ "react-hooks/set-state-in-effect": "error",
1639
+ "react-hooks/set-state-in-render": "error",
1640
+ "react-hooks/static-components": "error",
1641
+ "react-hooks/unsupported-syntax": "warn",
1642
+ "react-hooks/use-memo": "error",
1643
+ "react-hooks/incompatible-library": "warn"
1644
+ } : {},
1446
1645
  // React Refresh rules
1447
- ...refreshPlugin && {
1448
- "react-refresh/only-export-components": [
1449
- "warn",
1450
- {
1451
- allowConstantExport: true,
1452
- allowExportNames: ["loader", "meta", "headers"]
1453
- }
1454
- ]
1455
- },
1456
- // React Compiler
1457
- ...reactCompiler && {
1458
- "react-compiler/react-compiler": "error"
1459
- },
1646
+ "react-refresh/only-export-components": [
1647
+ "error",
1648
+ {
1649
+ allowConstantExport: isAllowConstantExport,
1650
+ allowExportNames: [
1651
+ ...isUsingNext ? [
1652
+ "dynamic",
1653
+ "dynamicParams",
1654
+ "revalidate",
1655
+ "fetchCache",
1656
+ "runtime",
1657
+ "preferredRegion",
1658
+ "maxDuration",
1659
+ "generateStaticParams",
1660
+ "metadata",
1661
+ "generateMetadata",
1662
+ "viewport",
1663
+ "generateViewport",
1664
+ "generateImageMetadata",
1665
+ "generateSitemaps"
1666
+ ] : [],
1667
+ ...isUsingRemix || isUsingReactRouter ? [
1668
+ "meta",
1669
+ "links",
1670
+ "headers",
1671
+ "loader",
1672
+ "action",
1673
+ "clientLoader",
1674
+ "clientAction",
1675
+ "handle",
1676
+ "shouldRevalidate"
1677
+ ] : []
1678
+ ]
1679
+ }
1680
+ ],
1460
1681
  // User overrides
1461
1682
  ...overrides
1462
- },
1463
- settings: {
1464
- react: {
1465
- version: "detect"
1466
- }
1683
+ }
1684
+ },
1685
+ {
1686
+ files: filesTypeAware,
1687
+ name: "eslint-sets/react/typescript",
1688
+ rules: {
1689
+ // Disables rules that are already handled by TypeScript
1690
+ "react-dom/no-string-style-prop": "off",
1691
+ "react-dom/no-unknown-property": "off"
1467
1692
  }
1468
1693
  }
1469
1694
  ];
1695
+ if (isTypeAware) {
1696
+ configs.push({
1697
+ files: filesTypeAware,
1698
+ ignores: ignoresTypeAware,
1699
+ name: "eslint-sets/react/type-aware",
1700
+ rules: typeAwareRules
1701
+ });
1702
+ }
1470
1703
  return configs;
1471
1704
  }
1472
1705
 
@@ -1752,134 +1985,56 @@ async function sortTsconfig(options = {}) {
1752
1985
  // src/configs/stylistic.ts
1753
1986
  import stylisticPlugin from "@stylistic/eslint-plugin";
1754
1987
  var StylisticConfigDefaults = {
1755
- arrowParens: false,
1756
- braceStyle: "1tbs",
1757
- bracketSpacing: true,
1988
+ experimental: false,
1758
1989
  indent: 2,
1759
1990
  jsx: true,
1760
- jsxQuotes: "prefer-double",
1761
- quoteProps: "as-needed",
1991
+ lessOpinionated: false,
1762
1992
  quotes: "single",
1763
- semi: false,
1764
- trailingComma: "always-multiline"
1993
+ semi: false
1765
1994
  };
1766
1995
  function stylistic(options = {}) {
1767
1996
  const {
1768
- arrowParens,
1769
- braceStyle,
1770
- bracketSpacing,
1997
+ experimental,
1771
1998
  indent,
1772
- jsx,
1773
- jsxQuotes,
1999
+ jsx: jsx2,
2000
+ lessOpinionated = false,
1774
2001
  overrides = {},
1775
- quoteProps,
1776
2002
  quotes,
1777
- semi,
1778
- trailingComma
2003
+ semi
1779
2004
  } = {
1780
2005
  ...StylisticConfigDefaults,
1781
2006
  ...options
1782
2007
  };
1783
2008
  const config2 = stylisticPlugin.configs.customize({
1784
- arrowParens,
1785
- blockSpacing: true,
1786
- braceStyle,
1787
- commaDangle: trailingComma,
1788
- indent: indent === "tab" ? 2 : indent,
1789
- jsx,
1790
- pluginName: "@stylistic",
1791
- quoteProps,
2009
+ experimental,
2010
+ indent,
2011
+ jsx: jsx2,
2012
+ pluginName: "style",
1792
2013
  quotes,
1793
2014
  semi
1794
2015
  });
1795
- const indentStyle = indent === "tab" ? "tab" : indent;
1796
2016
  return [
1797
2017
  {
1798
2018
  files: [GLOB_SRC],
1799
2019
  name: "eslint-sets/stylistic",
1800
2020
  plugins: {
1801
- "@stylistic": stylisticPlugin
2021
+ style: stylisticPlugin
1802
2022
  },
1803
2023
  rules: {
1804
2024
  // Base rules from customize
1805
2025
  ...config2.rules,
1806
- // Override with custom settings
1807
- "@stylistic/arrow-parens": ["error", arrowParens ? "always" : "as-needed", { requireForBlockBody: false }],
1808
- "@stylistic/brace-style": ["error", braceStyle, { allowSingleLine: true }],
1809
- // Additional rules not covered by customize
1810
- "@stylistic/curly-newline": "off",
1811
- "@stylistic/function-call-spacing": ["error", "never"],
1812
- "@stylistic/indent": [
1813
- "error",
1814
- indentStyle,
1815
- {
1816
- ignoredNodes: ["TemplateLiteral"],
1817
- SwitchCase: 1
1818
- }
1819
- ],
1820
- "@stylistic/jsx-curly-brace-presence": ["error", { children: "never", props: "never" }],
1821
- "@stylistic/jsx-curly-newline": [
1822
- "error",
1823
- { multiline: "consistent", singleline: "consistent" }
1824
- ],
1825
- "@stylistic/jsx-curly-spacing": ["error", { attributes: true, children: true }],
1826
- // Note: jsx-indent and jsx-indent-props are deprecated in v5, use indent instead
1827
- "@stylistic/jsx-newline": "off",
1828
- "@stylistic/jsx-one-expression-per-line": ["error", { allow: "literal" }],
1829
- "@stylistic/jsx-pascal-case": "off",
1830
- "@stylistic/jsx-quotes": ["error", jsxQuotes],
1831
- "@stylistic/jsx-self-closing-comp": "error",
1832
- "@stylistic/jsx-sort-props": "off",
1833
- "@stylistic/jsx-tag-spacing": ["error", { beforeSelfClosing: "always" }],
1834
- "@stylistic/jsx-wrap-multilines": "off",
1835
- "@stylistic/linebreak-style": "off",
1836
- "@stylistic/member-delimiter-style": [
1837
- "error",
1838
- {
1839
- multiline: { delimiter: "none", requireLast: false },
1840
- singleline: { delimiter: "semi", requireLast: false }
1841
- }
1842
- ],
1843
- "@stylistic/multiline-ternary": ["error", "never"],
1844
- "@stylistic/newline-per-chained-call": ["error", { ignoreChainWithDepth: 4 }],
1845
- "@stylistic/no-mixed-operators": ["error", {
1846
- allowSamePrecedence: true,
1847
- groups: [
1848
- ["==", "!=", "===", "!==", ">", ">=", "<", "<="],
1849
- ["&&", "||"],
1850
- ["in", "instanceof"]
1851
- ]
1852
- }],
1853
- "@stylistic/no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
1854
- "@stylistic/no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }],
1855
- "@stylistic/no-tabs": indent === "tab" ? "off" : "error",
1856
- "@stylistic/no-trailing-spaces": "error",
1857
- "@stylistic/object-curly-spacing": ["error", bracketSpacing ? "always" : "never"],
1858
- "@stylistic/operator-linebreak": ["error", "after", {
1859
- overrides: {
1860
- "&": "before",
1861
- // Intersection type: ampersand at beginning of line
1862
- // ':': 'before', // Ternary operator: colon at beginning of line
1863
- // '?': 'before', // Ternary operator: question mark at beginning of line
1864
- "|": "before"
1865
- // Union type: pipe at beginning of line
1866
- }
1867
- }],
1868
- "@stylistic/padding-line-between-statements": [
1869
- "error",
1870
- { blankLine: "always", next: "return", prev: "*" },
1871
- { blankLine: "always", next: "*", prev: ["const", "let", "var"] },
1872
- { blankLine: "any", next: ["const", "let", "var"], prev: ["const", "let", "var"] }
1873
- ],
1874
- "@stylistic/space-before-function-paren": [
1875
- "error",
1876
- {
1877
- anonymous: "always",
1878
- asyncArrow: "always",
1879
- named: "never"
1880
- }
1881
- ],
1882
- "@stylistic/type-annotation-spacing": "error",
2026
+ // arrow-parens: omit parens for single argument
2027
+ "style/arrow-parens": ["error", "as-needed"],
2028
+ // brace-style: use 1tbs (else on same line)
2029
+ "style/brace-style": ["error", "1tbs", { allowSingleLine: true }],
2030
+ // Generator and yield star spacing
2031
+ "style/generator-star-spacing": ["error", { after: true, before: false }],
2032
+ "style/multiline-ternary": ["error", "never"],
2033
+ "style/yield-star-spacing": ["error", { after: true, before: false }],
2034
+ // Less opinionated mode uses basic curly rule
2035
+ ...lessOpinionated ? {
2036
+ curly: ["error", "all"]
2037
+ } : {},
1883
2038
  // User overrides
1884
2039
  ...overrides
1885
2040
  }
@@ -1940,93 +2095,65 @@ async function svelte(options = {}) {
1940
2095
 
1941
2096
  // src/configs/test.ts
1942
2097
  import vitest from "@vitest/eslint-plugin";
1943
- function test(options = {}) {
1944
- const { overrides = {} } = options;
2098
+ function renameVitestRules(rules) {
2099
+ const result = {};
2100
+ for (const [key, value] of Object.entries(rules)) {
2101
+ const newKey = key.replace(/^vitest\//, "test/");
2102
+ result[newKey] = value;
2103
+ }
2104
+ return result;
2105
+ }
2106
+ function createTestPlugin(vitestPlugin, noOnlyTestsPlugin) {
2107
+ const rules = {};
2108
+ for (const [name, rule] of Object.entries(vitestPlugin.rules || {})) {
2109
+ rules[name] = rule;
2110
+ }
2111
+ if (noOnlyTestsPlugin?.rules) {
2112
+ for (const [name, rule] of Object.entries(noOnlyTestsPlugin.rules)) {
2113
+ rules[name] = rule;
2114
+ }
2115
+ }
1945
2116
  return {
1946
- files: [GLOB_TESTS],
1947
- name: "eslint-sets/test",
1948
- plugins: {
1949
- vitest
2117
+ meta: {
2118
+ name: "eslint-sets/test-plugin",
2119
+ version: "1.0.0"
1950
2120
  },
1951
- rules: {
1952
- ...vitest.configs.recommended.rules,
1953
- // Relax rules for test files
1954
- "no-console": "off",
1955
- "ts/no-explicit-any": "off",
1956
- "ts/no-non-null-assertion": "off",
1957
- "ts/no-unsafe-assignment": "off",
1958
- "ts/no-unsafe-call": "off",
1959
- "ts/no-unsafe-member-access": "off",
1960
- "ts/no-unsafe-return": "off",
1961
- // Vitest rules
1962
- "vitest/consistent-test-it": [
1963
- "error",
1964
- {
1965
- fn: "it"
1966
- }
1967
- ],
1968
- "vitest/expect-expect": "off",
1969
- "vitest/max-expects": "off",
1970
- "vitest/max-nested-describe": "off",
1971
- "vitest/no-alias-methods": "error",
1972
- "vitest/no-commented-out-tests": "warn",
1973
- "vitest/no-conditional-expect": "warn",
1974
- "vitest/no-conditional-in-test": "error",
1975
- "vitest/no-conditional-tests": "warn",
1976
- "vitest/no-disabled-tests": "warn",
1977
- "vitest/no-done-callback": "error",
1978
- "vitest/no-duplicate-hooks": "error",
1979
- "vitest/no-focused-tests": "error",
1980
- "vitest/no-hooks": "off",
1981
- "vitest/no-identical-title": "error",
1982
- "vitest/no-import-node-test": "error",
1983
- "vitest/no-interpolation-in-snapshots": "error",
1984
- "vitest/no-large-snapshots": "off",
1985
- "vitest/no-mocks-import": "error",
1986
- "vitest/no-restricted-matchers": "off",
1987
- "vitest/no-restricted-vi-methods": "off",
1988
- "vitest/no-standalone-expect": "error",
1989
- "vitest/no-test-prefixes": "error",
1990
- "vitest/no-test-return-statement": "error",
1991
- "vitest/padding-around-after-all-blocks": "off",
1992
- "vitest/padding-around-after-each-blocks": "off",
1993
- "vitest/padding-around-before-all-blocks": "off",
1994
- "vitest/padding-around-before-each-blocks": "off",
1995
- "vitest/padding-around-describe-blocks": "off",
1996
- "vitest/padding-around-test-blocks": "off",
1997
- "vitest/prefer-called-with": "off",
1998
- "vitest/prefer-comparison-matcher": "error",
1999
- "vitest/prefer-each": "error",
2000
- "vitest/prefer-equality-matcher": "error",
2001
- "vitest/prefer-expect-assertions": "off",
2002
- "vitest/prefer-expect-resolves": "error",
2003
- "vitest/prefer-hooks-in-order": "error",
2004
- "vitest/prefer-hooks-on-top": "error",
2005
- "vitest/prefer-lowercase-title": "off",
2006
- "vitest/prefer-mock-promise-shorthand": "error",
2007
- "vitest/prefer-snapshot-hint": "off",
2008
- "vitest/prefer-spy-on": "off",
2009
- "vitest/prefer-strict-boolean-matchers": "off",
2010
- "vitest/prefer-strict-equal": "off",
2011
- "vitest/prefer-to-be": "error",
2012
- "vitest/prefer-to-be-falsy": "error",
2013
- "vitest/prefer-to-be-object": "error",
2014
- "vitest/prefer-to-be-truthy": "error",
2015
- "vitest/prefer-to-contain": "error",
2016
- "vitest/prefer-to-have-length": "error",
2017
- "vitest/prefer-todo": "warn",
2018
- "vitest/require-hook": "off",
2019
- "vitest/require-local-test-context-for-concurrent-snapshots": "error",
2020
- "vitest/require-to-throw-message": "off",
2021
- "vitest/require-top-level-describe": "off",
2022
- "vitest/valid-describe-callback": "error",
2023
- "vitest/valid-expect": "error",
2024
- "vitest/valid-title": "error",
2025
- // User overrides
2026
- ...overrides
2027
- }
2121
+ rules
2028
2122
  };
2029
2123
  }
2124
+ async function test(options = {}) {
2125
+ const { isInEditor = false, overrides = {} } = options;
2126
+ const noOnlyTestsPlugin = await loadPlugin("eslint-plugin-no-only-tests");
2127
+ const testPlugin = createTestPlugin(vitest, noOnlyTestsPlugin);
2128
+ const recommendedRules = renameVitestRules(vitest.configs.recommended.rules);
2129
+ return [
2130
+ {
2131
+ files: [GLOB_TESTS],
2132
+ name: "eslint-sets/test",
2133
+ plugins: {
2134
+ test: testPlugin
2135
+ },
2136
+ rules: {
2137
+ // Vitest core rules (renamed)
2138
+ ...recommendedRules,
2139
+ // Additional vitest rules
2140
+ "test/consistent-test-it": ["error", { fn: "it", withinDescribe: "it" }],
2141
+ "test/no-identical-title": "error",
2142
+ "test/no-import-node-test": "error",
2143
+ "test/prefer-hooks-in-order": "error",
2144
+ "test/prefer-lowercase-title": "error",
2145
+ // no-only-tests rule (renamed)
2146
+ "test/no-only-tests": isInEditor ? "warn" : "error",
2147
+ // Disables for test files
2148
+ "node/prefer-global/process": "off",
2149
+ "no-unused-expressions": "off",
2150
+ "ts/explicit-function-return-type": "off",
2151
+ // User overrides
2152
+ ...overrides
2153
+ }
2154
+ }
2155
+ ];
2156
+ }
2030
2157
 
2031
2158
  // src/configs/toml.ts
2032
2159
  import tomlPlugin from "eslint-plugin-toml";
@@ -2051,6 +2178,8 @@ function toml(options = {}) {
2051
2178
  toml: tomlPlugin
2052
2179
  },
2053
2180
  rules: {
2181
+ // Disable style/spaced-comment for TOML files
2182
+ "style/spaced-comment": "off",
2054
2183
  // TOML core rules (always enabled)
2055
2184
  "toml/comma-style": "error",
2056
2185
  "toml/keys-order": "error",
@@ -2059,6 +2188,8 @@ function toml(options = {}) {
2059
2188
  "toml/precision-of-fractional-seconds": "error",
2060
2189
  "toml/precision-of-integer": "error",
2061
2190
  "toml/tables-order": "error",
2191
+ // Vue custom block
2192
+ "toml/vue-custom-block/no-parsing-error": "error",
2062
2193
  // Stylistic rules (conditional)
2063
2194
  ...stylistic2 ? {
2064
2195
  "toml/array-bracket-newline": "error",
@@ -2167,7 +2298,9 @@ async function typescript(options = {}) {
2167
2298
  prefer: "type-imports"
2168
2299
  }],
2169
2300
  "ts/method-signature-style": ["error", "property"],
2301
+ "ts/no-dupe-class-members": "error",
2170
2302
  "ts/no-dynamic-delete": "off",
2303
+ "ts/no-empty-object-type": ["error", { allowInterfaces: "always" }],
2171
2304
  "ts/no-explicit-any": "off",
2172
2305
  "ts/no-extraneous-class": "off",
2173
2306
  "ts/no-import-type-side-effects": "error",
@@ -2232,7 +2365,7 @@ async function typescript(options = {}) {
2232
2365
  name: "eslint-sets/typescript/disables/dts",
2233
2366
  rules: {
2234
2367
  "eslint-comments/no-unlimited-disable": "off",
2235
- "import-x/no-duplicates": "off",
2368
+ "import/no-duplicates": "off",
2236
2369
  "no-restricted-syntax": "off",
2237
2370
  "unused-imports/no-unused-vars": "off"
2238
2371
  }
@@ -2273,11 +2406,9 @@ function unicorn(options = {}) {
2273
2406
  "unicorn/error-message": "error",
2274
2407
  "unicorn/escape-case": "error",
2275
2408
  "unicorn/new-for-builtins": "error",
2276
- "unicorn/no-instanceof-array": "error",
2277
2409
  "unicorn/no-new-array": "error",
2278
2410
  "unicorn/no-new-buffer": "error",
2279
2411
  "unicorn/number-literal-case": "error",
2280
- "unicorn/prefer-array-find": "error",
2281
2412
  "unicorn/prefer-dom-node-text-content": "error",
2282
2413
  "unicorn/prefer-includes": "error",
2283
2414
  "unicorn/prefer-node-protocol": "error",
@@ -2344,12 +2475,15 @@ async function vue(options = {}) {
2344
2475
  const {
2345
2476
  a11y = false,
2346
2477
  overrides = {},
2478
+ sfcBlocks = false,
2347
2479
  stylistic: stylistic2 = true,
2348
2480
  vueVersion = 3
2349
2481
  } = options;
2350
2482
  const {
2351
2483
  indent = 2
2352
2484
  } = typeof stylistic2 === "boolean" ? {} : stylistic2;
2485
+ const vueA11yPlugin = a11y ? await loadPlugin("eslint-plugin-vuejs-accessibility") : null;
2486
+ const vueBlocksProcessor = sfcBlocks ? await loadPlugin("eslint-processor-vue-blocks") : null;
2353
2487
  const vueRecommendedRules = vueVersion === 2 ? {
2354
2488
  ...vuePlugin.configs["flat/vue2-essential"]?.rules || {},
2355
2489
  ...vuePlugin.configs["flat/vue2-strongly-recommended"]?.rules || {},
@@ -2359,10 +2493,85 @@ async function vue(options = {}) {
2359
2493
  ...vuePlugin.configs["flat/strongly-recommended"]?.rules || {},
2360
2494
  ...vuePlugin.configs["flat/recommended"]?.rules || {}
2361
2495
  };
2362
- const configs = [
2496
+ const configs = [];
2497
+ if (vueBlocksProcessor && typeof sfcBlocks !== "boolean") {
2498
+ const processorOptions = typeof sfcBlocks === "object" ? sfcBlocks : {};
2499
+ configs.push({
2500
+ files: [GLOB_VUE],
2501
+ name: "eslint-sets/vue/sfc-blocks",
2502
+ processor: vueBlocksProcessor.default({
2503
+ blocks: {
2504
+ styles: processorOptions.styles ?? true,
2505
+ customBlocks: processorOptions.customBlocks ?? false
2506
+ }
2507
+ })
2508
+ });
2509
+ } else if (vueBlocksProcessor) {
2510
+ configs.push({
2511
+ files: [GLOB_VUE],
2512
+ name: "eslint-sets/vue/sfc-blocks",
2513
+ processor: vueBlocksProcessor.default({
2514
+ blocks: {
2515
+ styles: true,
2516
+ customBlocks: false
2517
+ }
2518
+ })
2519
+ });
2520
+ }
2521
+ configs.push(
2363
2522
  {
2364
2523
  files: [GLOB_VUE],
2365
2524
  languageOptions: {
2525
+ globals: vueVersion === 3 ? {
2526
+ // Vue 3 global APIs
2527
+ computed: "readonly",
2528
+ defineComponent: "readonly",
2529
+ effectScope: "readonly",
2530
+ getCurrentInstance: "readonly",
2531
+ inject: "readonly",
2532
+ isProxy: "readonly",
2533
+ isReactive: "readonly",
2534
+ isReadonly: "readonly",
2535
+ isRef: "readonly",
2536
+ markRaw: "readonly",
2537
+ onActivated: "readonly",
2538
+ onBeforeMount: "readonly",
2539
+ onBeforeUnmount: "readonly",
2540
+ onBeforeUpdate: "readonly",
2541
+ onDeactivated: "readonly",
2542
+ onErrorCaptured: "readonly",
2543
+ onMounted: "readonly",
2544
+ onRenderTracked: "readonly",
2545
+ onRenderTriggered: "readonly",
2546
+ onScopeDispose: "readonly",
2547
+ onServerPrefetch: "readonly",
2548
+ onUnmounted: "readonly",
2549
+ onUpdated: "readonly",
2550
+ provide: "readonly",
2551
+ reactive: "readonly",
2552
+ readonly: "readonly",
2553
+ ref: "readonly",
2554
+ resolveComponent: "readonly",
2555
+ resolveDirective: "readonly",
2556
+ shallowReactive: "readonly",
2557
+ shallowReadonly: "readonly",
2558
+ shallowRef: "readonly",
2559
+ toRaw: "readonly",
2560
+ toRef: "readonly",
2561
+ toRefs: "readonly",
2562
+ triggerRef: "readonly",
2563
+ unref: "readonly",
2564
+ useAttrs: "readonly",
2565
+ useCssModule: "readonly",
2566
+ useCssVars: "readonly",
2567
+ useRoute: "readonly",
2568
+ useRouter: "readonly",
2569
+ useSlots: "readonly",
2570
+ watch: "readonly",
2571
+ watchEffect: "readonly",
2572
+ watchPostEffect: "readonly",
2573
+ watchSyncEffect: "readonly"
2574
+ } : {},
2366
2575
  parser: vueParser,
2367
2576
  parserOptions: {
2368
2577
  ecmaFeatures: {
@@ -2376,7 +2585,8 @@ async function vue(options = {}) {
2376
2585
  },
2377
2586
  name: "eslint-sets/vue",
2378
2587
  plugins: {
2379
- vue: vuePlugin
2588
+ vue: vuePlugin,
2589
+ ...vueA11yPlugin ? { "vue-a11y": vueA11yPlugin } : {}
2380
2590
  },
2381
2591
  rules: {
2382
2592
  // Vue recommended rules
@@ -2395,12 +2605,19 @@ async function vue(options = {}) {
2395
2605
  "vue/no-empty-pattern": "error",
2396
2606
  "vue/no-irregular-whitespace": "error",
2397
2607
  "vue/no-loss-of-precision": "error",
2608
+ "vue/no-restricted-syntax": [
2609
+ "error",
2610
+ "DebuggerStatement",
2611
+ "LabeledStatement",
2612
+ "WithStatement"
2613
+ ],
2398
2614
  "vue/no-restricted-v-bind": ["error", "/^v-/"],
2399
2615
  "vue/no-setup-props-reactivity-loss": "off",
2400
2616
  "vue/no-sparse-arrays": "error",
2401
2617
  "vue/no-unused-refs": "error",
2402
2618
  "vue/no-useless-v-bind": "error",
2403
2619
  "vue/no-v-html": "off",
2620
+ "vue/object-shorthand": ["error", "always", { avoidQuotes: true, ignoreConstructors: false }],
2404
2621
  "vue/prefer-separate-static-class": "error",
2405
2622
  "vue/prefer-template": "error",
2406
2623
  "vue/prop-name-casing": ["error", "camelCase"],
@@ -2414,10 +2631,11 @@ async function vue(options = {}) {
2414
2631
  "vue/arrow-spacing": ["error", { after: true, before: true }],
2415
2632
  "vue/block-spacing": ["error", "always"],
2416
2633
  "vue/block-tag-newline": ["error", { multiline: "always", singleline: "always" }],
2417
- "vue/brace-style": ["error", "stroustrup", { allowSingleLine: true }],
2634
+ "vue/brace-style": ["error", "1tbs", { allowSingleLine: true }],
2418
2635
  "vue/comma-dangle": ["error", "always-multiline"],
2419
2636
  "vue/comma-spacing": ["error", { after: true, before: false }],
2420
2637
  "vue/comma-style": ["error", "last"],
2638
+ "vue/html-comment-content-spacing": ["error", "always", { exceptions: ["-"] }],
2421
2639
  "vue/html-indent": ["error", indent === "tab" ? "tab" : indent],
2422
2640
  "vue/html-quotes": ["error", "double"],
2423
2641
  "vue/key-spacing": ["error", { afterColon: true, beforeColon: false }],
@@ -2429,8 +2647,6 @@ async function vue(options = {}) {
2429
2647
  "vue/operator-linebreak": ["error", "after", {
2430
2648
  overrides: {
2431
2649
  "&": "before",
2432
- // ':': 'before', // Ternary operator: colon at beginning of line
2433
- // '?': 'before', // Ternary operator: question mark at beginning of line
2434
2650
  "|": "before"
2435
2651
  }
2436
2652
  }],
@@ -2439,95 +2655,45 @@ async function vue(options = {}) {
2439
2655
  "vue/space-in-parens": ["error", "never"],
2440
2656
  "vue/template-curly-spacing": "error"
2441
2657
  } : {},
2658
+ // Vue a11y rules (conditional)
2659
+ ...vueA11yPlugin ? {
2660
+ "vue-a11y/alt-text": "error",
2661
+ "vue-a11y/anchor-has-content": "error",
2662
+ "vue-a11y/aria-props": "error",
2663
+ "vue-a11y/aria-role": "error",
2664
+ "vue-a11y/aria-unsupported-elements": "error",
2665
+ "vue-a11y/click-events-have-key-events": "error",
2666
+ "vue-a11y/form-control-has-label": "error",
2667
+ "vue-a11y/heading-has-content": "error",
2668
+ "vue-a11y/iframe-has-title": "error",
2669
+ "vue-a11y/interactive-supports-focus": "error",
2670
+ "vue-a11y/label-has-for": "error",
2671
+ "vue-a11y/media-has-caption": "warn",
2672
+ "vue-a11y/mouse-events-have-key-events": "error",
2673
+ "vue-a11y/no-access-key": "error",
2674
+ "vue-a11y/no-aria-hidden-on-focusable": "error",
2675
+ "vue-a11y/no-autofocus": "warn",
2676
+ "vue-a11y/no-distracting-elements": "error",
2677
+ "vue-a11y/no-redundant-roles": "error",
2678
+ "vue-a11y/no-role-presentation-on-focusable": "error",
2679
+ "vue-a11y/no-static-element-interactions": "error",
2680
+ "vue-a11y/role-has-required-aria-props": "error",
2681
+ "vue-a11y/tabindex-no-positive": "warn"
2682
+ } : {},
2442
2683
  // User overrides
2443
- ...overrides
2684
+ ...overrides,
2685
+ // Disable rules that are handled elsewhere
2686
+ "node/prefer-global/process": "off",
2687
+ "ts/explicit-function-return-type": "off"
2444
2688
  }
2445
2689
  }
2446
- ];
2447
- if (a11y) {
2448
- const vueA11yPlugin = await loadPlugin("eslint-plugin-vuejs-accessibility");
2449
- if (vueA11yPlugin) {
2450
- configs.push({
2451
- files: [GLOB_VUE],
2452
- name: "eslint-sets/vue/a11y",
2453
- plugins: {
2454
- "vuejs-accessibility": vueA11yPlugin
2455
- },
2456
- rules: {
2457
- // Core accessibility rules
2458
- "vuejs-accessibility/alt-text": "error",
2459
- "vuejs-accessibility/aria-label": "error",
2460
- "vuejs-accessibility/aria-props": "error",
2461
- "vuejs-accessibility/aria-role": "error",
2462
- "vuejs-accessibility/form-control-has-label": "error",
2463
- "vuejs-accessibility/html-has-lang": "error",
2464
- "vuejs-accessibility/label-has-for": "error",
2465
- "vuejs-accessibility/no-autofocus": "warn",
2466
- "vuejs-accessibility/no-redundant-roles": "error",
2467
- "vuejs-accessibility/tabindex-no-positive": "error"
2468
- }
2469
- });
2470
- }
2471
- }
2690
+ );
2472
2691
  return configs;
2473
2692
  }
2474
2693
 
2475
- // src/configs/vue-a11y.ts
2476
- async function vueA11y(options = {}) {
2477
- const { overrides = {} } = options;
2478
- const plugin = await loadPlugin("eslint-plugin-vuejs-accessibility");
2479
- if (!plugin) {
2480
- return [];
2481
- }
2482
- return [
2483
- {
2484
- files: [GLOB_VUE],
2485
- name: "eslint-sets/vue-a11y",
2486
- plugins: {
2487
- "vuejs-accessibility": plugin
2488
- },
2489
- rules: {
2490
- // Vue accessibility rules
2491
- "vuejs-accessibility/alt-text": "error",
2492
- "vuejs-accessibility/anchor-has-content": "error",
2493
- "vuejs-accessibility/aria-activedescendant-has-tabindex": "error",
2494
- "vuejs-accessibility/aria-hidden": "warn",
2495
- "vuejs-accessibility/aria-label": "error",
2496
- "vuejs-accessibility/aria-props": "error",
2497
- "vuejs-accessibility/aria-role": "error",
2498
- "vuejs-accessibility/aria-unsupported-elements": "error",
2499
- "vuejs-accessibility/click-events-have-key-events": "warn",
2500
- "vuejs-accessibility/form-control-has-label": "error",
2501
- "vuejs-accessibility/heading-has-content": "error",
2502
- "vuejs-accessibility/html-has-lang": "error",
2503
- "vuejs-accessibility/iframe-has-title": "error",
2504
- "vuejs-accessibility/interactive-supports-focus": "error",
2505
- "vuejs-accessibility/label-has-for": "error",
2506
- "vuejs-accessibility/lang": "error",
2507
- "vuejs-accessibility/media-has-caption": "warn",
2508
- "vuejs-accessibility/mouse-events-have-key-events": "error",
2509
- "vuejs-accessibility/no-access-key": "error",
2510
- "vuejs-accessibility/no-autofocus": "warn",
2511
- "vuejs-accessibility/no-distracting-elements": "warn",
2512
- "vuejs-accessibility/no-onchange": "off",
2513
- "vuejs-accessibility/no-redundant-roles": "error",
2514
- "vuejs-accessibility/no-static-element-interactions": "warn",
2515
- "vuejs-accessibility/role-has-required-aria-props": "error",
2516
- "vuejs-accessibility/role-supports-aria-props": "error",
2517
- "vuejs-accessibility/scope": "error",
2518
- "vuejs-accessibility/tabindex-no-positive": "error",
2519
- "vuejs-accessibility/video-has-caption": "warn",
2520
- // User overrides
2521
- ...overrides
2522
- }
2523
- }
2524
- ];
2525
- }
2526
-
2527
2694
  // src/configs/yaml.ts
2528
- import ymlPlugin, { configs as ymlConfigs } from "eslint-plugin-yml";
2695
+ import ymlPlugin from "eslint-plugin-yml";
2529
2696
  import yamlParser from "yaml-eslint-parser";
2530
- var ymlStandardRules = ymlConfigs?.standard?.rules || {};
2531
2697
  function yaml(options = {}) {
2532
2698
  const {
2533
2699
  overrides = {},
@@ -2535,7 +2701,7 @@ function yaml(options = {}) {
2535
2701
  } = options;
2536
2702
  const {
2537
2703
  indent = 2,
2538
- quotes = "double"
2704
+ quotes = "single"
2539
2705
  } = typeof stylistic2 === "boolean" ? {} : stylistic2;
2540
2706
  return [
2541
2707
  {
@@ -2545,39 +2711,40 @@ function yaml(options = {}) {
2545
2711
  },
2546
2712
  name: "eslint-sets/yaml",
2547
2713
  plugins: {
2548
- yml: ymlPlugin
2714
+ yaml: ymlPlugin
2549
2715
  },
2550
2716
  rules: {
2551
- ...ymlStandardRules,
2717
+ "style/spaced-comment": "off",
2718
+ // Disable file-extension rule
2719
+ "yml/file-extension": "off",
2552
2720
  // YAML core rules (always enabled)
2553
- "yml/block-mapping": "error",
2554
- "yml/block-sequence": "error",
2555
- "yml/file-extension": ["error", { extension: "yml" }],
2556
- "yml/key-name-casing": "off",
2557
- "yml/no-empty-document": "error",
2558
- "yml/no-empty-key": "error",
2559
- "yml/no-empty-mapping-value": "error",
2560
- "yml/no-empty-sequence-entry": "error",
2561
- "yml/no-irregular-whitespace": "error",
2562
- "yml/plain-scalar": "error",
2563
- "yml/require-string-key": "error",
2564
- "yml/sort-keys": "off",
2565
- "yml/sort-sequence-values": "off",
2721
+ "yaml/block-mapping": "error",
2722
+ "yaml/block-sequence": "error",
2723
+ "yaml/no-empty-key": "error",
2724
+ "yaml/no-empty-sequence-entry": "error",
2725
+ "yaml/no-irregular-whitespace": "error",
2726
+ "yaml/plain-scalar": "error",
2727
+ // Vue custom block
2728
+ "yaml/vue-custom-block/no-parsing-error": "error",
2566
2729
  // Stylistic rules (conditional)
2567
2730
  ...stylistic2 ? {
2568
- // yml/indent only accepts integer values, not "tab"
2569
- // When using tabs, disable indent rule and no-tab-indent
2731
+ "yaml/block-mapping-question-indicator-newline": "error",
2732
+ "yaml/block-sequence-hyphen-indicator-newline": "error",
2733
+ "yaml/flow-mapping-curly-newline": "error",
2734
+ "yaml/flow-mapping-curly-spacing": "error",
2735
+ "yaml/flow-sequence-bracket-newline": "error",
2736
+ "yaml/flow-sequence-bracket-spacing": "error",
2737
+ // yaml/indent only accepts integer values, not "tab"
2570
2738
  ...indent === "tab" ? {
2571
- "yml/indent": "off",
2572
- "yml/no-tab-indent": "off"
2739
+ "yaml/indent": "off",
2740
+ "yaml/no-tab-indent": "off"
2573
2741
  } : {
2574
- "yml/indent": ["error", indent],
2575
- "yml/no-tab-indent": "error"
2742
+ "yaml/indent": ["error", indent],
2743
+ "yaml/no-tab-indent": "error"
2576
2744
  },
2577
- "yml/key-spacing": "error",
2578
- "yml/no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }],
2579
- "yml/quotes": ["error", { avoidEscape: true, prefer: quotes }],
2580
- "yml/spaced-comment": "error"
2745
+ "yaml/key-spacing": "error",
2746
+ "yaml/quotes": ["error", { avoidEscape: true, prefer: quotes }],
2747
+ "yaml/spaced-comment": "error"
2581
2748
  } : {},
2582
2749
  // User overrides
2583
2750
  ...overrides
@@ -2610,17 +2777,17 @@ async function config(options = {}) {
2610
2777
  astro: astroOption = "auto",
2611
2778
  autoDetect = true,
2612
2779
  command: commandOption = true,
2780
+ comments: commentsOption = true,
2613
2781
  disables: disablesOption = true,
2614
- e18e: e18eOption = false,
2615
- eslintComments: eslintCommentsOption = true,
2616
2782
  extends: extendConfigs = [],
2617
2783
  formatters: formattersOption = false,
2618
2784
  gitignore: gitignoreOption = true,
2619
2785
  ignores: ignorePatterns,
2620
2786
  imports: importsOption = true,
2621
2787
  isInEditor,
2788
+ jsdoc: jsdocOption = true,
2622
2789
  jsonc: jsoncOption = true,
2623
- jsxA11y: jsxA11yOption = false,
2790
+ jsx: jsxOption = false,
2624
2791
  markdown: markdownOption = true,
2625
2792
  nextjs: nextjsOption = "auto",
2626
2793
  node: nodeOption = true,
@@ -2646,9 +2813,6 @@ async function config(options = {}) {
2646
2813
  yaml: yamlOption = true
2647
2814
  } = options;
2648
2815
  const inEditor = isInEditor ?? isInEditorEnv();
2649
- if (inEditor) {
2650
- console.info("[@eslint-sets/eslint-config] Detected running in editor, some rules are disabled.");
2651
- }
2652
2816
  const configs = [];
2653
2817
  const allIgnores = processIgnores(ignorePatterns);
2654
2818
  if (gitignoreOption) {
@@ -2681,6 +2845,10 @@ async function config(options = {}) {
2681
2845
  reactOpts.overrides = getOverrides(options, "react");
2682
2846
  configs.push(...await react(reactOpts));
2683
2847
  }
2848
+ if (jsxOption !== false) {
2849
+ const jsxOpts = typeof jsxOption === "object" ? jsxOption : {};
2850
+ configs.push(...await jsx(jsxOpts));
2851
+ }
2684
2852
  if (isEnabled(svelteOption) || isAutoDetect(svelteOption) && autoDetect && hasSvelte()) {
2685
2853
  configs.push(...await svelte());
2686
2854
  }
@@ -2749,20 +2917,22 @@ async function config(options = {}) {
2749
2917
  }
2750
2918
  if (testOption !== false) {
2751
2919
  const testOpts = typeof testOption === "object" ? testOption : {};
2752
- configs.push(test(testOpts));
2753
- configs.push(...await noOnlyTests());
2920
+ configs.push(...await test({ ...testOpts, isInEditor: inEditor }));
2754
2921
  }
2755
2922
  if (nodeOption !== false) {
2756
2923
  configs.push(...node());
2757
2924
  }
2758
- if (eslintCommentsOption !== false) {
2759
- configs.push(...await eslintComments());
2925
+ if (commentsOption !== false) {
2926
+ configs.push(...await comments());
2927
+ }
2928
+ if (jsdocOption !== false) {
2929
+ configs.push(...await jsdoc(typeof jsdocOption === "object" ? jsdocOption : {}));
2760
2930
  }
2761
2931
  if (disablesOption !== false) {
2762
2932
  configs.push(...disables());
2763
2933
  }
2764
2934
  if (commandOption !== false) {
2765
- configs.push(...command());
2935
+ configs.push(...await command());
2766
2936
  }
2767
2937
  if (sortPackageJsonOption !== false) {
2768
2938
  configs.push(...await sortPackageJson());
@@ -2770,23 +2940,24 @@ async function config(options = {}) {
2770
2940
  if (sortTsconfigOption !== false) {
2771
2941
  configs.push(...await sortTsconfig());
2772
2942
  }
2773
- if (jsxA11yOption && !(isEnabled(reactOption) || isAutoDetect(reactOption) && autoDetect && hasReact())) {
2774
- configs.push(...await jsxA11y());
2775
- }
2776
2943
  if (isEnabled(unocssOption) || isAutoDetect(unocssOption) && autoDetect && hasUnoCSS()) {
2777
2944
  configs.push(
2778
2945
  ...await unocss(resolveOptionsOverrides(options, "unocss"))
2779
2946
  );
2780
2947
  }
2781
- if (e18eOption !== false && e18eOption !== void 0) {
2782
- configs.push(...await e18e(typeof e18eOption === "object" ? e18eOption : {}));
2783
- }
2784
2948
  if (pnpmOption !== false && pnpmOption !== void 0) {
2785
2949
  configs.push(...await pnpm(typeof pnpmOption === "object" ? pnpmOption : {}));
2786
2950
  }
2787
2951
  if (formattersOption !== false && formattersOption !== void 0) {
2952
+ const formattersStylistic = stylisticOption === false ? {} : {
2953
+ indent: typeof stylisticOption === "object" ? stylisticOption.indent : 2,
2954
+ quotes: typeof stylisticOption === "object" ? stylisticOption.quotes : "single"
2955
+ };
2788
2956
  configs.push(
2789
- ...await formatters(typeof formattersOption === "object" ? formattersOption : {})
2957
+ ...await formatters(
2958
+ typeof formattersOption === "object" ? formattersOption : {},
2959
+ formattersStylistic
2960
+ )
2790
2961
  );
2791
2962
  }
2792
2963
  if (stylisticOption !== false && stylisticOption !== void 0) {
@@ -2819,6 +2990,7 @@ export {
2819
2990
  EDITOR_ENV_KEYS,
2820
2991
  GLOB_ALL,
2821
2992
  GLOB_ASTRO,
2993
+ GLOB_ASTRO_TS,
2822
2994
  GLOB_COMMAND_FILES,
2823
2995
  GLOB_CONFIG_FILES,
2824
2996
  GLOB_EXCLUDES,
@@ -2827,9 +2999,13 @@ export {
2827
2999
  GLOB_JSON,
2828
3000
  GLOB_JSON5,
2829
3001
  GLOB_JSONC,
3002
+ GLOB_JSX,
2830
3003
  GLOB_MD,
3004
+ GLOB_MD_CODE,
3005
+ GLOB_MD_IN_MD,
2831
3006
  GLOB_REACT,
2832
3007
  GLOB_SRC,
3008
+ GLOB_SRC_EXT,
2833
3009
  GLOB_SVELTE,
2834
3010
  GLOB_TESTS,
2835
3011
  GLOB_TS,
@@ -2839,20 +3015,22 @@ export {
2839
3015
  NEXTJS_PACKAGES,
2840
3016
  NUXT_PACKAGES,
2841
3017
  REACT_COMPILER_PACKAGES,
3018
+ REACT_REFRESH_ALLOW_CONSTANT_EXPORT_PACKAGES,
3019
+ REACT_ROUTER_PACKAGES,
3020
+ REMIX_PACKAGES,
2842
3021
  UNOCSS_PACKAGES,
2843
3022
  VUE_PACKAGES,
2844
3023
  angular,
2845
3024
  astro,
2846
3025
  combine,
2847
3026
  command,
3027
+ comments,
2848
3028
  config,
2849
3029
  deepMerge,
2850
3030
  eslintConfig as default,
2851
3031
  disables,
2852
- e18e,
2853
3032
  ensureArray,
2854
3033
  ensurePackages,
2855
- eslintComments,
2856
3034
  filterNil,
2857
3035
  findGitignore,
2858
3036
  formatters,
@@ -2866,10 +3044,13 @@ export {
2866
3044
  hasPrettier,
2867
3045
  hasReact,
2868
3046
  hasReactCompiler,
3047
+ hasReactRouter,
3048
+ hasRemix,
2869
3049
  hasSolid,
2870
3050
  hasSvelte,
2871
3051
  hasTypeScript,
2872
3052
  hasUnoCSS,
3053
+ hasVite,
2873
3054
  hasVitest,
2874
3055
  hasVue,
2875
3056
  ignores,
@@ -2878,12 +3059,12 @@ export {
2878
3059
  isInEditorEnv,
2879
3060
  isObject,
2880
3061
  javascript,
3062
+ jsdoc,
2881
3063
  jsonc,
2882
- jsxA11y,
3064
+ jsx,
2883
3065
  loadPlugin,
2884
3066
  markdown,
2885
3067
  nextjs,
2886
- noOnlyTests,
2887
3068
  node,
2888
3069
  nuxt,
2889
3070
  parseGitignore,
@@ -2906,6 +3087,5 @@ export {
2906
3087
  unicorn,
2907
3088
  unocss,
2908
3089
  vue,
2909
- vueA11y,
2910
3090
  yaml
2911
3091
  };