@luxass/eslint-config 4.3.7 → 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -21
- package/dist/index.cjs +361 -367
- package/dist/index.d.cts +1170 -1271
- package/dist/index.d.ts +1170 -1271
- package/dist/index.js +358 -367
- package/package.json +57 -47
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
|
|
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
|
-
|
|
1710
|
+
nextjs: pluginNextjs
|
|
1618
1711
|
}
|
|
1619
1712
|
},
|
|
1620
1713
|
{
|
|
1621
1714
|
name: "luxass/nextjs/rules",
|
|
1622
1715
|
files,
|
|
1623
1716
|
rules: {
|
|
1624
|
-
...
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
"
|
|
1635
|
-
"
|
|
1636
|
-
"
|
|
1637
|
-
"
|
|
1638
|
-
"
|
|
1639
|
-
"
|
|
1640
|
-
"
|
|
1641
|
-
"
|
|
1642
|
-
"
|
|
1643
|
-
"
|
|
1644
|
-
"
|
|
1645
|
-
|
|
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
|
|
@@ -1668,7 +1768,7 @@ async function nextjs(options = {}) {
|
|
|
1668
1768
|
name: "luxass/nextjs/og-override",
|
|
1669
1769
|
files: GLOB_NEXTJS_OG,
|
|
1670
1770
|
rules: {
|
|
1671
|
-
"
|
|
1771
|
+
"nextjs/no-img-element": "off",
|
|
1672
1772
|
"react/no-unknown-property": ["error", {
|
|
1673
1773
|
ignore: ["tw"]
|
|
1674
1774
|
}]
|
|
@@ -1679,281 +1779,151 @@ async function nextjs(options = {}) {
|
|
|
1679
1779
|
|
|
1680
1780
|
// src/configs/react.ts
|
|
1681
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
|
+
];
|
|
1682
1791
|
async function react(options = {}) {
|
|
1683
1792
|
const {
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
overrides = {},
|
|
1687
|
-
refresh = true,
|
|
1688
|
-
typescript: typescript2 = true
|
|
1793
|
+
files = [GLOB_TS, GLOB_TSX],
|
|
1794
|
+
overrides = {}
|
|
1689
1795
|
} = options;
|
|
1690
1796
|
await ensure([
|
|
1691
|
-
"eslint-plugin
|
|
1797
|
+
"@eslint-react/eslint-plugin",
|
|
1692
1798
|
"eslint-plugin-react-hooks",
|
|
1693
|
-
|
|
1694
|
-
...a11y ? ["eslint-plugin-jsx-a11y"] : []
|
|
1799
|
+
"eslint-plugin-react-refresh"
|
|
1695
1800
|
]);
|
|
1801
|
+
const tsconfigPath = options?.tsconfigPath ? toArray(options.tsconfigPath) : void 0;
|
|
1802
|
+
const isTypeAware = !!tsconfigPath;
|
|
1696
1803
|
const [
|
|
1697
1804
|
pluginReact,
|
|
1698
1805
|
pluginReactHooks,
|
|
1699
1806
|
pluginReactRefresh,
|
|
1700
|
-
|
|
1807
|
+
parserTs
|
|
1701
1808
|
] = await Promise.all([
|
|
1702
|
-
interop(import("eslint-plugin
|
|
1809
|
+
interop(import("@eslint-react/eslint-plugin")),
|
|
1703
1810
|
interop(import("eslint-plugin-react-hooks")),
|
|
1704
|
-
|
|
1705
|
-
|
|
1811
|
+
interop(import("eslint-plugin-react-refresh")),
|
|
1812
|
+
interop(import("@typescript-eslint/parser"))
|
|
1706
1813
|
]);
|
|
1707
|
-
const isAllowConstantExport =
|
|
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;
|
|
1708
1820
|
return [
|
|
1709
1821
|
{
|
|
1710
1822
|
name: "luxass/react/setup",
|
|
1711
1823
|
plugins: {
|
|
1712
|
-
"react":
|
|
1824
|
+
"react": plugins["@eslint-react"],
|
|
1825
|
+
"react-dom": plugins["@eslint-react/dom"],
|
|
1713
1826
|
"react-hooks": pluginReactHooks,
|
|
1714
|
-
|
|
1715
|
-
|
|
1827
|
+
"react-hooks-extra": plugins["@eslint-react/hooks-extra"],
|
|
1828
|
+
"react-naming-convention": plugins["@eslint-react/naming-convention"],
|
|
1829
|
+
"react-refresh": pluginReactRefresh
|
|
1716
1830
|
}
|
|
1717
1831
|
},
|
|
1718
1832
|
{
|
|
1719
1833
|
name: "luxass/react/rules",
|
|
1720
1834
|
files,
|
|
1721
1835
|
languageOptions: {
|
|
1836
|
+
parser: parserTs,
|
|
1722
1837
|
parserOptions: {
|
|
1723
1838
|
ecmaFeatures: {
|
|
1724
1839
|
jsx: true
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1840
|
+
},
|
|
1841
|
+
...isTypeAware ? { project: tsconfigPath } : {}
|
|
1842
|
+
},
|
|
1843
|
+
sourceType: "module"
|
|
1727
1844
|
},
|
|
1728
1845
|
rules: {
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
"jsx-a11y/click-events-have-key-events": "error",
|
|
1742
|
-
"jsx-a11y/control-has-associated-label": [
|
|
1743
|
-
"off",
|
|
1744
|
-
{
|
|
1745
|
-
ignoreElements: [
|
|
1746
|
-
"audio",
|
|
1747
|
-
"canvas",
|
|
1748
|
-
"embed",
|
|
1749
|
-
"input",
|
|
1750
|
-
"textarea",
|
|
1751
|
-
"tr",
|
|
1752
|
-
"video"
|
|
1753
|
-
],
|
|
1754
|
-
ignoreRoles: [
|
|
1755
|
-
"grid",
|
|
1756
|
-
"listbox",
|
|
1757
|
-
"menu",
|
|
1758
|
-
"menubar",
|
|
1759
|
-
"radiogroup",
|
|
1760
|
-
"row",
|
|
1761
|
-
"tablist",
|
|
1762
|
-
"toolbar",
|
|
1763
|
-
"tree",
|
|
1764
|
-
"treegrid"
|
|
1765
|
-
],
|
|
1766
|
-
includeRoles: [
|
|
1767
|
-
"alert",
|
|
1768
|
-
"dialog"
|
|
1769
|
-
]
|
|
1770
|
-
}
|
|
1771
|
-
],
|
|
1772
|
-
"jsx-a11y/heading-has-content": "error",
|
|
1773
|
-
"jsx-a11y/html-has-lang": "error",
|
|
1774
|
-
"jsx-a11y/iframe-has-title": "error",
|
|
1775
|
-
"jsx-a11y/img-redundant-alt": "error",
|
|
1776
|
-
"jsx-a11y/interactive-supports-focus": [
|
|
1777
|
-
"error",
|
|
1778
|
-
{
|
|
1779
|
-
tabbable: [
|
|
1780
|
-
"button",
|
|
1781
|
-
"checkbox",
|
|
1782
|
-
"link",
|
|
1783
|
-
"searchbox",
|
|
1784
|
-
"spinbutton",
|
|
1785
|
-
"switch",
|
|
1786
|
-
"textbox"
|
|
1787
|
-
]
|
|
1788
|
-
}
|
|
1789
|
-
],
|
|
1790
|
-
"jsx-a11y/label-has-associated-control": "error",
|
|
1791
|
-
"jsx-a11y/label-has-for": "off",
|
|
1792
|
-
"jsx-a11y/media-has-caption": "error",
|
|
1793
|
-
"jsx-a11y/mouse-events-have-key-events": "error",
|
|
1794
|
-
"jsx-a11y/no-access-key": "error",
|
|
1795
|
-
"jsx-a11y/no-autofocus": "error",
|
|
1796
|
-
"jsx-a11y/no-distracting-elements": "error",
|
|
1797
|
-
"jsx-a11y/no-interactive-element-to-noninteractive-role": [
|
|
1798
|
-
"error",
|
|
1799
|
-
{
|
|
1800
|
-
canvas: [
|
|
1801
|
-
"img"
|
|
1802
|
-
],
|
|
1803
|
-
tr: [
|
|
1804
|
-
"none",
|
|
1805
|
-
"presentation"
|
|
1806
|
-
]
|
|
1807
|
-
}
|
|
1808
|
-
],
|
|
1809
|
-
"jsx-a11y/no-noninteractive-element-interactions": [
|
|
1810
|
-
"error",
|
|
1811
|
-
{
|
|
1812
|
-
alert: [
|
|
1813
|
-
"onKeyUp",
|
|
1814
|
-
"onKeyDown",
|
|
1815
|
-
"onKeyPress"
|
|
1816
|
-
],
|
|
1817
|
-
body: [
|
|
1818
|
-
"onError",
|
|
1819
|
-
"onLoad"
|
|
1820
|
-
],
|
|
1821
|
-
dialog: [
|
|
1822
|
-
"onKeyUp",
|
|
1823
|
-
"onKeyDown",
|
|
1824
|
-
"onKeyPress"
|
|
1825
|
-
],
|
|
1826
|
-
handlers: [
|
|
1827
|
-
"onClick",
|
|
1828
|
-
"onError",
|
|
1829
|
-
"onLoad",
|
|
1830
|
-
"onMouseDown",
|
|
1831
|
-
"onMouseUp",
|
|
1832
|
-
"onKeyPress",
|
|
1833
|
-
"onKeyDown",
|
|
1834
|
-
"onKeyUp"
|
|
1835
|
-
],
|
|
1836
|
-
iframe: [
|
|
1837
|
-
"onError",
|
|
1838
|
-
"onLoad"
|
|
1839
|
-
],
|
|
1840
|
-
img: [
|
|
1841
|
-
"onError",
|
|
1842
|
-
"onLoad"
|
|
1843
|
-
]
|
|
1844
|
-
}
|
|
1845
|
-
],
|
|
1846
|
-
"jsx-a11y/no-noninteractive-element-to-interactive-role": [
|
|
1847
|
-
"error",
|
|
1848
|
-
{
|
|
1849
|
-
fieldset: [
|
|
1850
|
-
"radiogroup",
|
|
1851
|
-
"presentation"
|
|
1852
|
-
],
|
|
1853
|
-
li: [
|
|
1854
|
-
"menuitem",
|
|
1855
|
-
"option",
|
|
1856
|
-
"row",
|
|
1857
|
-
"tab",
|
|
1858
|
-
"treeitem"
|
|
1859
|
-
],
|
|
1860
|
-
ol: [
|
|
1861
|
-
"listbox",
|
|
1862
|
-
"menu",
|
|
1863
|
-
"menubar",
|
|
1864
|
-
"radiogroup",
|
|
1865
|
-
"tablist",
|
|
1866
|
-
"tree",
|
|
1867
|
-
"treegrid"
|
|
1868
|
-
],
|
|
1869
|
-
table: [
|
|
1870
|
-
"grid"
|
|
1871
|
-
],
|
|
1872
|
-
td: [
|
|
1873
|
-
"gridcell"
|
|
1874
|
-
],
|
|
1875
|
-
ul: [
|
|
1876
|
-
"listbox",
|
|
1877
|
-
"menu",
|
|
1878
|
-
"menubar",
|
|
1879
|
-
"radiogroup",
|
|
1880
|
-
"tablist",
|
|
1881
|
-
"tree",
|
|
1882
|
-
"treegrid"
|
|
1883
|
-
]
|
|
1884
|
-
}
|
|
1885
|
-
],
|
|
1886
|
-
"jsx-a11y/no-noninteractive-tabindex": [
|
|
1887
|
-
"error",
|
|
1888
|
-
{
|
|
1889
|
-
allowExpressionValues: true,
|
|
1890
|
-
roles: [
|
|
1891
|
-
"tabpanel"
|
|
1892
|
-
],
|
|
1893
|
-
tags: []
|
|
1894
|
-
}
|
|
1895
|
-
],
|
|
1896
|
-
"jsx-a11y/no-redundant-roles": "error",
|
|
1897
|
-
"jsx-a11y/no-static-element-interactions": [
|
|
1898
|
-
"error",
|
|
1899
|
-
{
|
|
1900
|
-
allowExpressionValues: true,
|
|
1901
|
-
handlers: [
|
|
1902
|
-
"onClick",
|
|
1903
|
-
"onMouseDown",
|
|
1904
|
-
"onMouseUp",
|
|
1905
|
-
"onKeyPress",
|
|
1906
|
-
"onKeyDown",
|
|
1907
|
-
"onKeyUp"
|
|
1908
|
-
]
|
|
1909
|
-
}
|
|
1910
|
-
],
|
|
1911
|
-
"jsx-a11y/role-has-required-aria-props": "error",
|
|
1912
|
-
"jsx-a11y/role-supports-aria-props": "error",
|
|
1913
|
-
"jsx-a11y/scope": "error",
|
|
1914
|
-
"jsx-a11y/tabindex-no-positive": "error"
|
|
1915
|
-
} : {},
|
|
1916
|
-
// recommended rules react
|
|
1917
|
-
"react/display-name": "error",
|
|
1918
|
-
"react/jsx-key": "error",
|
|
1919
|
-
"react/jsx-no-comment-textnodes": "error",
|
|
1920
|
-
"react/jsx-no-duplicate-props": "error",
|
|
1921
|
-
"react/jsx-no-target-blank": "error",
|
|
1922
|
-
"react/jsx-no-undef": "error",
|
|
1923
|
-
"react/jsx-uses-react": "error",
|
|
1924
|
-
"react/jsx-uses-vars": "error",
|
|
1925
|
-
"react/no-children-prop": "error",
|
|
1926
|
-
"react/no-danger-with-children": "error",
|
|
1927
|
-
"react/no-deprecated": "error",
|
|
1928
|
-
"react/no-direct-mutation-state": "error",
|
|
1929
|
-
"react/no-find-dom-node": "error",
|
|
1930
|
-
"react/no-is-mounted": "error",
|
|
1931
|
-
"react/no-render-return-value": "error",
|
|
1932
|
-
"react/no-string-refs": "error",
|
|
1933
|
-
"react/no-unescaped-entities": "error",
|
|
1934
|
-
"react/no-unknown-property": "error",
|
|
1935
|
-
"react/no-unsafe": "off",
|
|
1936
|
-
"react/prop-types": "error",
|
|
1937
|
-
"react/react-in-jsx-scope": "off",
|
|
1938
|
-
"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",
|
|
1939
1858
|
// recommended rules react-hooks
|
|
1940
1859
|
"react-hooks/exhaustive-deps": "warn",
|
|
1941
1860
|
"react-hooks/rules-of-hooks": "error",
|
|
1942
1861
|
// react refresh
|
|
1943
|
-
|
|
1944
|
-
"
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1862
|
+
"react-refresh/only-export-components": [
|
|
1863
|
+
"warn",
|
|
1864
|
+
{
|
|
1865
|
+
allowConstantExport: isAllowConstantExport,
|
|
1866
|
+
allowExportNames: [
|
|
1867
|
+
...isUsingNext ? [
|
|
1868
|
+
"config",
|
|
1869
|
+
"generateStaticParams",
|
|
1870
|
+
"metadata",
|
|
1871
|
+
"generateMetadata",
|
|
1872
|
+
"viewport",
|
|
1873
|
+
"generateViewport"
|
|
1874
|
+
] : [],
|
|
1875
|
+
...isUsingRemix ? [
|
|
1876
|
+
"meta",
|
|
1877
|
+
"links",
|
|
1878
|
+
"headers",
|
|
1879
|
+
"loader",
|
|
1880
|
+
"action"
|
|
1881
|
+
] : []
|
|
1882
|
+
]
|
|
1883
|
+
}
|
|
1884
|
+
],
|
|
1885
|
+
// recommended rules from @eslint-react
|
|
1886
|
+
"react/ensure-forward-ref-using-ref": "warn",
|
|
1887
|
+
"react/no-access-state-in-setstate": "error",
|
|
1888
|
+
"react/no-array-index-key": "warn",
|
|
1889
|
+
"react/no-children-count": "warn",
|
|
1890
|
+
"react/no-children-for-each": "warn",
|
|
1891
|
+
"react/no-children-map": "warn",
|
|
1892
|
+
"react/no-children-only": "warn",
|
|
1893
|
+
"react/no-children-prop": "warn",
|
|
1894
|
+
"react/no-children-to-array": "warn",
|
|
1895
|
+
"react/no-clone-element": "warn",
|
|
1896
|
+
"react/no-comment-textnodes": "warn",
|
|
1897
|
+
"react/no-component-will-mount": "error",
|
|
1898
|
+
"react/no-component-will-receive-props": "error",
|
|
1899
|
+
"react/no-component-will-update": "error",
|
|
1900
|
+
"react/no-create-ref": "error",
|
|
1901
|
+
"react/no-direct-mutation-state": "error",
|
|
1902
|
+
"react/no-duplicate-key": "error",
|
|
1903
|
+
"react/no-implicit-key": "error",
|
|
1904
|
+
"react/no-missing-key": "error",
|
|
1905
|
+
"react/no-nested-components": "warn",
|
|
1906
|
+
"react/no-redundant-should-component-update": "error",
|
|
1907
|
+
"react/no-set-state-in-component-did-mount": "warn",
|
|
1908
|
+
"react/no-set-state-in-component-did-update": "warn",
|
|
1909
|
+
"react/no-set-state-in-component-will-update": "warn",
|
|
1910
|
+
"react/no-string-refs": "error",
|
|
1911
|
+
"react/no-unsafe-component-will-mount": "warn",
|
|
1912
|
+
"react/no-unsafe-component-will-receive-props": "warn",
|
|
1913
|
+
"react/no-unsafe-component-will-update": "warn",
|
|
1914
|
+
"react/no-unstable-context-value": "error",
|
|
1915
|
+
"react/no-unstable-default-props": "error",
|
|
1916
|
+
"react/no-unused-class-component-members": "warn",
|
|
1917
|
+
"react/no-unused-state": "warn",
|
|
1918
|
+
"react/no-useless-fragment": "warn",
|
|
1919
|
+
"react/prefer-destructuring-assignment": "warn",
|
|
1920
|
+
"react/prefer-shorthand-boolean": "warn",
|
|
1921
|
+
"react/prefer-shorthand-fragment": "warn",
|
|
1922
|
+
...isTypeAware ? {
|
|
1923
|
+
"react/no-leaked-conditional-rendering": "warn"
|
|
1949
1924
|
} : {},
|
|
1950
1925
|
// overrides
|
|
1951
1926
|
...overrides
|
|
1952
|
-
},
|
|
1953
|
-
settings: {
|
|
1954
|
-
react: {
|
|
1955
|
-
version: "detect"
|
|
1956
|
-
}
|
|
1957
1927
|
}
|
|
1958
1928
|
}
|
|
1959
1929
|
];
|
|
@@ -2211,7 +2181,7 @@ async function formatters(options = {}, stylistic2 = {}) {
|
|
|
2211
2181
|
if (options.html) {
|
|
2212
2182
|
configs.push({
|
|
2213
2183
|
name: "luxass/formatter/html",
|
|
2214
|
-
files: [
|
|
2184
|
+
files: [GLOB_HTML],
|
|
2215
2185
|
languageOptions: {
|
|
2216
2186
|
parser: parserPlain
|
|
2217
2187
|
},
|
|
@@ -2361,10 +2331,14 @@ async function solid(options = {}) {
|
|
|
2361
2331
|
await ensure([
|
|
2362
2332
|
"eslint-plugin-solid"
|
|
2363
2333
|
]);
|
|
2334
|
+
const tsconfigPath = options?.tsconfigPath ? toArray(options.tsconfigPath) : void 0;
|
|
2335
|
+
const isTypeAware = !!tsconfigPath;
|
|
2364
2336
|
const [
|
|
2365
|
-
pluginSolid
|
|
2337
|
+
pluginSolid,
|
|
2338
|
+
parserTs
|
|
2366
2339
|
] = await Promise.all([
|
|
2367
|
-
interop(import("eslint-plugin-solid"))
|
|
2340
|
+
interop(import("eslint-plugin-solid")),
|
|
2341
|
+
interop(import("@typescript-eslint/parser"))
|
|
2368
2342
|
]);
|
|
2369
2343
|
return [
|
|
2370
2344
|
{
|
|
@@ -2377,42 +2351,41 @@ async function solid(options = {}) {
|
|
|
2377
2351
|
name: "luxass/solid/rules",
|
|
2378
2352
|
files,
|
|
2379
2353
|
languageOptions: {
|
|
2354
|
+
parser: parserTs,
|
|
2380
2355
|
parserOptions: {
|
|
2381
2356
|
ecmaFeatures: {
|
|
2382
2357
|
jsx: true
|
|
2383
|
-
}
|
|
2358
|
+
},
|
|
2359
|
+
...isTypeAware ? { project: tsconfigPath } : {}
|
|
2384
2360
|
},
|
|
2385
2361
|
sourceType: "module"
|
|
2386
2362
|
},
|
|
2387
2363
|
rules: {
|
|
2388
|
-
// solid recommended rules
|
|
2389
2364
|
// reactivity
|
|
2390
2365
|
"solid/components-return-once": "warn",
|
|
2391
|
-
"solid/event-handlers": "
|
|
2366
|
+
"solid/event-handlers": ["error", {
|
|
2367
|
+
// if true, don't warn on ambiguously named event handlers like `onclick` or `onchange`
|
|
2368
|
+
ignoreCase: false,
|
|
2369
|
+
// if true, warn when spreading event handlers onto JSX. Enable for Solid < v1.6.
|
|
2370
|
+
warnOnSpread: false
|
|
2371
|
+
}],
|
|
2392
2372
|
// these rules are mostly style suggestions
|
|
2393
|
-
"solid/imports": "
|
|
2373
|
+
"solid/imports": "error",
|
|
2394
2374
|
// identifier usage is important
|
|
2395
2375
|
"solid/jsx-no-duplicate-props": "error",
|
|
2396
2376
|
"solid/jsx-no-script-url": "error",
|
|
2397
2377
|
"solid/jsx-no-undef": "error",
|
|
2398
2378
|
"solid/jsx-uses-vars": "error",
|
|
2399
|
-
"solid/no-array-handlers": "off",
|
|
2400
2379
|
"solid/no-destructure": "error",
|
|
2401
2380
|
// security problems
|
|
2402
|
-
"solid/no-innerhtml": "error",
|
|
2403
|
-
|
|
2404
|
-
"solid/no-
|
|
2405
|
-
"solid/no-react-deps": "warn",
|
|
2406
|
-
"solid/no-react-specific-props": "warn",
|
|
2381
|
+
"solid/no-innerhtml": ["error", { allowStatic: true }],
|
|
2382
|
+
"solid/no-react-deps": "error",
|
|
2383
|
+
"solid/no-react-specific-props": "error",
|
|
2407
2384
|
"solid/no-unknown-namespaces": "error",
|
|
2408
|
-
// deprecated
|
|
2409
|
-
"solid/prefer-classlist": "off",
|
|
2410
2385
|
"solid/prefer-for": "error",
|
|
2411
|
-
// handled by Solid compiler, opt-in style suggestion
|
|
2412
|
-
"solid/prefer-show": "off",
|
|
2413
2386
|
"solid/reactivity": "warn",
|
|
2414
|
-
"solid/self-closing-comp": "
|
|
2415
|
-
"solid/style-prop": "
|
|
2387
|
+
"solid/self-closing-comp": "error",
|
|
2388
|
+
"solid/style-prop": ["error", { styleProps: ["style", "css"] }],
|
|
2416
2389
|
...typescript2 ? {
|
|
2417
2390
|
"solid/jsx-no-undef": ["error", { typescriptEnabled: true }],
|
|
2418
2391
|
// namespaces taken care of by TS
|
|
@@ -2449,7 +2422,12 @@ var defaultPluginRenaming = {
|
|
|
2449
2422
|
"import-x": "import",
|
|
2450
2423
|
"n": "node",
|
|
2451
2424
|
"vitest": "test",
|
|
2452
|
-
"yml": "yaml"
|
|
2425
|
+
"yml": "yaml",
|
|
2426
|
+
"@eslint-react": "react",
|
|
2427
|
+
"@eslint-react/dom": "react-dom",
|
|
2428
|
+
"@eslint-react/hooks-extra": "react-hooks-extra",
|
|
2429
|
+
"@eslint-react/naming-convention": "react-naming-convention",
|
|
2430
|
+
"@next/next": "nextjs"
|
|
2453
2431
|
};
|
|
2454
2432
|
function luxass(options = {}, ...userConfigs) {
|
|
2455
2433
|
const {
|
|
@@ -2461,6 +2439,7 @@ function luxass(options = {}, ...userConfigs) {
|
|
|
2461
2439
|
nextjs: enableNextJS = false,
|
|
2462
2440
|
react: enableReact = false,
|
|
2463
2441
|
tailwindcss: enableTailwindCSS = false,
|
|
2442
|
+
svelte: enableSvelte = false,
|
|
2464
2443
|
solid: enableSolid = false,
|
|
2465
2444
|
typescript: enableTypeScript = isPackageExists4("typescript"),
|
|
2466
2445
|
unocss: enableUnoCSS = false,
|
|
@@ -2522,8 +2501,7 @@ function luxass(options = {}, ...userConfigs) {
|
|
|
2522
2501
|
configs.push(react({
|
|
2523
2502
|
...resolveSubOptions(options, "react"),
|
|
2524
2503
|
overrides: getOverrides(options, "react"),
|
|
2525
|
-
|
|
2526
|
-
refresh: !enableNextJS
|
|
2504
|
+
tsconfigPath: getOverrides(options, "typescript").tsconfigPath
|
|
2527
2505
|
}));
|
|
2528
2506
|
}
|
|
2529
2507
|
if (enableNextJS) {
|
|
@@ -2543,6 +2521,16 @@ function luxass(options = {}, ...userConfigs) {
|
|
|
2543
2521
|
})
|
|
2544
2522
|
);
|
|
2545
2523
|
}
|
|
2524
|
+
if (enableSvelte) {
|
|
2525
|
+
configs.push(
|
|
2526
|
+
svelte({
|
|
2527
|
+
...resolveSubOptions(options, "svelte"),
|
|
2528
|
+
overrides: getOverrides(options, "svelte"),
|
|
2529
|
+
stylistic: stylisticOptions,
|
|
2530
|
+
typescript: !!enableTypeScript
|
|
2531
|
+
})
|
|
2532
|
+
);
|
|
2533
|
+
}
|
|
2546
2534
|
if (enableVue) {
|
|
2547
2535
|
configs.push(
|
|
2548
2536
|
vue({
|
|
@@ -2619,15 +2607,15 @@ function luxass(options = {}, ...userConfigs) {
|
|
|
2619
2607
|
if (Object.keys(fusedConfig).length) {
|
|
2620
2608
|
configs.push([fusedConfig]);
|
|
2621
2609
|
}
|
|
2622
|
-
let
|
|
2623
|
-
|
|
2610
|
+
let composer = new FlatConfigComposer();
|
|
2611
|
+
composer = composer.append(
|
|
2624
2612
|
...configs,
|
|
2625
2613
|
...userConfigs
|
|
2626
2614
|
);
|
|
2627
2615
|
if (autoRenamePlugins) {
|
|
2628
|
-
|
|
2616
|
+
composer = composer.renamePlugins(defaultPluginRenaming);
|
|
2629
2617
|
}
|
|
2630
|
-
return
|
|
2618
|
+
return composer;
|
|
2631
2619
|
}
|
|
2632
2620
|
|
|
2633
2621
|
// src/index.ts
|
|
@@ -2654,6 +2642,7 @@ export {
|
|
|
2654
2642
|
GLOB_SRC,
|
|
2655
2643
|
GLOB_SRC_EXT,
|
|
2656
2644
|
GLOB_STYLE,
|
|
2645
|
+
GLOB_SVELTE,
|
|
2657
2646
|
GLOB_TESTS,
|
|
2658
2647
|
GLOB_TOML,
|
|
2659
2648
|
GLOB_TS,
|
|
@@ -2673,6 +2662,7 @@ export {
|
|
|
2673
2662
|
javascript,
|
|
2674
2663
|
jsdoc,
|
|
2675
2664
|
jsonc,
|
|
2665
|
+
luxass,
|
|
2676
2666
|
markdown,
|
|
2677
2667
|
nextjs,
|
|
2678
2668
|
node,
|
|
@@ -2684,6 +2674,7 @@ export {
|
|
|
2684
2674
|
sortPackageJson,
|
|
2685
2675
|
sortTsconfig,
|
|
2686
2676
|
stylistic,
|
|
2677
|
+
svelte,
|
|
2687
2678
|
tailwindcss,
|
|
2688
2679
|
test,
|
|
2689
2680
|
toArray,
|