@luxass/eslint-config 4.3.6 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -99,6 +99,7 @@ var GLOB_JSON5 = "**/*.json5";
99
99
  var GLOB_JSONC = "**/*.jsonc";
100
100
  var GLOB_MARKDOWN = "**/*.md";
101
101
  var GLOB_MARKDOWN_IN_MARKDOWN = "**/*.md/*.md";
102
+ var GLOB_SVELTE = "**/*.svelte";
102
103
  var GLOB_VUE = "**/*.vue";
103
104
  var GLOB_YAML = "**/*.y?(a)ml";
104
105
  var GLOB_TOML = "**/*.toml";
@@ -423,6 +424,172 @@ function sortTsconfig() {
423
424
  ];
424
425
  }
425
426
 
427
+ // src/utils.ts
428
+ import process from "node:process";
429
+ import { isPackageExists } from "local-pkg";
430
+ var parserPlain = {
431
+ meta: {
432
+ name: "parser-plain"
433
+ },
434
+ parseForESLint: (code) => ({
435
+ ast: {
436
+ body: [],
437
+ comments: [],
438
+ loc: { end: code.length, start: 0 },
439
+ range: [0, code.length],
440
+ tokens: [],
441
+ type: "Program"
442
+ },
443
+ scopeManager: null,
444
+ services: { isPlain: true },
445
+ visitorKeys: {
446
+ Program: []
447
+ }
448
+ })
449
+ };
450
+ async function combine(...configs) {
451
+ const resolved = await Promise.all(configs);
452
+ return resolved.flat();
453
+ }
454
+ function renameRules(rules, from, to) {
455
+ return Object.fromEntries(
456
+ Object.entries(rules).map(([key, value]) => {
457
+ if (key.startsWith(from)) {
458
+ return [to + key.slice(from.length), value];
459
+ }
460
+ return [key, value];
461
+ })
462
+ );
463
+ }
464
+ function toArray(value) {
465
+ return Array.isArray(value) ? value : [value];
466
+ }
467
+ async function interop(m) {
468
+ const resolved = await m;
469
+ return resolved.default || resolved;
470
+ }
471
+ async function ensure(packages) {
472
+ if (process.env.CI || process.stdout.isTTY === false) {
473
+ return;
474
+ }
475
+ ;
476
+ const nonExistingPackages = packages.filter((i) => i && !isPackageExists(i));
477
+ if (nonExistingPackages.length === 0) {
478
+ return;
479
+ }
480
+ const p = await import("@clack/prompts");
481
+ const result = await p.confirm({
482
+ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?`
483
+ });
484
+ if (result) {
485
+ await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
486
+ }
487
+ }
488
+ function resolveSubOptions(options, key) {
489
+ return typeof options[key] === "boolean" ? {} : options[key] || {};
490
+ }
491
+ function getOverrides(options, key) {
492
+ const sub = resolveSubOptions(options, key);
493
+ return {
494
+ ..."overrides" in sub ? sub.overrides : {}
495
+ };
496
+ }
497
+
498
+ // src/configs/svelte.ts
499
+ async function svelte(options = {}) {
500
+ const {
501
+ files = [GLOB_SVELTE],
502
+ overrides = {},
503
+ stylistic: stylistic2 = true
504
+ } = options;
505
+ const {
506
+ indent = 2,
507
+ quotes = "single"
508
+ } = typeof stylistic2 === "boolean" ? {} : stylistic2;
509
+ await ensure([
510
+ "eslint-plugin-svelte"
511
+ ]);
512
+ const [
513
+ pluginSvelte,
514
+ parserSvelte
515
+ ] = await Promise.all([
516
+ interop(import("eslint-plugin-svelte")),
517
+ interop(import("svelte-eslint-parser"))
518
+ ]);
519
+ return [
520
+ {
521
+ name: "antfu/svelte/setup",
522
+ plugins: {
523
+ svelte: pluginSvelte
524
+ }
525
+ },
526
+ {
527
+ files,
528
+ languageOptions: {
529
+ parser: parserSvelte,
530
+ parserOptions: {
531
+ extraFileExtensions: [".svelte"],
532
+ parser: options.typescript ? await interop(import("@typescript-eslint/parser")) : null
533
+ }
534
+ },
535
+ name: "antfu/svelte/rules",
536
+ processor: pluginSvelte.processors[".svelte"],
537
+ rules: {
538
+ "import/no-mutable-exports": "off",
539
+ "no-undef": "off",
540
+ // incompatible with most recent (attribute-form) generic types RFC
541
+ "no-unused-vars": ["error", {
542
+ args: "none",
543
+ caughtErrors: "none",
544
+ ignoreRestSiblings: true,
545
+ vars: "all",
546
+ varsIgnorePattern: "^(\\$\\$Props$|\\$\\$Events$|\\$\\$Slots$)"
547
+ }],
548
+ "svelte/comment-directive": "error",
549
+ "svelte/no-at-debug-tags": "warn",
550
+ "svelte/no-at-html-tags": "error",
551
+ "svelte/no-dupe-else-if-blocks": "error",
552
+ "svelte/no-dupe-style-properties": "error",
553
+ "svelte/no-dupe-use-directives": "error",
554
+ "svelte/no-dynamic-slot-name": "error",
555
+ "svelte/no-export-load-in-svelte-module-in-kit-pages": "error",
556
+ "svelte/no-inner-declarations": "error",
557
+ "svelte/no-not-function-handler": "error",
558
+ "svelte/no-object-in-text-mustaches": "error",
559
+ "svelte/no-reactive-functions": "error",
560
+ "svelte/no-reactive-literals": "error",
561
+ "svelte/no-shorthand-style-property-overrides": "error",
562
+ "svelte/no-unknown-style-directive-property": "error",
563
+ "svelte/no-unused-svelte-ignore": "error",
564
+ "svelte/no-useless-mustaches": "error",
565
+ "svelte/require-store-callbacks-use-set-param": "error",
566
+ "svelte/system": "error",
567
+ "svelte/valid-compile": "error",
568
+ "svelte/valid-each-key": "error",
569
+ "unused-imports/no-unused-vars": [
570
+ "error",
571
+ { args: "after-used", argsIgnorePattern: "^_", vars: "all", varsIgnorePattern: "^(_|\\$\\$Props$|\\$\\$Events$|\\$\\$Slots$)" }
572
+ ],
573
+ ...stylistic2 ? {
574
+ "style/indent": "off",
575
+ // superseded by svelte/indent
576
+ "style/no-trailing-spaces": "off",
577
+ // superseded by svelte/no-trailing-spaces
578
+ "svelte/derived-has-same-inputs-outputs": "error",
579
+ "svelte/html-closing-bracket-spacing": "error",
580
+ "svelte/html-quotes": ["error", { prefer: quotes }],
581
+ "svelte/indent": ["error", { alignAttributesVertically: true, indent }],
582
+ "svelte/mustache-spacing": "error",
583
+ "svelte/no-spaces-around-equal-signs-in-attribute": "error",
584
+ "svelte/no-trailing-spaces": "error",
585
+ "svelte/spaced-html-comment": "error"
586
+ } : {},
587
+ ...overrides
588
+ }
589
+ }
590
+ ];
591
+ }
592
+
426
593
  // src/configs/imports.ts
427
594
  import pluginImport from "eslint-plugin-import-x";
428
595
  import pluginAntfu from "eslint-plugin-antfu";
@@ -722,77 +889,6 @@ async function javascript(options = {}) {
722
889
  ];
723
890
  }
724
891
 
725
- // src/utils.ts
726
- import process from "node:process";
727
- import { isPackageExists } from "local-pkg";
728
- var parserPlain = {
729
- meta: {
730
- name: "parser-plain"
731
- },
732
- parseForESLint: (code) => ({
733
- ast: {
734
- body: [],
735
- comments: [],
736
- loc: { end: code.length, start: 0 },
737
- range: [0, code.length],
738
- tokens: [],
739
- type: "Program"
740
- },
741
- scopeManager: null,
742
- services: { isPlain: true },
743
- visitorKeys: {
744
- Program: []
745
- }
746
- })
747
- };
748
- async function combine(...configs) {
749
- const resolved = await Promise.all(configs);
750
- return resolved.flat();
751
- }
752
- function renameRules(rules, from, to) {
753
- return Object.fromEntries(
754
- Object.entries(rules).map(([key, value]) => {
755
- if (key.startsWith(from)) {
756
- return [to + key.slice(from.length), value];
757
- }
758
- return [key, value];
759
- })
760
- );
761
- }
762
- function toArray(value) {
763
- return Array.isArray(value) ? value : [value];
764
- }
765
- async function interop(m) {
766
- const resolved = await m;
767
- return resolved.default || resolved;
768
- }
769
- async function ensure(packages) {
770
- if (process.env.CI || process.stdout.isTTY === false) {
771
- return;
772
- }
773
- ;
774
- const nonExistingPackages = packages.filter((i) => i && !isPackageExists(i));
775
- if (nonExistingPackages.length === 0) {
776
- return;
777
- }
778
- const p = await import("@clack/prompts");
779
- const result = await p.confirm({
780
- message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?`
781
- });
782
- if (result) {
783
- await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
784
- }
785
- }
786
- function resolveSubOptions(options, key) {
787
- return typeof options[key] === "boolean" ? {} : options[key] || {};
788
- }
789
- function getOverrides(options, key) {
790
- const sub = resolveSubOptions(options, key);
791
- return {
792
- ..."overrides" in sub ? sub.overrides : {}
793
- };
794
- }
795
-
796
892
  // src/configs/jsdoc.ts
797
893
  async function jsdoc(options = {}) {
798
894
  const {
@@ -929,7 +1025,7 @@ async function markdown(options = {}) {
929
1025
  }
930
1026
  },
931
1027
  {
932
- name: "luxass/markdown:processor",
1028
+ name: "luxass/markdown/processor",
933
1029
  files,
934
1030
  ignores: [GLOB_MARKDOWN_IN_MARKDOWN],
935
1031
  // `eslint-plugin-markdown` only creates virtual files for code blocks,
@@ -1518,6 +1614,7 @@ async function yaml(options = {}) {
1518
1614
  }
1519
1615
 
1520
1616
  // src/configs/test.ts
1617
+ var _pluginTest;
1521
1618
  async function test(options = {}) {
1522
1619
  const {
1523
1620
  editor = false,
@@ -1529,16 +1626,12 @@ async function test(options = {}) {
1529
1626
  ] = await Promise.all([
1530
1627
  interop(import("eslint-plugin-vitest"))
1531
1628
  ]);
1629
+ _pluginTest = _pluginTest || pluginVitest;
1532
1630
  return [
1533
1631
  {
1534
1632
  name: "luxass/test/setup",
1535
1633
  plugins: {
1536
- test: {
1537
- ...pluginVitest,
1538
- rules: {
1539
- ...pluginVitest.rules
1540
- }
1541
- }
1634
+ test: _pluginTest
1542
1635
  }
1543
1636
  },
1544
1637
  {
@@ -1614,35 +1707,42 @@ async function nextjs(options = {}) {
1614
1707
  {
1615
1708
  name: "luxass/nextjs/setup",
1616
1709
  plugins: {
1617
- "@next/next": pluginNextjs
1710
+ nextjs: pluginNextjs
1618
1711
  }
1619
1712
  },
1620
1713
  {
1621
1714
  name: "luxass/nextjs/rules",
1622
1715
  files,
1623
1716
  rules: {
1624
- ...pluginNextjs.configs.recommended.rules,
1625
- ...pluginNextjs.configs["core-web-vitals"].rules,
1626
- "@next/next/google-font-display": ["error"],
1627
- "@next/next/google-font-preconnect": ["error"],
1628
- "@next/next/inline-script-id": ["error"],
1629
- "@next/next/next-script-for-ga": ["warn"],
1630
- "@next/next/no-assign-module-variable": ["error"],
1631
- "@next/next/no-css-tags": ["warn"],
1632
- "@next/next/no-document-import-in-page": ["error"],
1633
- "@next/next/no-duplicate-head": ["error"],
1634
- "@next/next/no-head-element": ["warn"],
1635
- "@next/next/no-head-import-in-document": ["error"],
1636
- "@next/next/no-html-link-for-pages": ["off"],
1637
- "@next/next/no-img-element": ["warn"],
1638
- "@next/next/no-page-custom-font": ["warn"],
1639
- "@next/next/no-script-component-in-head": ["error"],
1640
- "@next/next/no-styled-jsx-in-document": ["warn"],
1641
- "@next/next/no-sync-scripts": ["warn"],
1642
- "@next/next/no-title-in-document-head": ["warn"],
1643
- "@next/next/no-typos": ["warn"],
1644
- "@next/next/no-unwanted-polyfillio": ["warn"],
1645
- // "jsx-a11y/anchor-is-valid": ["off"],
1717
+ ...renameRules(
1718
+ pluginNextjs.configs.recommended.rules,
1719
+ "@next/next/",
1720
+ "nextjs/"
1721
+ ),
1722
+ ...renameRules(
1723
+ pluginNextjs.configs["core-web-vitals"].rules,
1724
+ "@next/next/",
1725
+ "nextjs/"
1726
+ ),
1727
+ "nextjs/google-font-display": ["error"],
1728
+ "nextjs/google-font-preconnect": ["error"],
1729
+ "nextjs/inline-script-id": ["error"],
1730
+ "nextjs/next-script-for-ga": ["warn"],
1731
+ "nextjs/no-assign-module-variable": ["error"],
1732
+ "nextjs/no-css-tags": ["warn"],
1733
+ "nextjs/no-document-import-in-page": ["error"],
1734
+ "nextjs/no-duplicate-head": ["error"],
1735
+ "nextjs/no-head-element": ["warn"],
1736
+ "nextjs/no-head-import-in-document": ["error"],
1737
+ "nextjs/no-html-link-for-pages": ["off"],
1738
+ "nextjs/no-img-element": ["warn"],
1739
+ "nextjs/no-page-custom-font": ["warn"],
1740
+ "nextjs/no-script-component-in-head": ["error"],
1741
+ "nextjs/no-styled-jsx-in-document": ["warn"],
1742
+ "nextjs/no-sync-scripts": ["warn"],
1743
+ "nextjs/no-title-in-document-head": ["warn"],
1744
+ "nextjs/no-typos": ["warn"],
1745
+ "nextjs/no-unwanted-polyfillio": ["warn"],
1646
1746
  // This rule creates errors with webpack parsing on edge runtime
1647
1747
  "unicorn/prefer-node-protocol": ["off"],
1648
1748
  ...overrides
@@ -1661,22 +1761,17 @@ async function nextjs(options = {}) {
1661
1761
  name: "luxass/nextjs/default-export-override",
1662
1762
  files: GLOB_NEXTJS_ROUTES,
1663
1763
  rules: {
1664
- "import/prefer-default-export": "error",
1665
- "react-refresh/only-export-components": "off"
1764
+ "import/prefer-default-export": "error"
1666
1765
  }
1667
1766
  },
1668
1767
  {
1669
1768
  name: "luxass/nextjs/og-override",
1670
1769
  files: GLOB_NEXTJS_OG,
1671
1770
  rules: {
1672
- "@next/next/no-img-element": "off",
1771
+ "nextjs/no-img-element": "off",
1673
1772
  "react/no-unknown-property": ["error", {
1674
1773
  ignore: ["tw"]
1675
- }],
1676
- "react-refresh/only-export-components": [
1677
- "warn",
1678
- { allowConstantExport: true }
1679
- ]
1774
+ }]
1680
1775
  }
1681
1776
  }
1682
1777
  ];
@@ -1684,278 +1779,148 @@ async function nextjs(options = {}) {
1684
1779
 
1685
1780
  // src/configs/react.ts
1686
1781
  import { isPackageExists as isPackageExists2 } from "local-pkg";
1782
+ var ReactRefreshAllowConstantExportPackages = [
1783
+ "vite"
1784
+ ];
1785
+ var RemixPackages = [
1786
+ "@remix-run/node",
1787
+ "@remix-run/react",
1788
+ "@remix-run/serve",
1789
+ "@remix-run/dev"
1790
+ ];
1687
1791
  async function react(options = {}) {
1688
1792
  const {
1689
- a11y = false,
1690
- files = [GLOB_JSX, GLOB_TSX],
1691
- overrides = {},
1692
- typescript: typescript2 = true
1793
+ files = [GLOB_TS, GLOB_TSX],
1794
+ overrides = {}
1693
1795
  } = options;
1694
1796
  await ensure([
1695
- "eslint-plugin-react",
1797
+ "@eslint-react/eslint-plugin",
1696
1798
  "eslint-plugin-react-hooks",
1697
- "eslint-plugin-react-refresh",
1698
- ...options.a11y ? ["eslint-plugin-jsx-a11y"] : []
1799
+ "eslint-plugin-react-refresh"
1699
1800
  ]);
1801
+ const tsconfigPath = options?.tsconfigPath ? toArray(options.tsconfigPath) : void 0;
1802
+ const isTypeAware = !!tsconfigPath;
1700
1803
  const [
1701
1804
  pluginReact,
1702
1805
  pluginReactHooks,
1703
1806
  pluginReactRefresh,
1704
- pluginA11y
1807
+ parserTs
1705
1808
  ] = await Promise.all([
1706
- interop(import("eslint-plugin-react")),
1809
+ interop(import("@eslint-react/eslint-plugin")),
1707
1810
  interop(import("eslint-plugin-react-hooks")),
1708
1811
  interop(import("eslint-plugin-react-refresh")),
1709
- ...a11y ? [interop(import("eslint-plugin-jsx-a11y"))] : []
1812
+ interop(import("@typescript-eslint/parser"))
1710
1813
  ]);
1711
- const isAllowConstantExport = isPackageExists2("vite");
1814
+ const isAllowConstantExport = ReactRefreshAllowConstantExportPackages.some(
1815
+ (i) => isPackageExists2(i)
1816
+ );
1817
+ const isUsingRemix = RemixPackages.some((i) => isPackageExists2(i));
1818
+ const isUsingNext = isPackageExists2("next");
1819
+ const plugins = pluginReact.configs.all.plugins;
1712
1820
  return [
1713
1821
  {
1714
1822
  name: "luxass/react/setup",
1715
1823
  plugins: {
1716
- "react": pluginReact,
1824
+ "react": plugins["@eslint-react"],
1825
+ "react-dom": plugins["@eslint-react/dom"],
1717
1826
  "react-hooks": pluginReactHooks,
1718
- "react-refresh": pluginReactRefresh,
1719
- ...a11y ? { "jsx-a11y": pluginA11y } : {}
1827
+ "react-hooks-extra": plugins["@eslint-react/hooks-extra"],
1828
+ "react-naming-convention": plugins["@eslint-react/naming-convention"],
1829
+ "react-refresh": pluginReactRefresh
1720
1830
  }
1721
1831
  },
1722
1832
  {
1723
1833
  name: "luxass/react/rules",
1724
1834
  files,
1725
1835
  languageOptions: {
1836
+ parser: parserTs,
1726
1837
  parserOptions: {
1727
1838
  ecmaFeatures: {
1728
1839
  jsx: true
1729
- }
1730
- }
1840
+ },
1841
+ ...isTypeAware ? { project: tsconfigPath } : {}
1842
+ },
1843
+ sourceType: "module"
1731
1844
  },
1732
1845
  rules: {
1733
- ...a11y ? {
1734
- // recommended rules for jsx-a11y
1735
- "jsx-a11y/alt-text": "error",
1736
- "jsx-a11y/anchor-ambiguous-text": "off",
1737
- "jsx-a11y/anchor-has-content": "error",
1738
- "jsx-a11y/anchor-is-valid": "error",
1739
- "jsx-a11y/aria-activedescendant-has-tabindex": "error",
1740
- "jsx-a11y/aria-props": "error",
1741
- "jsx-a11y/aria-proptypes": "error",
1742
- "jsx-a11y/aria-role": "error",
1743
- "jsx-a11y/aria-unsupported-elements": "error",
1744
- "jsx-a11y/autocomplete-valid": "error",
1745
- "jsx-a11y/click-events-have-key-events": "error",
1746
- "jsx-a11y/control-has-associated-label": [
1747
- "off",
1748
- {
1749
- ignoreElements: [
1750
- "audio",
1751
- "canvas",
1752
- "embed",
1753
- "input",
1754
- "textarea",
1755
- "tr",
1756
- "video"
1757
- ],
1758
- ignoreRoles: [
1759
- "grid",
1760
- "listbox",
1761
- "menu",
1762
- "menubar",
1763
- "radiogroup",
1764
- "row",
1765
- "tablist",
1766
- "toolbar",
1767
- "tree",
1768
- "treegrid"
1769
- ],
1770
- includeRoles: [
1771
- "alert",
1772
- "dialog"
1773
- ]
1774
- }
1775
- ],
1776
- "jsx-a11y/heading-has-content": "error",
1777
- "jsx-a11y/html-has-lang": "error",
1778
- "jsx-a11y/iframe-has-title": "error",
1779
- "jsx-a11y/img-redundant-alt": "error",
1780
- "jsx-a11y/interactive-supports-focus": [
1781
- "error",
1782
- {
1783
- tabbable: [
1784
- "button",
1785
- "checkbox",
1786
- "link",
1787
- "searchbox",
1788
- "spinbutton",
1789
- "switch",
1790
- "textbox"
1791
- ]
1792
- }
1793
- ],
1794
- "jsx-a11y/label-has-associated-control": "error",
1795
- "jsx-a11y/label-has-for": "off",
1796
- "jsx-a11y/media-has-caption": "error",
1797
- "jsx-a11y/mouse-events-have-key-events": "error",
1798
- "jsx-a11y/no-access-key": "error",
1799
- "jsx-a11y/no-autofocus": "error",
1800
- "jsx-a11y/no-distracting-elements": "error",
1801
- "jsx-a11y/no-interactive-element-to-noninteractive-role": [
1802
- "error",
1803
- {
1804
- canvas: [
1805
- "img"
1806
- ],
1807
- tr: [
1808
- "none",
1809
- "presentation"
1810
- ]
1811
- }
1812
- ],
1813
- "jsx-a11y/no-noninteractive-element-interactions": [
1814
- "error",
1815
- {
1816
- alert: [
1817
- "onKeyUp",
1818
- "onKeyDown",
1819
- "onKeyPress"
1820
- ],
1821
- body: [
1822
- "onError",
1823
- "onLoad"
1824
- ],
1825
- dialog: [
1826
- "onKeyUp",
1827
- "onKeyDown",
1828
- "onKeyPress"
1829
- ],
1830
- handlers: [
1831
- "onClick",
1832
- "onError",
1833
- "onLoad",
1834
- "onMouseDown",
1835
- "onMouseUp",
1836
- "onKeyPress",
1837
- "onKeyDown",
1838
- "onKeyUp"
1839
- ],
1840
- iframe: [
1841
- "onError",
1842
- "onLoad"
1843
- ],
1844
- img: [
1845
- "onError",
1846
- "onLoad"
1847
- ]
1848
- }
1849
- ],
1850
- "jsx-a11y/no-noninteractive-element-to-interactive-role": [
1851
- "error",
1852
- {
1853
- fieldset: [
1854
- "radiogroup",
1855
- "presentation"
1856
- ],
1857
- li: [
1858
- "menuitem",
1859
- "option",
1860
- "row",
1861
- "tab",
1862
- "treeitem"
1863
- ],
1864
- ol: [
1865
- "listbox",
1866
- "menu",
1867
- "menubar",
1868
- "radiogroup",
1869
- "tablist",
1870
- "tree",
1871
- "treegrid"
1872
- ],
1873
- table: [
1874
- "grid"
1875
- ],
1876
- td: [
1877
- "gridcell"
1878
- ],
1879
- ul: [
1880
- "listbox",
1881
- "menu",
1882
- "menubar",
1883
- "radiogroup",
1884
- "tablist",
1885
- "tree",
1886
- "treegrid"
1887
- ]
1888
- }
1889
- ],
1890
- "jsx-a11y/no-noninteractive-tabindex": [
1891
- "error",
1892
- {
1893
- allowExpressionValues: true,
1894
- roles: [
1895
- "tabpanel"
1896
- ],
1897
- tags: []
1898
- }
1899
- ],
1900
- "jsx-a11y/no-redundant-roles": "error",
1901
- "jsx-a11y/no-static-element-interactions": [
1902
- "error",
1903
- {
1904
- allowExpressionValues: true,
1905
- handlers: [
1906
- "onClick",
1907
- "onMouseDown",
1908
- "onMouseUp",
1909
- "onKeyPress",
1910
- "onKeyDown",
1911
- "onKeyUp"
1912
- ]
1913
- }
1914
- ],
1915
- "jsx-a11y/role-has-required-aria-props": "error",
1916
- "jsx-a11y/role-supports-aria-props": "error",
1917
- "jsx-a11y/scope": "error",
1918
- "jsx-a11y/tabindex-no-positive": "error"
1919
- } : {},
1920
- // recommended rules react
1921
- "react/display-name": "error",
1922
- "react/jsx-key": "error",
1923
- "react/jsx-no-comment-textnodes": "error",
1924
- "react/jsx-no-duplicate-props": "error",
1925
- "react/jsx-no-target-blank": "error",
1926
- "react/jsx-no-undef": "error",
1927
- "react/jsx-uses-react": "error",
1928
- "react/jsx-uses-vars": "error",
1929
- "react/no-children-prop": "error",
1930
- "react/no-danger-with-children": "error",
1931
- "react/no-deprecated": "error",
1932
- "react/no-direct-mutation-state": "error",
1933
- "react/no-find-dom-node": "error",
1934
- "react/no-is-mounted": "error",
1935
- "react/no-render-return-value": "error",
1936
- "react/no-string-refs": "error",
1937
- "react/no-unescaped-entities": "error",
1938
- "react/no-unknown-property": "error",
1939
- "react/no-unsafe": "off",
1940
- "react/prop-types": "error",
1941
- "react/react-in-jsx-scope": "off",
1942
- "react/require-render-return": "error",
1846
+ // recommended rules from @eslint-react/dom
1847
+ "react-dom/no-children-in-void-dom-elements": "warn",
1848
+ "react-dom/no-dangerously-set-innerhtml": "warn",
1849
+ "react-dom/no-dangerously-set-innerhtml-with-children": "error",
1850
+ "react-dom/no-find-dom-node": "error",
1851
+ "react-dom/no-missing-button-type": "warn",
1852
+ "react-dom/no-missing-iframe-sandbox": "warn",
1853
+ "react-dom/no-namespace": "error",
1854
+ "react-dom/no-render-return-value": "error",
1855
+ "react-dom/no-script-url": "warn",
1856
+ "react-dom/no-unsafe-iframe-sandbox": "warn",
1857
+ "react-dom/no-unsafe-target-blank": "warn",
1943
1858
  // recommended rules react-hooks
1944
1859
  "react-hooks/exhaustive-deps": "warn",
1945
1860
  "react-hooks/rules-of-hooks": "error",
1946
1861
  // react refresh
1947
- "react-refresh/only-export-components": ["warn", { allowConstantExport: isAllowConstantExport }],
1948
- ...typescript2 ? {
1949
- "react/jsx-no-undef": "off",
1950
- "react/prop-type": "off"
1862
+ "react-refresh/only-export-components": [
1863
+ "warn",
1864
+ {
1865
+ allowConstantExport: isAllowConstantExport,
1866
+ allowExportNames: isUsingNext ? [
1867
+ "config",
1868
+ "generateStaticParams",
1869
+ "metadata",
1870
+ "generateMetadata",
1871
+ "viewport",
1872
+ "generateViewport"
1873
+ ] : isUsingRemix ? [
1874
+ "meta",
1875
+ "links",
1876
+ "headers",
1877
+ "loader",
1878
+ "action"
1879
+ ] : void 0
1880
+ }
1881
+ ],
1882
+ // recommended rules from @eslint-react
1883
+ "react/ensure-forward-ref-using-ref": "warn",
1884
+ "react/no-access-state-in-setstate": "error",
1885
+ "react/no-array-index-key": "warn",
1886
+ "react/no-children-count": "warn",
1887
+ "react/no-children-for-each": "warn",
1888
+ "react/no-children-map": "warn",
1889
+ "react/no-children-only": "warn",
1890
+ "react/no-children-prop": "warn",
1891
+ "react/no-children-to-array": "warn",
1892
+ "react/no-clone-element": "warn",
1893
+ "react/no-comment-textnodes": "warn",
1894
+ "react/no-component-will-mount": "error",
1895
+ "react/no-component-will-receive-props": "error",
1896
+ "react/no-component-will-update": "error",
1897
+ "react/no-create-ref": "error",
1898
+ "react/no-direct-mutation-state": "error",
1899
+ "react/no-duplicate-key": "error",
1900
+ "react/no-implicit-key": "error",
1901
+ "react/no-missing-key": "error",
1902
+ "react/no-nested-components": "warn",
1903
+ "react/no-redundant-should-component-update": "error",
1904
+ "react/no-set-state-in-component-did-mount": "warn",
1905
+ "react/no-set-state-in-component-did-update": "warn",
1906
+ "react/no-set-state-in-component-will-update": "warn",
1907
+ "react/no-string-refs": "error",
1908
+ "react/no-unsafe-component-will-mount": "warn",
1909
+ "react/no-unsafe-component-will-receive-props": "warn",
1910
+ "react/no-unsafe-component-will-update": "warn",
1911
+ "react/no-unstable-context-value": "error",
1912
+ "react/no-unstable-default-props": "error",
1913
+ "react/no-unused-class-component-members": "warn",
1914
+ "react/no-unused-state": "warn",
1915
+ "react/no-useless-fragment": "warn",
1916
+ "react/prefer-destructuring-assignment": "warn",
1917
+ "react/prefer-shorthand-boolean": "warn",
1918
+ "react/prefer-shorthand-fragment": "warn",
1919
+ ...isTypeAware ? {
1920
+ "react/no-leaked-conditional-rendering": "warn"
1951
1921
  } : {},
1952
1922
  // overrides
1953
1923
  ...overrides
1954
- },
1955
- settings: {
1956
- react: {
1957
- version: "detect"
1958
- }
1959
1924
  }
1960
1925
  }
1961
1926
  ];
@@ -2079,7 +2044,7 @@ async function tailwindcss(options = {}) {
2079
2044
  }
2080
2045
  },
2081
2046
  plugins: {
2082
- tailwind: pluginTailwindCSS
2047
+ tailwindcss: pluginTailwindCSS
2083
2048
  }
2084
2049
  },
2085
2050
  {
@@ -2087,19 +2052,19 @@ async function tailwindcss(options = {}) {
2087
2052
  files,
2088
2053
  rules: {
2089
2054
  // https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/classnames-order.md
2090
- "tailwind/classnames-order": "warn",
2055
+ "tailwindcss/classnames-order": "warn",
2091
2056
  // https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/enforces-negative-arbitrary-values.md
2092
- "tailwind/enforces-negative-arbitrary-values": "warn",
2057
+ "tailwindcss/enforces-negative-arbitrary-values": "warn",
2093
2058
  // https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/enforces-shorthand.md
2094
- "tailwind/enforces-shorthand": "warn",
2059
+ "tailwindcss/enforces-shorthand": "warn",
2095
2060
  // https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/migration-from-tailwind-2.md
2096
- "tailwind/migration-from-tailwind-2": "warn",
2061
+ "tailwindcss/migration-from-tailwind-2": "warn",
2097
2062
  // https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/no-arbitrary-value.md
2098
- "tailwind/no-arbitrary-value": "off",
2063
+ "tailwindcss/no-arbitrary-value": "off",
2099
2064
  // https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/no-contradicting-classname.md
2100
- "tailwind/no-contradicting-classname": "error",
2065
+ "tailwindcss/no-contradicting-classname": "error",
2101
2066
  // https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/no-custom-classname.md
2102
- "tailwind/no-custom-classname": "warn",
2067
+ "tailwindcss/no-custom-classname": "warn",
2103
2068
  ...overrides
2104
2069
  }
2105
2070
  }
@@ -2213,7 +2178,7 @@ async function formatters(options = {}, stylistic2 = {}) {
2213
2178
  if (options.html) {
2214
2179
  configs.push({
2215
2180
  name: "luxass/formatter/html",
2216
- files: ["**/*.html"],
2181
+ files: [GLOB_HTML],
2217
2182
  languageOptions: {
2218
2183
  parser: parserPlain
2219
2184
  },
@@ -2363,10 +2328,14 @@ async function solid(options = {}) {
2363
2328
  await ensure([
2364
2329
  "eslint-plugin-solid"
2365
2330
  ]);
2331
+ const tsconfigPath = options?.tsconfigPath ? toArray(options.tsconfigPath) : void 0;
2332
+ const isTypeAware = !!tsconfigPath;
2366
2333
  const [
2367
- pluginSolid
2334
+ pluginSolid,
2335
+ parserTs
2368
2336
  ] = await Promise.all([
2369
- interop(import("eslint-plugin-solid"))
2337
+ interop(import("eslint-plugin-solid")),
2338
+ interop(import("@typescript-eslint/parser"))
2370
2339
  ]);
2371
2340
  return [
2372
2341
  {
@@ -2379,42 +2348,41 @@ async function solid(options = {}) {
2379
2348
  name: "luxass/solid/rules",
2380
2349
  files,
2381
2350
  languageOptions: {
2351
+ parser: parserTs,
2382
2352
  parserOptions: {
2383
2353
  ecmaFeatures: {
2384
2354
  jsx: true
2385
- }
2355
+ },
2356
+ ...isTypeAware ? { project: tsconfigPath } : {}
2386
2357
  },
2387
2358
  sourceType: "module"
2388
2359
  },
2389
2360
  rules: {
2390
- // solid recommended rules
2391
2361
  // reactivity
2392
2362
  "solid/components-return-once": "warn",
2393
- "solid/event-handlers": "warn",
2363
+ "solid/event-handlers": ["error", {
2364
+ // if true, don't warn on ambiguously named event handlers like `onclick` or `onchange`
2365
+ ignoreCase: false,
2366
+ // if true, warn when spreading event handlers onto JSX. Enable for Solid < v1.6.
2367
+ warnOnSpread: false
2368
+ }],
2394
2369
  // these rules are mostly style suggestions
2395
- "solid/imports": "warn",
2370
+ "solid/imports": "error",
2396
2371
  // identifier usage is important
2397
2372
  "solid/jsx-no-duplicate-props": "error",
2398
2373
  "solid/jsx-no-script-url": "error",
2399
2374
  "solid/jsx-no-undef": "error",
2400
2375
  "solid/jsx-uses-vars": "error",
2401
- "solid/no-array-handlers": "off",
2402
2376
  "solid/no-destructure": "error",
2403
2377
  // security problems
2404
- "solid/no-innerhtml": "error",
2405
- // only necessary for resource-constrained environments
2406
- "solid/no-proxy-apis": "off",
2407
- "solid/no-react-deps": "warn",
2408
- "solid/no-react-specific-props": "warn",
2378
+ "solid/no-innerhtml": ["error", { allowStatic: true }],
2379
+ "solid/no-react-deps": "error",
2380
+ "solid/no-react-specific-props": "error",
2409
2381
  "solid/no-unknown-namespaces": "error",
2410
- // deprecated
2411
- "solid/prefer-classlist": "off",
2412
2382
  "solid/prefer-for": "error",
2413
- // handled by Solid compiler, opt-in style suggestion
2414
- "solid/prefer-show": "off",
2415
2383
  "solid/reactivity": "warn",
2416
- "solid/self-closing-comp": "warn",
2417
- "solid/style-prop": "warn",
2384
+ "solid/self-closing-comp": "error",
2385
+ "solid/style-prop": ["error", { styleProps: ["style", "css"] }],
2418
2386
  ...typescript2 ? {
2419
2387
  "solid/jsx-no-undef": ["error", { typescriptEnabled: true }],
2420
2388
  // namespaces taken care of by TS
@@ -2451,7 +2419,12 @@ var defaultPluginRenaming = {
2451
2419
  "import-x": "import",
2452
2420
  "n": "node",
2453
2421
  "vitest": "test",
2454
- "yml": "yaml"
2422
+ "yml": "yaml",
2423
+ "@eslint-react": "react",
2424
+ "@eslint-react/dom": "react-dom",
2425
+ "@eslint-react/hooks-extra": "react-hooks-extra",
2426
+ "@eslint-react/naming-convention": "react-naming-convention",
2427
+ "@next/next": "nextjs"
2455
2428
  };
2456
2429
  function luxass(options = {}, ...userConfigs) {
2457
2430
  const {
@@ -2463,6 +2436,7 @@ function luxass(options = {}, ...userConfigs) {
2463
2436
  nextjs: enableNextJS = false,
2464
2437
  react: enableReact = false,
2465
2438
  tailwindcss: enableTailwindCSS = false,
2439
+ svelte: enableSvelte = false,
2466
2440
  solid: enableSolid = false,
2467
2441
  typescript: enableTypeScript = isPackageExists4("typescript"),
2468
2442
  unocss: enableUnoCSS = false,
@@ -2522,8 +2496,9 @@ function luxass(options = {}, ...userConfigs) {
2522
2496
  }
2523
2497
  if (enableReact || enableNextJS) {
2524
2498
  configs.push(react({
2499
+ ...resolveSubOptions(options, "react"),
2525
2500
  overrides: getOverrides(options, "react"),
2526
- typescript: !!enableTypeScript
2501
+ tsconfigPath: getOverrides(options, "typescript").tsconfigPath
2527
2502
  }));
2528
2503
  }
2529
2504
  if (enableNextJS) {
@@ -2543,6 +2518,16 @@ function luxass(options = {}, ...userConfigs) {
2543
2518
  })
2544
2519
  );
2545
2520
  }
2521
+ if (enableSvelte) {
2522
+ configs.push(
2523
+ svelte({
2524
+ ...resolveSubOptions(options, "svelte"),
2525
+ overrides: getOverrides(options, "svelte"),
2526
+ stylistic: stylisticOptions,
2527
+ typescript: !!enableTypeScript
2528
+ })
2529
+ );
2530
+ }
2546
2531
  if (enableVue) {
2547
2532
  configs.push(
2548
2533
  vue({
@@ -2619,15 +2604,15 @@ function luxass(options = {}, ...userConfigs) {
2619
2604
  if (Object.keys(fusedConfig).length) {
2620
2605
  configs.push([fusedConfig]);
2621
2606
  }
2622
- let pipeline = new FlatConfigComposer();
2623
- pipeline = pipeline.append(
2607
+ let composer = new FlatConfigComposer();
2608
+ composer = composer.append(
2624
2609
  ...configs,
2625
2610
  ...userConfigs
2626
2611
  );
2627
2612
  if (autoRenamePlugins) {
2628
- pipeline = pipeline.renamePlugins(defaultPluginRenaming);
2613
+ composer = composer.renamePlugins(defaultPluginRenaming);
2629
2614
  }
2630
- return pipeline;
2615
+ return composer;
2631
2616
  }
2632
2617
 
2633
2618
  // src/index.ts
@@ -2654,6 +2639,7 @@ export {
2654
2639
  GLOB_SRC,
2655
2640
  GLOB_SRC_EXT,
2656
2641
  GLOB_STYLE,
2642
+ GLOB_SVELTE,
2657
2643
  GLOB_TESTS,
2658
2644
  GLOB_TOML,
2659
2645
  GLOB_TS,
@@ -2673,6 +2659,7 @@ export {
2673
2659
  javascript,
2674
2660
  jsdoc,
2675
2661
  jsonc,
2662
+ luxass,
2676
2663
  markdown,
2677
2664
  nextjs,
2678
2665
  node,
@@ -2684,6 +2671,7 @@ export {
2684
2671
  sortPackageJson,
2685
2672
  sortTsconfig,
2686
2673
  stylistic,
2674
+ svelte,
2687
2675
  tailwindcss,
2688
2676
  test,
2689
2677
  toArray,