@isentinel/eslint-config 6.2.0 → 6.3.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/README.md +22 -14
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +4 -24
- package/dist/index.mjs +221 -141
- package/dist/lint-cli.mjs +1 -1
- package/dist/oxfmt.mjs +44 -16
- package/dist/oxlint.mjs +40 -81
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -990,19 +990,21 @@ as in the factories, so oxfmt formats the same files the linter would. TOML,
|
|
|
990
990
|
`.mdx` and other files the linter does not format are ignored.
|
|
991
991
|
|
|
992
992
|
In standalone mode, oxfmt never sees the linter's options. The factories warn
|
|
993
|
-
once per lint run when you set any of these, because they do not change
|
|
994
|
-
|
|
995
|
-
or `gitignore` (`false` or custom files).
|
|
996
|
-
|
|
993
|
+
once per lint run when you set any of these, because they do not change what
|
|
994
|
+
oxfmt formats: `formatters` (any value except `true`), `componentExts`,
|
|
995
|
+
`ignores`, or `gitignore` (`false` or custom files). They change only which
|
|
996
|
+
Markdown code blocks ESLint formats: `formatters` chooses their languages, and
|
|
997
|
+
the ignores choose their files. Set the equivalent in `isentinelOxfmt` instead
|
|
998
|
+
(`formatters`, `componentExts`, `ignorePatterns`, and format options).
|
|
997
999
|
`stylistic: false` turns off the stylistic lint rules but not oxfmt. The rule
|
|
998
1000
|
widths also come from the oxfmt config only, not from
|
|
999
1001
|
`formatters.prettierOptions` or `formatters.oxfmtOptions`. The setup wizard
|
|
1000
1002
|
copies migrated `.eslintignore` patterns to both configs.
|
|
1001
1003
|
|
|
1002
|
-
With `formatter: "standalone"`, the linter enables `oxfmt/oxfmt`
|
|
1003
|
-
keeps the rules that turn off formatting
|
|
1004
|
-
stays in ESLint, because oxfmt does not
|
|
1005
|
-
all of this for you.
|
|
1004
|
+
With `formatter: "standalone"`, the linter enables `oxfmt/oxfmt` only in
|
|
1005
|
+
Markdown code blocks (see below), but keeps the rules that turn off formatting
|
|
1006
|
+
conflicts. Lua formatting (Stylua) stays in ESLint, because oxfmt does not
|
|
1007
|
+
format Lua. The setup wizard can write all of this for you.
|
|
1006
1008
|
|
|
1007
1009
|
`isentinel-lint` runs `oxfmt --check` next to the linters whenever it finds an
|
|
1008
1010
|
`oxfmt.config.ts` or `oxfmt.config.mts`, and `oxfmt --write` last with `--fix`.
|
|
@@ -1031,12 +1033,18 @@ becomes implicit only if it fits. It comes from `stylistic.maxLen`, else
|
|
|
1031
1033
|
`useOxfmt.printWidth` is the width the rule gives oxfmt to predict its output.
|
|
1032
1034
|
It always comes from the root `printWidth` of the oxfmt config, so that `--fix`
|
|
1033
1035
|
agrees with oxfmt. An override that changes `printWidth` or `tabWidth` for JS or
|
|
1034
|
-
TS files gets a warning, because the linter uses the root values.
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1036
|
+
TS files gets a warning, because the linter uses the root values. The comment
|
|
1037
|
+
length rules take their `tabSize` from the same oxfmt widths.
|
|
1038
|
+
|
|
1039
|
+
Markdown prose and Markdown code blocks are formatted separately, in both modes.
|
|
1040
|
+
Oxfmt formats the prose at the Markdown width (`jsdocPrintWidth`, else 80) and
|
|
1041
|
+
leaves code blocks alone (`embeddedLanguageFormatting: "off"`). ESLint formats
|
|
1042
|
+
each code block with `oxfmt/oxfmt` and the options of its language, the same as
|
|
1043
|
+
a file of that language: a TypeScript block uses the root `printWidth`, a YAML
|
|
1044
|
+
block the YAML options. Overrides and `.editorconfig` sections, which match by
|
|
1045
|
+
path, do not reach code blocks; the config's `ignorePatterns` do. The lint rules
|
|
1046
|
+
in a code block use the same widths as in a source file. ESLint does not format
|
|
1047
|
+
code blocks in files it ignores.
|
|
1040
1048
|
|
|
1041
1049
|
The stylistic `indent` and `quotes`, and the JSON bracket spacing, follow the
|
|
1042
1050
|
oxfmt options (`useTabs`, `tabWidth`, `singleQuote`, `bracketSpacing`) unless
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -27270,7 +27270,7 @@ type Yoda = [] | [("always" | "never")] | [("always" | "never"), {
|
|
|
27270
27270
|
onlyEquality?: boolean;
|
|
27271
27271
|
}];
|
|
27272
27272
|
// Names of all the configs
|
|
27273
|
-
type ConfigNames = 'isentinel/eslint/comments' | 'isentinel/eslint/comments/src' | 'isentinel/e18e/rules' | 'isentinel/eslint-plugin/setup' | 'isentinel/eslint-plugin/rules' | 'isentinel/flawless/setup' | 'isentinel/flawless/rules' | 'isentinel/flawless/
|
|
27273
|
+
type ConfigNames = 'isentinel/eslint/comments' | 'isentinel/eslint/comments/src' | 'isentinel/e18e/rules' | 'isentinel/eslint-plugin/setup' | 'isentinel/eslint-plugin/rules' | 'isentinel/flawless/setup' | 'isentinel/flawless/rules' | 'isentinel/flawless/rules-type-aware' | 'isentinel/gitignore' | 'isentinel/ignores' | 'isentinel/imports/rules' | 'isentinel/imports/game' | 'isentinel/javascript/setup' | 'isentinel/javascript/rules' | 'isentinel/jsdoc/setup' | 'isentinel/jsdoc' | 'isentinel/jsonc/setup' | 'isentinel/jsonc/rules' | 'isentinel/jsonc/tsconfig' | 'isentinel/markdown/setup' | 'isentinel/markdown/processor' | 'isentinel/markdown/parser' | 'isentinel/markdown/disables' | 'isentinel/naming/setup' | 'isentinel/naming/ts/rules-type-aware' | 'isentinel/naming/tsx/rules-type-aware' | 'isentinel/node/rules' | 'isentinel/oxfmt/setup' | 'isentinel/oxfmt/javascript' | 'isentinel/oxfmt/typescript' | 'isentinel/oxfmt/css' | 'isentinel/oxfmt/scss' | 'isentinel/oxfmt/less' | 'isentinel/oxfmt/html' | 'isentinel/oxfmt/markdown' | 'isentinel/oxfmt/graphql' | 'isentinel/oxfmt/json' | 'isentinel/oxfmt/json5' | 'isentinel/oxfmt/yaml' | 'isentinel/oxfmt/markdown-code/javascript' | 'isentinel/oxfmt/markdown-code/typescript' | 'isentinel/oxfmt/markdown-code/css' | 'isentinel/oxfmt/markdown-code/scss' | 'isentinel/oxfmt/markdown-code/less' | 'isentinel/oxfmt/markdown-code/html' | 'isentinel/oxfmt/markdown-code/graphql' | 'isentinel/oxfmt/markdown-code/json' | 'isentinel/oxfmt/markdown-code/json5' | 'isentinel/oxfmt/markdown-code/yaml' | 'isentinel/package-json/setup' | 'isentinel/package-json' | 'isentinel/package-json/root' | 'isentinel/perfectionist/setup' | 'isentinel/perfectionist' | 'isentinel/perfectionist/jsx' | 'isentinel/pnpm/setup' | 'isentinel/pnpm/package-json' | 'isentinel/pnpm/pnpm-workspace-yaml' | 'isentinel/project-structure/setup' | 'isentinel/project-structure/rules' | 'isentinel/promise' | 'isentinel/react/setup' | 'isentinel/react/setup/naming' | 'isentinel/react/setup/testing-library' | 'isentinel/react/rules' | 'isentinel/react/type-aware-rules' | 'isentinel/roblox/setup' | 'isentinel/roblox/parser' | 'isentinel/roblox/type-aware-parser' | 'isentinel/roblox' | 'isentinel/roblox/rules-type-aware' | 'isentinel/roblox/format-lua/setup' | 'isentinel/roblox/format-lua' | 'isentinel/small-rules/setup' | 'isentinel/small-rules' | 'isentinel/sonarjs' | 'isentinel/spelling/setup' | 'isentinel/spelling' | 'isentinel/stylistic/setup' | 'isentinel/stylistic' | 'isentinel/test/jest/setup' | 'isentinel/test/jest/rules' | 'isentinel/test/jest/type-tests' | 'isentinel/test/vitest/setup' | 'isentinel/test/vitest/rules' | 'isentinel/test/vitest/type-tests' | 'isentinel/toml/setup' | 'isentinel/toml/rules' | 'isentinel/typescript/setup' | 'isentinel/typescript/parser' | 'isentinel/typescript/type-aware-parser' | 'isentinel/typescript/rules' | 'isentinel/typescript/rules-type-aware' | 'isentinel/typescript/erasable-syntax-only' | 'isentinel/unicorn/setup' | 'isentinel/unicorn/rules' | 'isentinel/unicorn/root' | 'isentinel/yaml/setup' | 'isentinel/yaml/rules';
|
|
27274
27274
|
//#endregion
|
|
27275
27275
|
//#region src/utils.d.ts
|
|
27276
27276
|
type ExtractRuleOptions<T> = T extends Linter.RuleEntry<infer U> ? U : never;
|
|
@@ -27315,21 +27315,12 @@ type OxfmtOptions = Omit<FormatConfig, "jsdoc"> & {
|
|
|
27315
27315
|
lineWrappingStyle?: "balance" | "greedy";
|
|
27316
27316
|
});
|
|
27317
27317
|
};
|
|
27318
|
-
/** The widths oxfmt formats Markdown files with. */
|
|
27319
|
-
interface MarkdownWidths {
|
|
27320
|
-
printWidth?: number;
|
|
27321
|
-
tabWidth?: number;
|
|
27322
|
-
}
|
|
27323
|
-
/** A config override that changes the widths of some Markdown files. */
|
|
27324
27318
|
/** Where an oxfmt override applies, relative to the config directory. */
|
|
27325
27319
|
interface OverrideScope {
|
|
27326
27320
|
/** Globs it skips: its `excludeFiles` and its negated `files`. */
|
|
27327
27321
|
excludeFiles: Array<string>;
|
|
27328
27322
|
files: Array<string>;
|
|
27329
27323
|
}
|
|
27330
|
-
interface MarkdownWidthOverride extends OverrideScope {
|
|
27331
|
-
widths: MarkdownWidths;
|
|
27332
|
-
}
|
|
27333
27324
|
//#endregion
|
|
27334
27325
|
//#region src/types.d.ts
|
|
27335
27326
|
type Awaitable<T> = Promise<T> | T;
|
|
@@ -28362,12 +28353,7 @@ declare const GLOB_ALL_SRC: string[];
|
|
|
28362
28353
|
declare const GLOB_EXCLUDE: string[];
|
|
28363
28354
|
//#endregion
|
|
28364
28355
|
//#region src/eslint/configs/comments.d.ts
|
|
28365
|
-
declare function comments({
|
|
28366
|
-
/** The widths oxfmt formats Markdown code blocks with. */
|
|
28367
|
-
markdownCode?: MarkdownWidths;
|
|
28368
|
-
/** Oxfmt config overrides that change the Markdown widths. */
|
|
28369
|
-
markdownCodeOverrides?: Array<MarkdownWidthOverride>;
|
|
28370
|
-
}): Promise<Array<TypedFlatConfigItem>>;
|
|
28356
|
+
declare function comments({ prettierOptions, stylistic }?: OptionsFormatters & OptionsStylistic): Promise<Array<TypedFlatConfigItem>>;
|
|
28371
28357
|
//#endregion
|
|
28372
28358
|
//#region src/eslint/configs/disables.d.ts
|
|
28373
28359
|
/**
|
|
@@ -28415,6 +28401,8 @@ interface FlawlessRuleOptions extends OptionsHasRoblox {
|
|
|
28415
28401
|
declare function oxfmt(options?: OptionsComponentExtensions & OptionsFiles & OptionsOverrides & {
|
|
28416
28402
|
formatters?: OptionsFormatters | true;
|
|
28417
28403
|
oxfmtConfigOptions?: OxfmtOptions;
|
|
28404
|
+
/** The oxfmt config's ignore patterns, for Markdown code blocks. */
|
|
28405
|
+
oxfmtIgnorePatterns?: Array<string>;
|
|
28418
28406
|
oxfmtOptions?: OxfmtOptions;
|
|
28419
28407
|
oxlint?: boolean;
|
|
28420
28408
|
prettierOptions?: Options;
|
|
@@ -28433,14 +28421,6 @@ declare function flawless(options?: FlawlessRuleOptions & OptionsOverridesTypeAw
|
|
|
28433
28421
|
* linted as standard-TS/Node land.
|
|
28434
28422
|
*/
|
|
28435
28423
|
complementIgnores?: Array<string>;
|
|
28436
|
-
/**
|
|
28437
|
-
* The widths oxfmt formats Markdown code blocks with, when it
|
|
28438
|
-
* formats Markdown: it formats embedded code with the Markdown
|
|
28439
|
-
* options, not the root ones.
|
|
28440
|
-
*/
|
|
28441
|
-
markdownCode?: MarkdownWidths;
|
|
28442
|
-
/** Oxfmt config overrides that change the Markdown widths. */
|
|
28443
|
-
markdownCodeOverrides?: Array<MarkdownWidthOverride>;
|
|
28444
28424
|
}, prettierOptions?: PrettierOptions): Promise<Array<TypedFlatConfigItem>>;
|
|
28445
28425
|
//#endregion
|
|
28446
28426
|
//#region src/eslint/configs/gitignore.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -764,6 +764,32 @@ function editorConfigToOxfmt(properties) {
|
|
|
764
764
|
return options;
|
|
765
765
|
}
|
|
766
766
|
//#endregion
|
|
767
|
+
//#region src/guards.ts
|
|
768
|
+
/**
|
|
769
|
+
* Internal runtime type guards. Prefer these over `as` assertions so values
|
|
770
|
+
* crossing untyped boundaries (`JSON.parse`, dynamic `import`, plugin objects)
|
|
771
|
+
* are validated at runtime rather than asserted away.
|
|
772
|
+
*/
|
|
773
|
+
/**
|
|
774
|
+
* Whether a value is a non-null, non-array object usable as a string-keyed
|
|
775
|
+
* record. Narrows `unknown` without an assertion.
|
|
776
|
+
*
|
|
777
|
+
* @param value - The value to test.
|
|
778
|
+
* @returns Whether the value is a plain object.
|
|
779
|
+
*/
|
|
780
|
+
function isRecord(value) {
|
|
781
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Whether a value is an array whose every element is a string.
|
|
785
|
+
*
|
|
786
|
+
* @param value - The value to test.
|
|
787
|
+
* @returns Whether the value is a `string` array.
|
|
788
|
+
*/
|
|
789
|
+
function isStringArray(value) {
|
|
790
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
791
|
+
}
|
|
792
|
+
//#endregion
|
|
767
793
|
//#region src/rules/oxfmt.ts
|
|
768
794
|
const UNSUPPORTED_PRETTIER_KEYS = /* @__PURE__ */ new Set([
|
|
769
795
|
"experimentalOperatorPosition",
|
|
@@ -830,12 +856,12 @@ function migratePrettierOptions(prettierOptions) {
|
|
|
830
856
|
function migratePrettierOverrides(overrides) {
|
|
831
857
|
if (!Array.isArray(overrides)) return [];
|
|
832
858
|
return overrides.flatMap((override) => {
|
|
833
|
-
if (
|
|
859
|
+
if (!isRecord(override)) return [];
|
|
834
860
|
const { excludeFiles, files, options } = override;
|
|
835
861
|
return [{
|
|
836
862
|
...excludeFiles === void 0 ? {} : { excludeFiles: stringsOf(excludeFiles) },
|
|
837
863
|
files: stringsOf(files),
|
|
838
|
-
options:
|
|
864
|
+
options: isRecord(options) ? migratePrettierOptions(options) : {}
|
|
839
865
|
}];
|
|
840
866
|
});
|
|
841
867
|
}
|
|
@@ -860,11 +886,16 @@ function buildOxfmtOptions({ oxfmtConfigOptions = {}, oxfmtOptions, prettierOpti
|
|
|
860
886
|
* ESLint config and the standalone oxfmt config so both format Markdown the
|
|
861
887
|
* same way.
|
|
862
888
|
*
|
|
889
|
+
* Oxfmt would format code blocks with these options too, at the prose width.
|
|
890
|
+
* It leaves them alone instead, and ESLint formats each block with the options
|
|
891
|
+
* of its own language (see `isentinel/oxfmt/markdown-code/*`).
|
|
892
|
+
*
|
|
863
893
|
* @param jsdocPrintWidth - Width for Markdown prose; 80 when unset.
|
|
864
894
|
* @returns Options applied on top of the base for Markdown files.
|
|
865
895
|
*/
|
|
866
896
|
function markdownOxfmtOptions(jsdocPrintWidth) {
|
|
867
897
|
return {
|
|
898
|
+
embeddedLanguageFormatting: "off",
|
|
868
899
|
printWidth: Number(jsdocPrintWidth) || 80,
|
|
869
900
|
proseWrap: "always",
|
|
870
901
|
tabWidth: 2
|
|
@@ -885,23 +916,6 @@ const YAML_OXFMT_OPTIONS = {
|
|
|
885
916
|
useTabs: false
|
|
886
917
|
};
|
|
887
918
|
//#endregion
|
|
888
|
-
//#region src/guards.ts
|
|
889
|
-
/**
|
|
890
|
-
* Internal runtime type guards. Prefer these over `as` assertions so values
|
|
891
|
-
* crossing untyped boundaries (`JSON.parse`, dynamic `import`, plugin objects)
|
|
892
|
-
* are validated at runtime rather than asserted away.
|
|
893
|
-
*/
|
|
894
|
-
/**
|
|
895
|
-
* Whether a value is a non-null, non-array object usable as a string-keyed
|
|
896
|
-
* record. Narrows `unknown` without an assertion.
|
|
897
|
-
*
|
|
898
|
-
* @param value - The value to test.
|
|
899
|
-
* @returns Whether the value is a plain object.
|
|
900
|
-
*/
|
|
901
|
-
function isRecord(value) {
|
|
902
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
903
|
-
}
|
|
904
|
-
//#endregion
|
|
905
919
|
//#region src/rules/react.ts
|
|
906
920
|
const DOM_IMPORT_MESSAGE = "Import from react-testing-library-lua instead; it re-exports the DOM utilities, and eslint-plugin-testing-library only detects one module per file.";
|
|
907
921
|
/**
|
|
@@ -1507,8 +1521,6 @@ const SCRIPT_EXTENSIONS = [
|
|
|
1507
1521
|
"ts",
|
|
1508
1522
|
"tsx"
|
|
1509
1523
|
];
|
|
1510
|
-
/** The extensions of the Markdown files ESLint lints code blocks in. */
|
|
1511
|
-
const MARKDOWN_EXTENSIONS = ["md"];
|
|
1512
1524
|
const JSON_EXTENSIONS = [
|
|
1513
1525
|
"json",
|
|
1514
1526
|
"json5",
|
|
@@ -1553,21 +1565,13 @@ function findOxfmtConfig(cwd = process.cwd()) {
|
|
|
1553
1565
|
}
|
|
1554
1566
|
}
|
|
1555
1567
|
/**
|
|
1556
|
-
* The
|
|
1568
|
+
* The string globs of an override's `files` or `excludeFiles`.
|
|
1557
1569
|
*
|
|
1558
|
-
* @param
|
|
1559
|
-
* @returns
|
|
1570
|
+
* @param value - One glob or a list of them, of unknown shape.
|
|
1571
|
+
* @returns The string globs.
|
|
1560
1572
|
*/
|
|
1561
|
-
function
|
|
1562
|
-
|
|
1563
|
-
return overrides.flatMap((override) => {
|
|
1564
|
-
if (!isRecord(override) || !overrideMatches(override, MARKDOWN_EXTENSIONS)) return [];
|
|
1565
|
-
const widths = widthsOf(override["options"]);
|
|
1566
|
-
return Object.keys(widths).length > 0 ? [{
|
|
1567
|
-
...scopeOf(override),
|
|
1568
|
-
widths
|
|
1569
|
-
}] : [];
|
|
1570
|
-
});
|
|
1573
|
+
function globsOf(value) {
|
|
1574
|
+
return [value].flat().filter((glob) => typeof glob === "string");
|
|
1571
1575
|
}
|
|
1572
1576
|
/**
|
|
1573
1577
|
* Where an override applies: its `files`, minus its `excludeFiles` and any
|
|
@@ -1577,12 +1581,9 @@ function markdownOverridesOf(overrides) {
|
|
|
1577
1581
|
* @returns Its scope.
|
|
1578
1582
|
*/
|
|
1579
1583
|
function scopeOf(override) {
|
|
1580
|
-
const
|
|
1581
|
-
return [value].flat().filter((glob) => typeof glob === "string");
|
|
1582
|
-
};
|
|
1583
|
-
const globs = strings(override["files"]);
|
|
1584
|
+
const globs = globsOf(override["files"]);
|
|
1584
1585
|
return {
|
|
1585
|
-
excludeFiles: [...
|
|
1586
|
+
excludeFiles: [...globsOf(override["excludeFiles"]), ...globs.filter((glob) => glob.startsWith("!")).map((glob) => glob.slice(1))],
|
|
1586
1587
|
files: globs.filter((glob) => !glob.startsWith("!"))
|
|
1587
1588
|
};
|
|
1588
1589
|
}
|
|
@@ -1609,7 +1610,8 @@ function jsonLayoutOverrides(overrides) {
|
|
|
1609
1610
|
}
|
|
1610
1611
|
/**
|
|
1611
1612
|
* Warn, at most once per process, about factory options that do not reach
|
|
1612
|
-
* standalone oxfmt: it formats with `oxfmt.config.ts` alone.
|
|
1613
|
+
* standalone oxfmt: it formats with `oxfmt.config.ts` alone. They still choose
|
|
1614
|
+
* which Markdown code blocks ESLint formats.
|
|
1613
1615
|
*
|
|
1614
1616
|
* @param options - The factory options.
|
|
1615
1617
|
* @param options.componentExts - Oxfmt formats only the extensions
|
|
@@ -1630,7 +1632,7 @@ function warnStandaloneOptions({ componentExts, formatters, gitignore, ignores }
|
|
|
1630
1632
|
].filter((name) => name !== void 0);
|
|
1631
1633
|
if (names.length > 0) {
|
|
1632
1634
|
state[WARNED_STANDALONE] = true;
|
|
1633
|
-
console.warn(`[@isentinel/eslint-config] With formatter: "standalone", oxfmt formats with oxfmt.config.ts alone, so these options do not change
|
|
1635
|
+
console.warn(`[@isentinel/eslint-config] With formatter: "standalone", oxfmt formats with oxfmt.config.ts alone, so these options do not change what oxfmt formats: ${names.join(", ")}. They change only which Markdown code blocks ESLint formats. Set the equivalent in isentinelOxfmt() (formatters, componentExts, ignorePatterns, format options).`);
|
|
1634
1636
|
}
|
|
1635
1637
|
}
|
|
1636
1638
|
/**
|
|
@@ -1658,8 +1660,7 @@ function warnScriptWidthOverrides(overrides, source) {
|
|
|
1658
1660
|
* {@link findOxfmtConfig}): `.oxfmtrc.json`, `.oxfmtrc.jsonc`,
|
|
1659
1661
|
* `oxfmt.config.ts` or `oxfmt.config.mts`.
|
|
1660
1662
|
*
|
|
1661
|
-
* @returns The format options and
|
|
1662
|
-
* found.
|
|
1663
|
+
* @returns The format options and overrides; empty options if none found.
|
|
1663
1664
|
* @rejects When the config is ambiguous or cannot be loaded.
|
|
1664
1665
|
*/
|
|
1665
1666
|
async function resolveOxfmtConfig() {
|
|
@@ -1748,26 +1749,26 @@ function mirrorsSection(override, sections) {
|
|
|
1748
1749
|
});
|
|
1749
1750
|
}
|
|
1750
1751
|
/**
|
|
1751
|
-
* Turn a loaded oxfmt config into `oxfmt/oxfmt` rule options
|
|
1752
|
-
*
|
|
1753
|
-
* and `overrides` are dropped from the options.
|
|
1752
|
+
* Turn a loaded oxfmt config into `oxfmt/oxfmt` rule options, its ignore
|
|
1753
|
+
* patterns and its overrides. The rule takes format options only, so
|
|
1754
|
+
* `$schema`, `ignorePatterns` and `overrides` are dropped from the options.
|
|
1754
1755
|
*
|
|
1755
1756
|
* @param config - The loaded config.
|
|
1756
1757
|
* @param config.$schema - Dropped.
|
|
1757
|
-
* @param config.ignorePatterns - Dropped; oxfmt applies them
|
|
1758
|
-
*
|
|
1759
|
-
*
|
|
1758
|
+
* @param config.ignorePatterns - Dropped from the options; oxfmt applies them
|
|
1759
|
+
* itself, except in Markdown code blocks.
|
|
1760
|
+
* @param config.overrides - Dropped from the options, after the width check.
|
|
1760
1761
|
* @param configPath - The config file, for the warning.
|
|
1761
|
-
* @returns The format options and
|
|
1762
|
+
* @returns The format options, ignore patterns and overrides.
|
|
1762
1763
|
*/
|
|
1763
|
-
function toResolvedConfig({ $schema: _schema, ignorePatterns
|
|
1764
|
+
function toResolvedConfig({ $schema: _schema, ignorePatterns, overrides, ...options }, configPath) {
|
|
1764
1765
|
const sections = editorConfigOverrides(path.dirname(configPath));
|
|
1765
1766
|
const list = Array.isArray(overrides) ? overrides : [];
|
|
1766
1767
|
const copied = list.filter((override) => mirrorsSection(override, sections));
|
|
1767
1768
|
warnScriptWidthOverrides(copied, ".editorconfig");
|
|
1768
1769
|
warnScriptWidthOverrides(list.filter((override) => !copied.includes(override)), path.basename(configPath));
|
|
1769
1770
|
return {
|
|
1770
|
-
|
|
1771
|
+
ignorePatterns: isStringArray(ignorePatterns) ? ignorePatterns : [],
|
|
1771
1772
|
options,
|
|
1772
1773
|
overrides: Array.isArray(overrides) ? overrides : []
|
|
1773
1774
|
};
|
|
@@ -1787,20 +1788,6 @@ function rcConfig(configPath, content) {
|
|
|
1787
1788
|
return toResolvedConfig(parsed, configPath);
|
|
1788
1789
|
}
|
|
1789
1790
|
/**
|
|
1790
|
-
* Pick `printWidth` and `tabWidth` out of a set of format options.
|
|
1791
|
-
*
|
|
1792
|
-
* @param options - Format options, of unknown shape.
|
|
1793
|
-
* @returns The widths it sets.
|
|
1794
|
-
*/
|
|
1795
|
-
function widthsOf(options) {
|
|
1796
|
-
if (!isRecord(options)) return {};
|
|
1797
|
-
const { printWidth, tabWidth } = options;
|
|
1798
|
-
return {
|
|
1799
|
-
...typeof printWidth === "number" ? { printWidth } : {},
|
|
1800
|
-
...typeof tabWidth === "number" ? { tabWidth } : {}
|
|
1801
|
-
};
|
|
1802
|
-
}
|
|
1803
|
-
/**
|
|
1804
1791
|
* Resolves the lowest Node major version a semver range can match.
|
|
1805
1792
|
*
|
|
1806
1793
|
* @param range - A semver range such as `>=24.12.0` or `^24 || ^26`.
|
|
@@ -1979,15 +1966,7 @@ function hydrate(specifier, transform) {
|
|
|
1979
1966
|
//#endregion
|
|
1980
1967
|
//#region src/eslint/configs/comments.ts
|
|
1981
1968
|
init_globs();
|
|
1982
|
-
async function comments({
|
|
1983
|
-
function lengthRules(tabSize) {
|
|
1984
|
-
return commentLengthRules({
|
|
1985
|
-
maxLength: (Number(prettierOptions["jsdocPrintWidth"]) || 80) + 2,
|
|
1986
|
-
multiLineMaxLength: Number(prettierOptions["jsdocPrintWidth"]) || 80,
|
|
1987
|
-
semanticComments: ["oxlint-disable", "oxlint-enable"],
|
|
1988
|
-
tabSize: tabSize ?? prettierOptions.tabWidth ?? 4
|
|
1989
|
-
});
|
|
1990
|
-
}
|
|
1969
|
+
async function comments({ prettierOptions = {}, stylistic = true } = {}) {
|
|
1991
1970
|
const pluginCommentLength = lazyPlugin("eslint-plugin-comment-length");
|
|
1992
1971
|
const pluginStylistic = lazyPlugin("@stylistic/eslint-plugin");
|
|
1993
1972
|
return [{
|
|
@@ -2009,19 +1988,13 @@ async function comments({ markdownCode, markdownCodeOverrides = [], prettierOpti
|
|
|
2009
1988
|
}, ...stylistic !== false ? [{
|
|
2010
1989
|
name: "isentinel/eslint/comments/src",
|
|
2011
1990
|
files: [GLOB_SRC],
|
|
2012
|
-
rules:
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
name: `isentinel/eslint/comments/markdown-code/override-${index}`,
|
|
2020
|
-
files: files.map((glob) => `${glob}/${GLOB_SRC}`),
|
|
2021
|
-
ignores: excludeFiles.map((glob) => `${glob}/**`),
|
|
2022
|
-
rules: lengthRules(widths.tabWidth ?? markdownCode.tabWidth)
|
|
2023
|
-
};
|
|
2024
|
-
})]] : []];
|
|
1991
|
+
rules: commentLengthRules({
|
|
1992
|
+
maxLength: (Number(prettierOptions["jsdocPrintWidth"]) || 80) + 2,
|
|
1993
|
+
multiLineMaxLength: Number(prettierOptions["jsdocPrintWidth"]) || 80,
|
|
1994
|
+
semanticComments: ["oxlint-disable", "oxlint-enable"],
|
|
1995
|
+
tabSize: prettierOptions.tabWidth ?? 4
|
|
1996
|
+
})
|
|
1997
|
+
}] : []];
|
|
2025
1998
|
}
|
|
2026
1999
|
//#endregion
|
|
2027
2000
|
//#region src/eslint/configs/disables.ts
|
|
@@ -2299,24 +2272,6 @@ async function eslintPlugin({ files = [GLOB_SRC], overrides = {} } = {}) {
|
|
|
2299
2272
|
//#endregion
|
|
2300
2273
|
//#region src/rules/flawless.ts
|
|
2301
2274
|
/**
|
|
2302
|
-
* Arrow return style rule on its own, for the Markdown code block override
|
|
2303
|
-
* where only the line width differs.
|
|
2304
|
-
*
|
|
2305
|
-
* @param options - Shared rule options.
|
|
2306
|
-
* @returns The rule map.
|
|
2307
|
-
*/
|
|
2308
|
-
function arrowStyleRules({ maxLen, maxLength, printWidth, tabWidth } = {}) {
|
|
2309
|
-
return { "flawless/arrow-return-style": ["error", {
|
|
2310
|
-
jsxAlwaysUseExplicitReturn: true,
|
|
2311
|
-
maxLen: maxLength ?? maxLen ?? printWidth ?? 100,
|
|
2312
|
-
maxObjectProperties: 2,
|
|
2313
|
-
namedExportsAlwaysUseExplicitReturn: true,
|
|
2314
|
-
objectReturnStyle: "complex-explicit",
|
|
2315
|
-
...tabWidth !== void 0 ? { tabWidth } : {},
|
|
2316
|
-
...printWidth !== void 0 ? { useOxfmt: { printWidth } } : {}
|
|
2317
|
-
}] };
|
|
2318
|
-
}
|
|
2319
|
-
/**
|
|
2320
2275
|
* Base (non-React) flawless rules shared between the ESLint and oxlint
|
|
2321
2276
|
* factories. The React flawless rules live in the react rule map; the
|
|
2322
2277
|
* type-aware rules live in {@link flawlessTypeAwareRules}, plus the type-aware
|
|
@@ -2377,6 +2332,23 @@ function antiSlopRules({ roblox = true }) {
|
|
|
2377
2332
|
};
|
|
2378
2333
|
}
|
|
2379
2334
|
/**
|
|
2335
|
+
* The arrow return style rule.
|
|
2336
|
+
*
|
|
2337
|
+
* @param options - Shared rule options.
|
|
2338
|
+
* @returns The rule map.
|
|
2339
|
+
*/
|
|
2340
|
+
function arrowStyleRules({ maxLen, printWidth, tabWidth } = {}) {
|
|
2341
|
+
return { "flawless/arrow-return-style": ["error", {
|
|
2342
|
+
jsxAlwaysUseExplicitReturn: true,
|
|
2343
|
+
maxLen: maxLen ?? printWidth ?? 100,
|
|
2344
|
+
maxObjectProperties: 2,
|
|
2345
|
+
namedExportsAlwaysUseExplicitReturn: true,
|
|
2346
|
+
objectReturnStyle: "complex-explicit",
|
|
2347
|
+
...tabWidth !== void 0 ? { tabWidth } : {},
|
|
2348
|
+
...printWidth !== void 0 ? { useOxfmt: { printWidth } } : {}
|
|
2349
|
+
}] };
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2380
2352
|
* Type-aware anti-slop rules.
|
|
2381
2353
|
*
|
|
2382
2354
|
* `flawless/no-reflect-set` is complement-only, like `flawless/no-reflect-get`.
|
|
@@ -2397,7 +2369,7 @@ function antiSlopTypeAwareRules({ roblox = true }) {
|
|
|
2397
2369
|
//#region src/eslint/configs/flawless.ts
|
|
2398
2370
|
init_globs();
|
|
2399
2371
|
async function flawless(options = {}, prettierOptions = {}) {
|
|
2400
|
-
const { antiSlop = false, complementIgnores,
|
|
2372
|
+
const { antiSlop = false, complementIgnores, overridesTypeAware = {}, roblox = true, stylistic = true, typeAware = true } = options;
|
|
2401
2373
|
const eslintPluginFlawless = await interopDefault(import("eslint-plugin-flawless"));
|
|
2402
2374
|
const filesTypeAware = [GLOB_TS, GLOB_TSX];
|
|
2403
2375
|
const ignoresTypeAware = options.ignoresTypeAware ?? [`**/*.md/**`, "**/*.d.{,c,m}ts"];
|
|
@@ -2412,13 +2384,6 @@ async function flawless(options = {}, prettierOptions = {}) {
|
|
|
2412
2384
|
stylistic,
|
|
2413
2385
|
tabWidth
|
|
2414
2386
|
};
|
|
2415
|
-
function markdownCodeRules(widths) {
|
|
2416
|
-
return arrowStyleRules({
|
|
2417
|
-
maxLength: Number(prettierOptions["jsdocPrintWidth"]) || 80,
|
|
2418
|
-
printWidth: widths.printWidth ?? printWidth,
|
|
2419
|
-
tabWidth: widths.tabWidth ?? tabWidth
|
|
2420
|
-
});
|
|
2421
|
-
}
|
|
2422
2387
|
return [
|
|
2423
2388
|
{
|
|
2424
2389
|
name: "isentinel/flawless/setup",
|
|
@@ -2432,21 +2397,6 @@ async function flawless(options = {}, prettierOptions = {}) {
|
|
|
2432
2397
|
roblox
|
|
2433
2398
|
})
|
|
2434
2399
|
},
|
|
2435
|
-
...stylistic !== false ? [{
|
|
2436
|
-
name: "isentinel/flawless/markdown-code",
|
|
2437
|
-
files: [GLOB_MARKDOWN_CODE],
|
|
2438
|
-
rules: markdownCodeRules(markdownCode)
|
|
2439
|
-
}, ...markdownCodeOverrides.map(({ excludeFiles, files, widths }, index) => {
|
|
2440
|
-
return {
|
|
2441
|
-
name: `isentinel/flawless/markdown-code/override-${index}`,
|
|
2442
|
-
files: files.map((glob) => `${glob}/${GLOB_SRC}`),
|
|
2443
|
-
ignores: excludeFiles.map((glob) => `${glob}/**`),
|
|
2444
|
-
rules: markdownCodeRules({
|
|
2445
|
-
...markdownCode,
|
|
2446
|
-
...widths
|
|
2447
|
-
})
|
|
2448
|
-
};
|
|
2449
|
-
})] : [],
|
|
2450
2400
|
...complementIgnores ? [{
|
|
2451
2401
|
name: "isentinel/flawless/complement",
|
|
2452
2402
|
files: [GLOB_SRC],
|
|
@@ -3915,6 +3865,53 @@ function resolveFormattedLanguages(formatters = true) {
|
|
|
3915
3865
|
};
|
|
3916
3866
|
}
|
|
3917
3867
|
//#endregion
|
|
3868
|
+
//#region src/eslint/oxfmt-markdown-code.ts
|
|
3869
|
+
/** As `GLOB_MARKDOWN`, case-sensitive. */
|
|
3870
|
+
const MARKDOWN_FILE = /\.md$/;
|
|
3871
|
+
/**
|
|
3872
|
+
* Wrap eslint-plugin-oxfmt so `oxfmt/oxfmt` formats Markdown code blocks.
|
|
3873
|
+
*
|
|
3874
|
+
* The rule skips every virtual file, so a code block is formatted only by
|
|
3875
|
+
* the formatter of the file it is in. Oxfmt formats Markdown code blocks at
|
|
3876
|
+
* the prose width, so the preset turns that off and lets the rule format each
|
|
3877
|
+
* block with the options of its own language. Virtual files of other
|
|
3878
|
+
* processors (Vue blocks, say) stay skipped: oxfmt formats those files whole.
|
|
3879
|
+
*
|
|
3880
|
+
* @param plugin - The loaded plugin.
|
|
3881
|
+
* @returns The plugin with the wrapped rule.
|
|
3882
|
+
*/
|
|
3883
|
+
function oxfmtMarkdownCode(plugin) {
|
|
3884
|
+
const { rules } = plugin;
|
|
3885
|
+
const rule = rules?.["oxfmt"];
|
|
3886
|
+
if (rule === void 0) return plugin;
|
|
3887
|
+
return {
|
|
3888
|
+
...plugin,
|
|
3889
|
+
rules: {
|
|
3890
|
+
...rules,
|
|
3891
|
+
oxfmt: markdownCodeRule(rule)
|
|
3892
|
+
}
|
|
3893
|
+
};
|
|
3894
|
+
}
|
|
3895
|
+
/**
|
|
3896
|
+
* Whether a file is a code block of a Markdown file.
|
|
3897
|
+
*
|
|
3898
|
+
* @param context - The rule context.
|
|
3899
|
+
* @returns Whether the file is a Markdown code block.
|
|
3900
|
+
*/
|
|
3901
|
+
function isMarkdownCodeBlock({ filename, physicalFilename }) {
|
|
3902
|
+
return filename !== physicalFilename && MARKDOWN_FILE.test(physicalFilename);
|
|
3903
|
+
}
|
|
3904
|
+
function markdownCodeRule(rule) {
|
|
3905
|
+
return {
|
|
3906
|
+
...rule,
|
|
3907
|
+
create(context) {
|
|
3908
|
+
if (!isMarkdownCodeBlock(context)) return rule.create(context);
|
|
3909
|
+
const proxy = Object.create(context, { physicalFilename: { value: context.filename } });
|
|
3910
|
+
return rule.create(proxy);
|
|
3911
|
+
}
|
|
3912
|
+
};
|
|
3913
|
+
}
|
|
3914
|
+
//#endregion
|
|
3918
3915
|
//#region src/eslint/oxfmt-single-fix.ts
|
|
3919
3916
|
/** Records the edit a fix makes, instead of making it. */
|
|
3920
3917
|
const recordingFixer = { replaceTextRange(range, text) {
|
|
@@ -4028,7 +4025,7 @@ const defaultPluginRenaming = {
|
|
|
4028
4025
|
//#region src/eslint/configs/oxfmt.ts
|
|
4029
4026
|
init_globs();
|
|
4030
4027
|
async function oxfmt(options) {
|
|
4031
|
-
const { componentExts: componentExtensions = [], files: oxfmtFiles, formatters = {}, oxfmtConfigOptions = {}, oxfmtOptions: userOxfmtOptions, oxlint: enableOxlint = false, prettierOptions = {}, standalone = false } = options ?? {};
|
|
4028
|
+
const { componentExts: componentExtensions = [], files: oxfmtFiles, formatters = {}, oxfmtConfigOptions = {}, oxfmtIgnorePatterns = [], oxfmtOptions: userOxfmtOptions, oxlint: enableOxlint = false, prettierOptions = {}, standalone = false } = options ?? {};
|
|
4032
4029
|
const languages = resolveFormattedLanguages(formatters);
|
|
4033
4030
|
const oxfmtOptions = buildOxfmtOptions({
|
|
4034
4031
|
oxfmtConfigOptions,
|
|
@@ -4049,7 +4046,28 @@ async function oxfmt(options) {
|
|
|
4049
4046
|
disableNestedConfig: true
|
|
4050
4047
|
}] };
|
|
4051
4048
|
}
|
|
4052
|
-
|
|
4049
|
+
/**
|
|
4050
|
+
* The `oxfmt/oxfmt` entry for Markdown code blocks, in every mode: oxfmt
|
|
4051
|
+
* leaves them alone, and oxlint cannot read Markdown. A code block takes
|
|
4052
|
+
* the root options of its language only: the rule does not load the
|
|
4053
|
+
* config, so its overrides and the `.editorconfig` sections, which match
|
|
4054
|
+
* by path, do not reach the block. The config's ignore patterns still do.
|
|
4055
|
+
*
|
|
4056
|
+
* @param layer - Options applied over the base options.
|
|
4057
|
+
* @returns The rule entry.
|
|
4058
|
+
*/
|
|
4059
|
+
function codeBlockRule(layer = {}) {
|
|
4060
|
+
return { "oxfmt/oxfmt": ["error", {
|
|
4061
|
+
...oxfmtOptions,
|
|
4062
|
+
...layer,
|
|
4063
|
+
ignorePatterns: oxfmtIgnorePatterns,
|
|
4064
|
+
overrides: [],
|
|
4065
|
+
useConfig: false
|
|
4066
|
+
}] };
|
|
4067
|
+
}
|
|
4068
|
+
const pluginOxfmt = lazyPlugin("eslint-plugin-oxfmt", (plugin) => {
|
|
4069
|
+
return oxfmtSingleFix(oxfmtMarkdownCode(plugin));
|
|
4070
|
+
});
|
|
4053
4071
|
const configPrettier = await interopDefault(import("eslint-config-prettier/flat"));
|
|
4054
4072
|
const rulesToIgnore = ["curly", "style/quotes"];
|
|
4055
4073
|
const rules = renameRules(configPrettier.rules, defaultPluginRenaming);
|
|
@@ -4091,9 +4109,80 @@ async function oxfmt(options) {
|
|
|
4091
4109
|
files: [...FORMATTED_FILES.yaml],
|
|
4092
4110
|
rules: formatRule(YAML_OXFMT_OPTIONS)
|
|
4093
4111
|
});
|
|
4112
|
+
const codeBlocks = markdownCodeBlocks(languages, componentExtensions).map(([name, files, layer]) => {
|
|
4113
|
+
return {
|
|
4114
|
+
name: `isentinel/oxfmt/markdown-code/${name}`,
|
|
4115
|
+
files: files.map((glob) => `${GLOB_MARKDOWN}/${glob}`),
|
|
4116
|
+
rules: codeBlockRule(layer)
|
|
4117
|
+
};
|
|
4118
|
+
});
|
|
4119
|
+
if (languages.markdown) configs.push(...codeBlocks);
|
|
4120
|
+
else configs.push({
|
|
4121
|
+
name: "isentinel/oxfmt/markdown-code",
|
|
4122
|
+
files: codeBlocks.flatMap((block) => block.files),
|
|
4123
|
+
rules: { "oxfmt/oxfmt": "off" }
|
|
4124
|
+
});
|
|
4094
4125
|
return configs;
|
|
4095
4126
|
}
|
|
4096
4127
|
/**
|
|
4128
|
+
* The code-block languages to format, with the options each one uses: the
|
|
4129
|
+
* same as a file of that language. Markdown blocks are left out: a config
|
|
4130
|
+
* that matches their virtual `*.md/*.md` files makes ESLint fail.
|
|
4131
|
+
*
|
|
4132
|
+
* @param languages - Which languages are formatted.
|
|
4133
|
+
* @param componentExtensions - Component extensions formatted as TypeScript.
|
|
4134
|
+
* @returns The code-block languages.
|
|
4135
|
+
*/
|
|
4136
|
+
function markdownCodeBlocks(languages, componentExtensions) {
|
|
4137
|
+
const blocks = [[
|
|
4138
|
+
"javascript",
|
|
4139
|
+
[...FORMATTED_FILES.javascript],
|
|
4140
|
+
{}
|
|
4141
|
+
], [
|
|
4142
|
+
"typescript",
|
|
4143
|
+
[...FORMATTED_FILES.typescript, ...componentExtensions.map((extension) => `**/*.${extension}`)],
|
|
4144
|
+
{}
|
|
4145
|
+
]];
|
|
4146
|
+
if (languages.css) blocks.push([
|
|
4147
|
+
"css",
|
|
4148
|
+
[...FORMATTED_FILES.css],
|
|
4149
|
+
{}
|
|
4150
|
+
], [
|
|
4151
|
+
"scss",
|
|
4152
|
+
[...FORMATTED_FILES.scss],
|
|
4153
|
+
{}
|
|
4154
|
+
], [
|
|
4155
|
+
"less",
|
|
4156
|
+
[...FORMATTED_FILES.less],
|
|
4157
|
+
{}
|
|
4158
|
+
]);
|
|
4159
|
+
if (languages.html) blocks.push([
|
|
4160
|
+
"html",
|
|
4161
|
+
[...FORMATTED_FILES.html],
|
|
4162
|
+
{}
|
|
4163
|
+
]);
|
|
4164
|
+
if (languages.graphql) blocks.push([
|
|
4165
|
+
"graphql",
|
|
4166
|
+
[...FORMATTED_FILES.graphql],
|
|
4167
|
+
{}
|
|
4168
|
+
]);
|
|
4169
|
+
if (languages.json) blocks.push([
|
|
4170
|
+
"json",
|
|
4171
|
+
[...FORMATTED_FILES.json],
|
|
4172
|
+
{}
|
|
4173
|
+
], [
|
|
4174
|
+
"json5",
|
|
4175
|
+
[GLOB_JSON5],
|
|
4176
|
+
JSON5_OXFMT_OPTIONS
|
|
4177
|
+
]);
|
|
4178
|
+
if (languages.yaml) blocks.push([
|
|
4179
|
+
"yaml",
|
|
4180
|
+
[...FORMATTED_FILES.yaml],
|
|
4181
|
+
YAML_OXFMT_OPTIONS
|
|
4182
|
+
]);
|
|
4183
|
+
return blocks;
|
|
4184
|
+
}
|
|
4185
|
+
/**
|
|
4097
4186
|
* A block for a language ESLint has no parser for: the plain parser lets
|
|
4098
4187
|
* `oxfmt/oxfmt` see the file, and keeps ESLint from parsing Markdown code
|
|
4099
4188
|
* blocks in it as JavaScript.
|
|
@@ -20858,19 +20947,10 @@ async function isentinel(options, ...userConfigs) {
|
|
|
20858
20947
|
config: enableGitignore,
|
|
20859
20948
|
explicit: "gitignore" in options
|
|
20860
20949
|
}));
|
|
20861
|
-
const markdownCodeWidths = formatter === "standalone" || formatters !== false && shouldEnableFeature(formatters, "markdown") ? {
|
|
20862
|
-
markdownCode: markdownOxfmtOptions(prettierSettings["jsdocPrintWidth"]),
|
|
20863
|
-
markdownCodeOverrides: [
|
|
20864
|
-
...markdownOverridesOf(sectionOverrides),
|
|
20865
|
-
...oxfmtConfig.markdownOverrides ?? [],
|
|
20866
|
-
...markdownOverridesOf(prettierSettings["overrides"])
|
|
20867
|
-
]
|
|
20868
|
-
} : {};
|
|
20869
20950
|
configs.push(smallRules({
|
|
20870
20951
|
isInEditor,
|
|
20871
20952
|
stylistic: stylisticOptions
|
|
20872
20953
|
}), comments({
|
|
20873
|
-
...markdownCodeWidths,
|
|
20874
20954
|
prettierOptions: widthSettings,
|
|
20875
20955
|
stylistic: stylisticOptions
|
|
20876
20956
|
}), flawless({
|
|
@@ -20878,7 +20958,6 @@ async function isentinel(options, ...userConfigs) {
|
|
|
20878
20958
|
..."tsconfigPath" in typescriptOptions ? { tsconfigPath: typescriptOptions.tsconfigPath } : {},
|
|
20879
20959
|
..."typeAware" in typescriptOptions ? { typeAware: typescriptOptions.typeAware } : {},
|
|
20880
20960
|
antiSlop,
|
|
20881
|
-
...markdownCodeWidths,
|
|
20882
20961
|
roblox: enableRoblox,
|
|
20883
20962
|
stylistic: stylisticOptions
|
|
20884
20963
|
}, widthSettings), ignores(options.ignores), imports({
|
|
@@ -21033,6 +21112,7 @@ async function isentinel(options, ...userConfigs) {
|
|
|
21033
21112
|
yaml: false
|
|
21034
21113
|
} : formatters,
|
|
21035
21114
|
oxfmtConfigOptions,
|
|
21115
|
+
oxfmtIgnorePatterns: oxfmtConfig.ignorePatterns,
|
|
21036
21116
|
oxfmtOptions: formatterOptions.oxfmtOptions,
|
|
21037
21117
|
oxlint: oxlintMode === "full",
|
|
21038
21118
|
prettierOptions: prettierSettings,
|
package/dist/lint-cli.mjs
CHANGED
|
@@ -42,7 +42,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
42
42
|
}) : target, mod));
|
|
43
43
|
//#endregion
|
|
44
44
|
//#region package.json
|
|
45
|
-
var version = "6.
|
|
45
|
+
var version = "6.3.0";
|
|
46
46
|
//#endregion
|
|
47
47
|
//#region src/lint-cli/lib/cli/types.ts
|
|
48
48
|
/**
|
package/dist/oxfmt.mjs
CHANGED
|
@@ -315,15 +315,15 @@ function parseJsonLike(contents) {
|
|
|
315
315
|
return;
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
|
-
function isRecord(value) {
|
|
318
|
+
function isRecord$1(value) {
|
|
319
319
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
320
320
|
}
|
|
321
321
|
function readPackageJsonPrettierKey(filePath) {
|
|
322
322
|
const contents = readFileOrUndefined(filePath);
|
|
323
323
|
if (contents === void 0) return;
|
|
324
324
|
const parsed = parseJsonLike(contents);
|
|
325
|
-
const prettierKey = isRecord(parsed) ? parsed["prettier"] : void 0;
|
|
326
|
-
return isRecord(prettierKey) ? prettierKey : void 0;
|
|
325
|
+
const prettierKey = isRecord$1(parsed) ? parsed["prettier"] : void 0;
|
|
326
|
+
return isRecord$1(prettierKey) ? prettierKey : void 0;
|
|
327
327
|
}
|
|
328
328
|
/**
|
|
329
329
|
* Load a JS Prettier config. Node's `require` handles ESM entry points
|
|
@@ -336,8 +336,8 @@ function readPackageJsonPrettierKey(filePath) {
|
|
|
336
336
|
function requireConfigModule(filePath) {
|
|
337
337
|
try {
|
|
338
338
|
const loaded = createRequire(filePath)(filePath);
|
|
339
|
-
const value = isRecord(loaded) && "default" in loaded ? loaded["default"] : loaded;
|
|
340
|
-
return isRecord(value) ? value : void 0;
|
|
339
|
+
const value = isRecord$1(loaded) && "default" in loaded ? loaded["default"] : loaded;
|
|
340
|
+
return isRecord$1(value) ? value : void 0;
|
|
341
341
|
} catch {
|
|
342
342
|
return;
|
|
343
343
|
}
|
|
@@ -355,7 +355,7 @@ function readConfigFile(filePath) {
|
|
|
355
355
|
const contents = readFileOrUndefined(filePath);
|
|
356
356
|
if (contents === void 0) return;
|
|
357
357
|
const parsed = parseJsonLike(contents) ?? parseYamlLike(contents);
|
|
358
|
-
return isRecord(parsed) ? parsed : void 0;
|
|
358
|
+
return isRecord$1(parsed) ? parsed : void 0;
|
|
359
359
|
}
|
|
360
360
|
function ancestorDirectories(cwd) {
|
|
361
361
|
const directories = [];
|
|
@@ -506,6 +506,23 @@ function editorConfigToOxfmt(properties) {
|
|
|
506
506
|
return options;
|
|
507
507
|
}
|
|
508
508
|
//#endregion
|
|
509
|
+
//#region src/guards.ts
|
|
510
|
+
/**
|
|
511
|
+
* Internal runtime type guards. Prefer these over `as` assertions so values
|
|
512
|
+
* crossing untyped boundaries (`JSON.parse`, dynamic `import`, plugin objects)
|
|
513
|
+
* are validated at runtime rather than asserted away.
|
|
514
|
+
*/
|
|
515
|
+
/**
|
|
516
|
+
* Whether a value is a non-null, non-array object usable as a string-keyed
|
|
517
|
+
* record. Narrows `unknown` without an assertion.
|
|
518
|
+
*
|
|
519
|
+
* @param value - The value to test.
|
|
520
|
+
* @returns Whether the value is a plain object.
|
|
521
|
+
*/
|
|
522
|
+
function isRecord(value) {
|
|
523
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
524
|
+
}
|
|
525
|
+
//#endregion
|
|
509
526
|
//#region src/rules/oxfmt.ts
|
|
510
527
|
const UNSUPPORTED_PRETTIER_KEYS = /* @__PURE__ */ new Set([
|
|
511
528
|
"experimentalOperatorPosition",
|
|
@@ -572,12 +589,12 @@ function migratePrettierOptions(prettierOptions) {
|
|
|
572
589
|
function migratePrettierOverrides(overrides) {
|
|
573
590
|
if (!Array.isArray(overrides)) return [];
|
|
574
591
|
return overrides.flatMap((override) => {
|
|
575
|
-
if (
|
|
592
|
+
if (!isRecord(override)) return [];
|
|
576
593
|
const { excludeFiles, files, options } = override;
|
|
577
594
|
return [{
|
|
578
595
|
...excludeFiles === void 0 ? {} : { excludeFiles: stringsOf(excludeFiles) },
|
|
579
596
|
files: stringsOf(files),
|
|
580
|
-
options:
|
|
597
|
+
options: isRecord(options) ? migratePrettierOptions(options) : {}
|
|
581
598
|
}];
|
|
582
599
|
});
|
|
583
600
|
}
|
|
@@ -592,17 +609,11 @@ function migratePrettierOverrides(overrides) {
|
|
|
592
609
|
* @returns The overrides with anchored globs.
|
|
593
610
|
*/
|
|
594
611
|
function anchorOverrideGlobs(overrides) {
|
|
595
|
-
function anchor(glob) {
|
|
596
|
-
const negated = glob.startsWith("!");
|
|
597
|
-
const body = negated ? glob.slice(1) : glob;
|
|
598
|
-
const anchored = body.includes("/") ? body : `./${body}`;
|
|
599
|
-
return negated ? `!${anchored}` : anchored;
|
|
600
|
-
}
|
|
601
612
|
return overrides.map((override) => {
|
|
602
613
|
return {
|
|
603
614
|
...override,
|
|
604
|
-
...override.excludeFiles ? { excludeFiles: override.excludeFiles.map(
|
|
605
|
-
files: override.files.map(
|
|
615
|
+
...override.excludeFiles ? { excludeFiles: override.excludeFiles.map(anchorGlob) } : {},
|
|
616
|
+
files: override.files.map(anchorGlob)
|
|
606
617
|
};
|
|
607
618
|
});
|
|
608
619
|
}
|
|
@@ -627,11 +638,16 @@ function buildOxfmtOptions({ oxfmtConfigOptions = {}, oxfmtOptions, prettierOpti
|
|
|
627
638
|
* ESLint config and the standalone oxfmt config so both format Markdown the
|
|
628
639
|
* same way.
|
|
629
640
|
*
|
|
641
|
+
* Oxfmt would format code blocks with these options too, at the prose width.
|
|
642
|
+
* It leaves them alone instead, and ESLint formats each block with the options
|
|
643
|
+
* of its own language (see `isentinel/oxfmt/markdown-code/*`).
|
|
644
|
+
*
|
|
630
645
|
* @param jsdocPrintWidth - Width for Markdown prose; 80 when unset.
|
|
631
646
|
* @returns Options applied on top of the base for Markdown files.
|
|
632
647
|
*/
|
|
633
648
|
function markdownOxfmtOptions(jsdocPrintWidth) {
|
|
634
649
|
return {
|
|
650
|
+
embeddedLanguageFormatting: "off",
|
|
635
651
|
printWidth: Number(jsdocPrintWidth) || 80,
|
|
636
652
|
proseWrap: "always",
|
|
637
653
|
tabWidth: 2
|
|
@@ -651,6 +667,18 @@ const YAML_OXFMT_OPTIONS = {
|
|
|
651
667
|
tabWidth: 2,
|
|
652
668
|
useTabs: false
|
|
653
669
|
};
|
|
670
|
+
/**
|
|
671
|
+
* Anchor one slash-less glob to the config directory, keeping its negation.
|
|
672
|
+
*
|
|
673
|
+
* @param glob - An override glob.
|
|
674
|
+
* @returns The anchored glob.
|
|
675
|
+
*/
|
|
676
|
+
function anchorGlob(glob) {
|
|
677
|
+
const negated = glob.startsWith("!");
|
|
678
|
+
const body = negated ? glob.slice(1) : glob;
|
|
679
|
+
const anchored = body.includes("/") ? body : `./${body}`;
|
|
680
|
+
return negated ? `!${anchored}` : anchored;
|
|
681
|
+
}
|
|
654
682
|
//#endregion
|
|
655
683
|
//#region src/oxfmt/index.ts
|
|
656
684
|
/**
|
package/dist/oxlint.mjs
CHANGED
|
@@ -5333,6 +5333,15 @@ const GLOB_EXCLUDE = [
|
|
|
5333
5333
|
function isRecord$1(value) {
|
|
5334
5334
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5335
5335
|
}
|
|
5336
|
+
/**
|
|
5337
|
+
* Whether a value is an array whose every element is a string.
|
|
5338
|
+
*
|
|
5339
|
+
* @param value - The value to test.
|
|
5340
|
+
* @returns Whether the value is a `string` array.
|
|
5341
|
+
*/
|
|
5342
|
+
function isStringArray(value) {
|
|
5343
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
5344
|
+
}
|
|
5336
5345
|
//#endregion
|
|
5337
5346
|
//#region src/prettier-config.ts
|
|
5338
5347
|
/**
|
|
@@ -5768,12 +5777,12 @@ function migratePrettierOptions(prettierOptions) {
|
|
|
5768
5777
|
function migratePrettierOverrides(overrides) {
|
|
5769
5778
|
if (!Array.isArray(overrides)) return [];
|
|
5770
5779
|
return overrides.flatMap((override) => {
|
|
5771
|
-
if (
|
|
5780
|
+
if (!isRecord$1(override)) return [];
|
|
5772
5781
|
const { excludeFiles, files, options } = override;
|
|
5773
5782
|
return [{
|
|
5774
5783
|
...excludeFiles === void 0 ? {} : { excludeFiles: stringsOf(excludeFiles) },
|
|
5775
5784
|
files: stringsOf(files),
|
|
5776
|
-
options:
|
|
5785
|
+
options: isRecord$1(options) ? migratePrettierOptions(options) : {}
|
|
5777
5786
|
}];
|
|
5778
5787
|
});
|
|
5779
5788
|
}
|
|
@@ -6261,8 +6270,6 @@ const SCRIPT_EXTENSIONS = [
|
|
|
6261
6270
|
"ts",
|
|
6262
6271
|
"tsx"
|
|
6263
6272
|
];
|
|
6264
|
-
/** The extensions of the Markdown files ESLint lints code blocks in. */
|
|
6265
|
-
const MARKDOWN_EXTENSIONS = ["md"];
|
|
6266
6273
|
const LEADING_DOT_SLASH = /^\.\//;
|
|
6267
6274
|
/** Set once a process has warned about a JS/TS width override. */
|
|
6268
6275
|
const WARNED_SCRIPT_OVERRIDE = Symbol.for("@isentinel/eslint-config/oxfmt-override-warned");
|
|
@@ -6302,42 +6309,9 @@ function findOxfmtConfig(cwd = process.cwd()) {
|
|
|
6302
6309
|
}
|
|
6303
6310
|
}
|
|
6304
6311
|
/**
|
|
6305
|
-
* The overrides that set `printWidth` or `tabWidth` for Markdown files.
|
|
6306
|
-
*
|
|
6307
|
-
* @param overrides - The config's `overrides`.
|
|
6308
|
-
* @returns Each such override's scope and widths, in order.
|
|
6309
|
-
*/
|
|
6310
|
-
function markdownOverridesOf(overrides) {
|
|
6311
|
-
if (!Array.isArray(overrides)) return [];
|
|
6312
|
-
return overrides.flatMap((override) => {
|
|
6313
|
-
if (!isRecord$1(override) || !overrideMatches(override, MARKDOWN_EXTENSIONS)) return [];
|
|
6314
|
-
const widths = widthsOf(override["options"]);
|
|
6315
|
-
return Object.keys(widths).length > 0 ? [{
|
|
6316
|
-
...scopeOf(override),
|
|
6317
|
-
widths
|
|
6318
|
-
}] : [];
|
|
6319
|
-
});
|
|
6320
|
-
}
|
|
6321
|
-
/**
|
|
6322
|
-
* Where an override applies: its `files`, minus its `excludeFiles` and any
|
|
6323
|
-
* negated glob in `files`.
|
|
6324
|
-
*
|
|
6325
|
-
* @param override - One override.
|
|
6326
|
-
* @returns Its scope.
|
|
6327
|
-
*/
|
|
6328
|
-
function scopeOf(override) {
|
|
6329
|
-
const strings = (value) => {
|
|
6330
|
-
return [value].flat().filter((glob) => typeof glob === "string");
|
|
6331
|
-
};
|
|
6332
|
-
const globs = strings(override["files"]);
|
|
6333
|
-
return {
|
|
6334
|
-
excludeFiles: [...strings(override["excludeFiles"]), ...globs.filter((glob) => glob.startsWith("!")).map((glob) => glob.slice(1))],
|
|
6335
|
-
files: globs.filter((glob) => !glob.startsWith("!"))
|
|
6336
|
-
};
|
|
6337
|
-
}
|
|
6338
|
-
/**
|
|
6339
6312
|
* Warn, at most once per process, about factory options that do not reach
|
|
6340
|
-
* standalone oxfmt: it formats with `oxfmt.config.ts` alone.
|
|
6313
|
+
* standalone oxfmt: it formats with `oxfmt.config.ts` alone. They still choose
|
|
6314
|
+
* which Markdown code blocks ESLint formats.
|
|
6341
6315
|
*
|
|
6342
6316
|
* @param options - The factory options.
|
|
6343
6317
|
* @param options.componentExts - Oxfmt formats only the extensions
|
|
@@ -6358,7 +6332,7 @@ function warnStandaloneOptions({ componentExts, formatters, gitignore, ignores }
|
|
|
6358
6332
|
].filter((name) => name !== void 0);
|
|
6359
6333
|
if (names.length > 0) {
|
|
6360
6334
|
state[WARNED_STANDALONE] = true;
|
|
6361
|
-
console.warn(`[@isentinel/eslint-config] With formatter: "standalone", oxfmt formats with oxfmt.config.ts alone, so these options do not change
|
|
6335
|
+
console.warn(`[@isentinel/eslint-config] With formatter: "standalone", oxfmt formats with oxfmt.config.ts alone, so these options do not change what oxfmt formats: ${names.join(", ")}. They change only which Markdown code blocks ESLint formats. Set the equivalent in isentinelOxfmt() (formatters, componentExts, ignorePatterns, format options).`);
|
|
6362
6336
|
}
|
|
6363
6337
|
}
|
|
6364
6338
|
/**
|
|
@@ -6471,26 +6445,26 @@ function mirrorsSection(override, sections) {
|
|
|
6471
6445
|
});
|
|
6472
6446
|
}
|
|
6473
6447
|
/**
|
|
6474
|
-
* Turn a loaded oxfmt config into `oxfmt/oxfmt` rule options
|
|
6475
|
-
*
|
|
6476
|
-
* and `overrides` are dropped from the options.
|
|
6448
|
+
* Turn a loaded oxfmt config into `oxfmt/oxfmt` rule options, its ignore
|
|
6449
|
+
* patterns and its overrides. The rule takes format options only, so
|
|
6450
|
+
* `$schema`, `ignorePatterns` and `overrides` are dropped from the options.
|
|
6477
6451
|
*
|
|
6478
6452
|
* @param config - The loaded config.
|
|
6479
6453
|
* @param config.$schema - Dropped.
|
|
6480
|
-
* @param config.ignorePatterns - Dropped; oxfmt applies them
|
|
6481
|
-
*
|
|
6482
|
-
*
|
|
6454
|
+
* @param config.ignorePatterns - Dropped from the options; oxfmt applies them
|
|
6455
|
+
* itself, except in Markdown code blocks.
|
|
6456
|
+
* @param config.overrides - Dropped from the options, after the width check.
|
|
6483
6457
|
* @param configPath - The config file, for the warning.
|
|
6484
|
-
* @returns The format options and
|
|
6458
|
+
* @returns The format options, ignore patterns and overrides.
|
|
6485
6459
|
*/
|
|
6486
|
-
function toResolvedConfig({ $schema: _schema, ignorePatterns
|
|
6460
|
+
function toResolvedConfig({ $schema: _schema, ignorePatterns, overrides, ...options }, configPath) {
|
|
6487
6461
|
const sections = editorConfigOverrides(path.dirname(configPath));
|
|
6488
6462
|
const list = Array.isArray(overrides) ? overrides : [];
|
|
6489
6463
|
const copied = list.filter((override) => mirrorsSection(override, sections));
|
|
6490
6464
|
warnScriptWidthOverrides(copied, ".editorconfig");
|
|
6491
6465
|
warnScriptWidthOverrides(list.filter((override) => !copied.includes(override)), path.basename(configPath));
|
|
6492
6466
|
return {
|
|
6493
|
-
|
|
6467
|
+
ignorePatterns: isStringArray(ignorePatterns) ? ignorePatterns : [],
|
|
6494
6468
|
options,
|
|
6495
6469
|
overrides: Array.isArray(overrides) ? overrides : []
|
|
6496
6470
|
};
|
|
@@ -6510,20 +6484,6 @@ function rcConfig(configPath, content) {
|
|
|
6510
6484
|
return toResolvedConfig(parsed, configPath);
|
|
6511
6485
|
}
|
|
6512
6486
|
/**
|
|
6513
|
-
* Pick `printWidth` and `tabWidth` out of a set of format options.
|
|
6514
|
-
*
|
|
6515
|
-
* @param options - Format options, of unknown shape.
|
|
6516
|
-
* @returns The widths it sets.
|
|
6517
|
-
*/
|
|
6518
|
-
function widthsOf(options) {
|
|
6519
|
-
if (!isRecord$1(options)) return {};
|
|
6520
|
-
const { printWidth, tabWidth } = options;
|
|
6521
|
-
return {
|
|
6522
|
-
...typeof printWidth === "number" ? { printWidth } : {},
|
|
6523
|
-
...typeof tabWidth === "number" ? { tabWidth } : {}
|
|
6524
|
-
};
|
|
6525
|
-
}
|
|
6526
|
-
/**
|
|
6527
6487
|
* Resolves the lowest Node major version a semver range can match.
|
|
6528
6488
|
*
|
|
6529
6489
|
* @param range - A semver range such as `>=24.12.0` or `^24 || ^26`.
|
|
@@ -7420,24 +7380,6 @@ function oxlintEslintPlugin(options = {}) {
|
|
|
7420
7380
|
//#endregion
|
|
7421
7381
|
//#region src/rules/flawless.ts
|
|
7422
7382
|
/**
|
|
7423
|
-
* Arrow return style rule on its own, for the Markdown code block override
|
|
7424
|
-
* where only the line width differs.
|
|
7425
|
-
*
|
|
7426
|
-
* @param options - Shared rule options.
|
|
7427
|
-
* @returns The rule map.
|
|
7428
|
-
*/
|
|
7429
|
-
function arrowStyleRules({ maxLen, maxLength, printWidth, tabWidth } = {}) {
|
|
7430
|
-
return { "flawless/arrow-return-style": ["error", {
|
|
7431
|
-
jsxAlwaysUseExplicitReturn: true,
|
|
7432
|
-
maxLen: maxLength ?? maxLen ?? printWidth ?? 100,
|
|
7433
|
-
maxObjectProperties: 2,
|
|
7434
|
-
namedExportsAlwaysUseExplicitReturn: true,
|
|
7435
|
-
objectReturnStyle: "complex-explicit",
|
|
7436
|
-
...tabWidth !== void 0 ? { tabWidth } : {},
|
|
7437
|
-
...printWidth !== void 0 ? { useOxfmt: { printWidth } } : {}
|
|
7438
|
-
}] };
|
|
7439
|
-
}
|
|
7440
|
-
/**
|
|
7441
7383
|
* Base (non-React) flawless rules shared between the ESLint and oxlint
|
|
7442
7384
|
* factories. The React flawless rules live in the react rule map; the
|
|
7443
7385
|
* type-aware rules live in {@link flawlessTypeAwareRules}, plus the type-aware
|
|
@@ -7483,6 +7425,23 @@ function antiSlopRules({ roblox = true }) {
|
|
|
7483
7425
|
...roblox ? {} : { "flawless/no-reflect-get": "error" }
|
|
7484
7426
|
};
|
|
7485
7427
|
}
|
|
7428
|
+
/**
|
|
7429
|
+
* The arrow return style rule.
|
|
7430
|
+
*
|
|
7431
|
+
* @param options - Shared rule options.
|
|
7432
|
+
* @returns The rule map.
|
|
7433
|
+
*/
|
|
7434
|
+
function arrowStyleRules({ maxLen, printWidth, tabWidth } = {}) {
|
|
7435
|
+
return { "flawless/arrow-return-style": ["error", {
|
|
7436
|
+
jsxAlwaysUseExplicitReturn: true,
|
|
7437
|
+
maxLen: maxLen ?? printWidth ?? 100,
|
|
7438
|
+
maxObjectProperties: 2,
|
|
7439
|
+
namedExportsAlwaysUseExplicitReturn: true,
|
|
7440
|
+
objectReturnStyle: "complex-explicit",
|
|
7441
|
+
...tabWidth !== void 0 ? { tabWidth } : {},
|
|
7442
|
+
...printWidth !== void 0 ? { useOxfmt: { printWidth } } : {}
|
|
7443
|
+
}] };
|
|
7444
|
+
}
|
|
7486
7445
|
//#endregion
|
|
7487
7446
|
//#region src/oxlint/configs/flawless.ts
|
|
7488
7447
|
function oxlintFlawless({ antiSlop = false, excludeFiles, roblox = true, stylistic = true } = {}, prettierOptions = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@isentinel/eslint-config",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.3.0",
|
|
4
4
|
"description": "iSentinel's ESLint config",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint-config",
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
"typescript": "6.0.3",
|
|
150
150
|
"unplugin-unused": "0.5.7",
|
|
151
151
|
"vitest": "4.1.10",
|
|
152
|
-
"@isentinel/eslint-config": "6.
|
|
152
|
+
"@isentinel/eslint-config": "6.3.0"
|
|
153
153
|
},
|
|
154
154
|
"peerDependencies": {
|
|
155
155
|
"@vitest/eslint-plugin": "^1.6.4",
|