@isentinel/eslint-config 6.0.0-beta.13 → 6.0.0-beta.14
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/cli.mjs +1 -1
- package/dist/index.d.mts +13 -3
- package/dist/index.mjs +79 -20
- package/dist/lint-cli.mjs +2 -2
- package/dist/oxlint.d.mts +34 -4
- package/dist/oxlint.mjs +107 -10
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import path from "node:path";
|
|
|
9
9
|
import { existsSync, readFileSync } from "fs";
|
|
10
10
|
import { execSync } from "node:child_process";
|
|
11
11
|
//#region package.json
|
|
12
|
-
var version = "6.0.0-beta.
|
|
12
|
+
var version = "6.0.0-beta.14";
|
|
13
13
|
var package_default = {
|
|
14
14
|
name: "@isentinel/eslint-config",
|
|
15
15
|
version,
|
package/dist/index.d.mts
CHANGED
|
@@ -26244,7 +26244,7 @@ type Yoda = [] | [("always" | "never")] | [("always" | "never"), {
|
|
|
26244
26244
|
onlyEquality?: boolean;
|
|
26245
26245
|
}];
|
|
26246
26246
|
// Names of all the configs
|
|
26247
|
-
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/markdown-code' | '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/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/promise' | 'isentinel/react/setup' | 'isentinel/react/setup/naming' | '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/vitest/setup' | 'isentinel/test/vitest/rules' | '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';
|
|
26247
|
+
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/markdown-code' | '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/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/promise' | 'isentinel/react/setup' | 'isentinel/react/setup/naming' | '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';
|
|
26248
26248
|
//#endregion
|
|
26249
26249
|
//#region src/utils.d.ts
|
|
26250
26250
|
type ExtractRuleOptions<T> = T extends Linter.RuleEntry<infer U> ? U : never;
|
|
@@ -26761,9 +26761,14 @@ interface OptionsConfig extends OptionsComponentExtensions, OptionsProjectType {
|
|
|
26761
26761
|
* Requires installing the optional peer dependencies `oxlint` and
|
|
26762
26762
|
* `oxlint-tsgolint`.
|
|
26763
26763
|
*
|
|
26764
|
+
* `"native"` narrows the hand-off to the rules oxlint implements in Rust
|
|
26765
|
+
* (native rules plus the tsgolint type-aware ones): rules that would run in
|
|
26766
|
+
* oxlint as jsPlugins — and formatting — stay in ESLint. Pair it with
|
|
26767
|
+
* `jsPlugins: false` in the oxlint factory, or both engines run them.
|
|
26768
|
+
*
|
|
26764
26769
|
* @default false
|
|
26765
26770
|
*/
|
|
26766
|
-
oxlint?: boolean;
|
|
26771
|
+
oxlint?: "native" | boolean;
|
|
26767
26772
|
/**
|
|
26768
26773
|
* Warn at config-build time when a user config references a rule that
|
|
26769
26774
|
* oxlint owns in hybrid mode (`oxlint: true`), where the ESLint entry has
|
|
@@ -27094,6 +27099,11 @@ declare const GLOB_MISE: Array<string>;
|
|
|
27094
27099
|
declare const GLOB_HTML = "**/*.htm{,l}";
|
|
27095
27100
|
declare const GLOB_XML = "**/*.xml";
|
|
27096
27101
|
declare const GLOB_GRAPHQL = "**/*.{g,graph}ql";
|
|
27102
|
+
/**
|
|
27103
|
+
* Type tests (`expectTypeOf` / `assertType`), run by Vitest's `typecheck`
|
|
27104
|
+
* mode. They are test files, but assert nothing at runtime.
|
|
27105
|
+
*/
|
|
27106
|
+
declare const GLOB_TYPE_TESTS = "**/*.test-d.{,c,m}[jt]s{,x}";
|
|
27097
27107
|
declare const GLOB_TESTS: Array<string>;
|
|
27098
27108
|
declare const GLOB_BUILD_TOOLS: Array<string>;
|
|
27099
27109
|
declare const GLOB_ALL_SRC: string[];
|
|
@@ -27282,4 +27292,4 @@ declare function unicorn({ complementIgnores, nameReplacements, roblox, root: cu
|
|
|
27282
27292
|
//#region src/eslint/configs/yaml.d.ts
|
|
27283
27293
|
declare function yaml({ files, overrides, stylistic }?: OptionsFiles & OptionsOverrides & OptionsStylistic): Promise<Array<TypedFlatConfigItem>>;
|
|
27284
27294
|
//#endregion
|
|
27285
|
-
export { Awaitable, type ConfigNames, type FlatConfigComposer, GLOB_ALL_JSON, GLOB_ALL_SRC, GLOB_BUILD_TOOLS, GLOB_CSS, GLOB_DTS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LINTABLE_EXTENSIONS, GLOB_LUA, GLOB_MARKDOWN, GLOB_MARKDOWN_BLOCKS, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_MISE, GLOB_PACKAGE_JSON, GLOB_PACKAGE_JSON_ROOT, GLOB_POSTCSS, GLOB_ROOT, GLOB_ROOT_SRC, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_SRC_EXTENSIONS, GLOB_STYLE, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSCONFIG, GLOB_TSX, GLOB_XML, GLOB_YAML, GitignoreOptions, JsdocOptions, NamedFlatConfigItem, NamedOptionsConfig, OptionsComponentExtensions, OptionsConfig, OptionsE18e, OptionsFiles, OptionsFilesTypeAware, OptionsFormatters, OptionsHasRoblox, OptionsHasTypeScript, OptionsIsInEditor, OptionsJest, OptionsOverrides, OptionsOverridesTypeAware, OptionsPnpm, OptionsProjectType, OptionsStylistic, OptionsTestFramework, OptionsTypeScriptErasableOnly, OptionsTypeScriptParserOptions, OptionsTypeScriptWithTypes, OptionsTypescript, OptionsUnicorn, OptionsVitest, type OxfmtOptions, PerfectionistConfig, type PrettierOptions, ReactConfig, Rules, SpellCheckConfig, StylisticConfig, StylisticConfigDefaults, TypedFlatConfigItem, comments, isentinel as default, isentinel, defaultPluginRenaming, disables, e18e, eslintPlugin, flawless, gitignore, ignores$1 as ignores, imports, isInAgentSession, isInEditorEnvironment, isInGitHooksOrLintStaged, javascript, jsdoc, jsonc, loadSmallRulesPlugin, markdown, naming, node, oxfmt, packageJson, perfectionist, pnpm, promise, react, roblox$1 as roblox, smallRules, sonarjs, sortCspell, sortGithubAction, sortMiseToml, sortPnpmWorkspace, sortRojoProject, sortTsconfig, spelling, stylistic$1 as stylistic, test, toml, typescript, unicorn, yaml };
|
|
27295
|
+
export { Awaitable, type ConfigNames, type FlatConfigComposer, GLOB_ALL_JSON, GLOB_ALL_SRC, GLOB_BUILD_TOOLS, GLOB_CSS, GLOB_DTS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LINTABLE_EXTENSIONS, GLOB_LUA, GLOB_MARKDOWN, GLOB_MARKDOWN_BLOCKS, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_MISE, GLOB_PACKAGE_JSON, GLOB_PACKAGE_JSON_ROOT, GLOB_POSTCSS, GLOB_ROOT, GLOB_ROOT_SRC, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_SRC_EXTENSIONS, GLOB_STYLE, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSCONFIG, GLOB_TSX, GLOB_TYPE_TESTS, GLOB_XML, GLOB_YAML, GitignoreOptions, JsdocOptions, NamedFlatConfigItem, NamedOptionsConfig, OptionsComponentExtensions, OptionsConfig, OptionsE18e, OptionsFiles, OptionsFilesTypeAware, OptionsFormatters, OptionsHasRoblox, OptionsHasTypeScript, OptionsIsInEditor, OptionsJest, OptionsOverrides, OptionsOverridesTypeAware, OptionsPnpm, OptionsProjectType, OptionsStylistic, OptionsTestFramework, OptionsTypeScriptErasableOnly, OptionsTypeScriptParserOptions, OptionsTypeScriptWithTypes, OptionsTypescript, OptionsUnicorn, OptionsVitest, type OxfmtOptions, PerfectionistConfig, type PrettierOptions, ReactConfig, Rules, SpellCheckConfig, StylisticConfig, StylisticConfigDefaults, TypedFlatConfigItem, comments, isentinel as default, isentinel, defaultPluginRenaming, disables, e18e, eslintPlugin, flawless, gitignore, ignores$1 as ignores, imports, isInAgentSession, isInEditorEnvironment, isInGitHooksOrLintStaged, javascript, jsdoc, jsonc, loadSmallRulesPlugin, markdown, naming, node, oxfmt, packageJson, perfectionist, pnpm, promise, react, roblox$1 as roblox, smallRules, sonarjs, sortCspell, sortGithubAction, sortMiseToml, sortPnpmWorkspace, sortRojoProject, sortTsconfig, spelling, stylistic$1 as stylistic, test, toml, typescript, unicorn, yaml };
|
package/dist/index.mjs
CHANGED
|
@@ -152,10 +152,16 @@ const GLOB_MISE = [
|
|
|
152
152
|
const GLOB_HTML = "**/*.htm{,l}";
|
|
153
153
|
const GLOB_XML = "**/*.xml";
|
|
154
154
|
const GLOB_GRAPHQL = "**/*.{g,graph}ql";
|
|
155
|
+
/**
|
|
156
|
+
* Type tests (`expectTypeOf` / `assertType`), run by Vitest's `typecheck`
|
|
157
|
+
* mode. They are test files, but assert nothing at runtime.
|
|
158
|
+
*/
|
|
159
|
+
const GLOB_TYPE_TESTS = `**/*.test-d.${GLOB_SRC_EXT}`;
|
|
155
160
|
const GLOB_TESTS = [
|
|
156
161
|
`**/__tests__/**/*.${GLOB_SRC_EXT}`,
|
|
157
162
|
`**/*.spec.${GLOB_SRC_EXT}`,
|
|
158
163
|
`**/*.test.${GLOB_SRC_EXT}`,
|
|
164
|
+
GLOB_TYPE_TESTS,
|
|
159
165
|
`**/*.bench.${GLOB_SRC_EXT}`,
|
|
160
166
|
`**/*.benchmark.${GLOB_SRC_EXT}`
|
|
161
167
|
];
|
|
@@ -4631,6 +4637,21 @@ async function stylistic(options = {}) {
|
|
|
4631
4637
|
//#endregion
|
|
4632
4638
|
//#region src/rules/test.ts
|
|
4633
4639
|
/**
|
|
4640
|
+
* Rules that make no sense in a type test (`*.test-d.ts`): these files assert
|
|
4641
|
+
* with `expectTypeOf`/`assertType` at compile time, run no expectations, and
|
|
4642
|
+
* name their blocks after the types under test.
|
|
4643
|
+
*
|
|
4644
|
+
* @param prefix - The test-plugin prefix in use (`jest` or `vitest`).
|
|
4645
|
+
* @returns The rule map.
|
|
4646
|
+
*/
|
|
4647
|
+
function typeTestRules(prefix) {
|
|
4648
|
+
return {
|
|
4649
|
+
[`${prefix}/expect-expect`]: "off",
|
|
4650
|
+
[`${prefix}/prefer-expect-assertions`]: "off",
|
|
4651
|
+
[`${prefix}/prefer-lowercase-title`]: "off"
|
|
4652
|
+
};
|
|
4653
|
+
}
|
|
4654
|
+
/**
|
|
4634
4655
|
* Jest-extended rules shared between the ESLint and oxlint factories.
|
|
4635
4656
|
*
|
|
4636
4657
|
* @returns The rule map.
|
|
@@ -4859,6 +4880,10 @@ async function test({ files = GLOB_TESTS, isInEditor = false, jest = false, over
|
|
|
4859
4880
|
globalPackage: "@rbxts/jest-globals",
|
|
4860
4881
|
version: 27
|
|
4861
4882
|
} }
|
|
4883
|
+
}, {
|
|
4884
|
+
name: "isentinel/test/jest/type-tests",
|
|
4885
|
+
files: [GLOB_TYPE_TESTS],
|
|
4886
|
+
rules: typeTestRules("jest")
|
|
4862
4887
|
});
|
|
4863
4888
|
}
|
|
4864
4889
|
if (enableVitest) {
|
|
@@ -4896,6 +4921,10 @@ async function test({ files = GLOB_TESTS, isInEditor = false, jest = false, over
|
|
|
4896
4921
|
...useJestExtended ? { jest: { globalPackage: "vitest" } } : {},
|
|
4897
4922
|
vitest: { typecheck: vitestOptions.typecheck ?? false }
|
|
4898
4923
|
}
|
|
4924
|
+
}, {
|
|
4925
|
+
name: "isentinel/test/vitest/type-tests",
|
|
4926
|
+
files: [GLOB_TYPE_TESTS],
|
|
4927
|
+
rules: typeTestRules("vitest")
|
|
4899
4928
|
});
|
|
4900
4929
|
}
|
|
4901
4930
|
return configs;
|
|
@@ -15378,6 +15407,17 @@ function isOxlintCovered(rule) {
|
|
|
15378
15407
|
return rule in oxlintRuleMapping || rule in oxcCoveredRules;
|
|
15379
15408
|
}
|
|
15380
15409
|
/**
|
|
15410
|
+
* Whether the rule only runs in oxlint through a jsPlugin (the original ESLint
|
|
15411
|
+
* plugin loaded by oxlint), rather than natively in Rust. Native-only hybrid
|
|
15412
|
+
* mode (`oxlint: "native"`) leaves these rules in ESLint.
|
|
15413
|
+
*
|
|
15414
|
+
* @param rule - The canonical ESLint rule name.
|
|
15415
|
+
* @returns Whether the rule runs as an oxlint jsPlugin.
|
|
15416
|
+
*/
|
|
15417
|
+
function isJsPluginRule(rule) {
|
|
15418
|
+
return oxlintRuleMapping[rule] === "js-plugin";
|
|
15419
|
+
}
|
|
15420
|
+
/**
|
|
15381
15421
|
* Whether the rule runs via oxlint-tsgolint (`oxlint --type-aware`); such rules
|
|
15382
15422
|
* are noise without type information, so they are gated on `typeAware`.
|
|
15383
15423
|
*
|
|
@@ -15398,9 +15438,11 @@ const HYBRID_FORMATTING_RULES = /* @__PURE__ */ new Set(["oxfmt/oxfmt"]);
|
|
|
15398
15438
|
* virtual files, so the preset re-enables those rules there.
|
|
15399
15439
|
*
|
|
15400
15440
|
* @param configs - The resolved flat config items.
|
|
15441
|
+
* @param mode - The hybrid mode; in `native` mode jsPlugin rules and formatting
|
|
15442
|
+
* stay in ESLint, so entries for them are live and not reported.
|
|
15401
15443
|
*/
|
|
15402
|
-
function warnDeadMappedRules(configs) {
|
|
15403
|
-
const references = findDeadMappedRules(configs);
|
|
15444
|
+
function warnDeadMappedRules(configs, mode) {
|
|
15445
|
+
const references = findDeadMappedRules(configs, mode);
|
|
15404
15446
|
if (references.length === 0) return;
|
|
15405
15447
|
const lines = references.map(({ config, rule }) => ` - "${rule}" in ${config}`);
|
|
15406
15448
|
console.warn(`[@isentinel/eslint-config] These config entries reference rules that oxlint owns in hybrid mode, so they have no effect in ESLint. Move them to oxlint.config.ts (or your oxfmt options) or remove them:\n${lines.join("\n")}`);
|
|
@@ -15427,12 +15469,13 @@ function warnMissingTsgolint() {
|
|
|
15427
15469
|
* @param typeAware - Whether oxlint runs type-aware (oxlint-tsgolint present).
|
|
15428
15470
|
* When `false`, tsgolint rules are kept in ESLint so they do not vanish from
|
|
15429
15471
|
* both engines.
|
|
15472
|
+
* @param mode - The hybrid mode; `native` keeps jsPlugin rules in ESLint.
|
|
15430
15473
|
*/
|
|
15431
|
-
function dropOxlintCoveredRules(configs, typeAware = true) {
|
|
15474
|
+
function dropOxlintCoveredRules(configs, typeAware = true, mode = "full") {
|
|
15432
15475
|
for (let index = 0; index < configs.length; index += 1) {
|
|
15433
15476
|
const config = configs[index];
|
|
15434
15477
|
if (config?.name === void 0 || !config.name.startsWith("isentinel/") || config.name.endsWith("/markdown-code") || config.rules === void 0 || targetsMarkdown(config.files)) continue;
|
|
15435
|
-
const dropped = dropCoveredRulesFromConfig(config.rules, typeAware);
|
|
15478
|
+
const dropped = dropCoveredRulesFromConfig(config.rules, typeAware, mode);
|
|
15436
15479
|
if (Object.keys(dropped).length === 0) continue;
|
|
15437
15480
|
if ((config.ignores ?? []).some((pattern) => typeof pattern === "string" && pattern.includes(".md/"))) continue;
|
|
15438
15481
|
configs.splice(index + 1, 0, {
|
|
@@ -15443,6 +15486,18 @@ function dropOxlintCoveredRules(configs, typeAware = true) {
|
|
|
15443
15486
|
index += 1;
|
|
15444
15487
|
}
|
|
15445
15488
|
}
|
|
15489
|
+
/**
|
|
15490
|
+
* Whether oxlint owns the rule in the given hybrid mode (and therefore whether
|
|
15491
|
+
* ESLint must drop it).
|
|
15492
|
+
*
|
|
15493
|
+
* @param rule - The canonical ESLint rule name.
|
|
15494
|
+
* @param mode - The hybrid mode.
|
|
15495
|
+
* @returns Whether oxlint runs the rule.
|
|
15496
|
+
*/
|
|
15497
|
+
function isOwnedByOxlint(rule, mode) {
|
|
15498
|
+
if (!isOxlintCovered(rule)) return false;
|
|
15499
|
+
return mode === "full" || !isJsPluginRule(rule);
|
|
15500
|
+
}
|
|
15446
15501
|
function isPresetConfig(config) {
|
|
15447
15502
|
return config.name?.startsWith("isentinel/") ?? false;
|
|
15448
15503
|
}
|
|
@@ -15462,22 +15517,22 @@ function targetsMarkdown(files) {
|
|
|
15462
15517
|
const patterns = files.flat();
|
|
15463
15518
|
return patterns.length > 0 && patterns.every((pattern) => typeof pattern === "string" && pattern.includes(".md"));
|
|
15464
15519
|
}
|
|
15465
|
-
function findDeadMappedRules(configs) {
|
|
15520
|
+
function findDeadMappedRules(configs, mode) {
|
|
15466
15521
|
const references = [];
|
|
15467
15522
|
for (const config of configs) {
|
|
15468
15523
|
if (config.rules === void 0 || isPresetConfig(config) || targetsMarkdown(config.files)) continue;
|
|
15469
15524
|
const label = describeConfig(config);
|
|
15470
|
-
for (const [rule, value] of Object.entries(config.rules)) if (value !== void 0 && (
|
|
15525
|
+
for (const [rule, value] of Object.entries(config.rules)) if (value !== void 0 && (isOwnedByOxlint(rule, mode) || mode === "full" && HYBRID_FORMATTING_RULES.has(rule))) references.push({
|
|
15471
15526
|
config: label,
|
|
15472
15527
|
rule
|
|
15473
15528
|
});
|
|
15474
15529
|
}
|
|
15475
15530
|
return references;
|
|
15476
15531
|
}
|
|
15477
|
-
function dropCoveredRulesFromConfig(rules, typeAware) {
|
|
15532
|
+
function dropCoveredRulesFromConfig(rules, typeAware, mode) {
|
|
15478
15533
|
const dropped = {};
|
|
15479
15534
|
for (const [rule, value] of Object.entries(rules)) {
|
|
15480
|
-
if (value === void 0 || !
|
|
15535
|
+
if (value === void 0 || !isOwnedByOxlint(rule, mode) || !typeAware && isTsgolintRule(rule)) continue;
|
|
15481
15536
|
const severity = Array.isArray(value) ? value[0] : value;
|
|
15482
15537
|
if (severity === "off" || severity === 0) continue;
|
|
15483
15538
|
dropped[rule] = value;
|
|
@@ -15662,6 +15717,10 @@ async function isentinel(options, ...userConfigs) {
|
|
|
15662
15717
|
const { autoRenamePlugins = true, componentExts: componentExtensions = [], e18e: enableE18e = true, eslintPlugin: enableEslintPlugin = false, formatters, gitignore: enableGitignore = true, jsdoc: enableJsdoc = true, jsonc: enableJsonc = true, jsx: enableJsx = true, markdown: enableMarkdown = true, oxlint: enableOxlint = false, pnpm: enableCatalogs = findUpSync("pnpm-workspace.yaml") !== void 0, react: enableReact = false, root: customRootGlobs, spellCheck: enableSpellCheck, toml: enableToml = true, yaml: enableYaml = true } = options;
|
|
15663
15718
|
const rootGlobs = mergeGlobs(GLOB_ROOT, customRootGlobs);
|
|
15664
15719
|
const enableRoblox = options.roblox !== false;
|
|
15720
|
+
const oxlintMode = (() => {
|
|
15721
|
+
if (enableOxlint === false) return "off";
|
|
15722
|
+
return enableOxlint === "native" ? "native" : "full";
|
|
15723
|
+
})();
|
|
15665
15724
|
const robloxScopedFiles = typeof options.roblox === "object" && options.roblox.files !== void 0 ? options.roblox.files.flat() : void 0;
|
|
15666
15725
|
const hasComplement = !enableRoblox || robloxScopedFiles !== void 0;
|
|
15667
15726
|
const needsComplementOverlay = enableRoblox && robloxScopedFiles !== void 0;
|
|
@@ -15808,33 +15867,33 @@ async function isentinel(options, ...userConfigs) {
|
|
|
15808
15867
|
componentExts: componentExtensions,
|
|
15809
15868
|
type: projectType
|
|
15810
15869
|
}));
|
|
15811
|
-
if (enableSpellCheck !== false
|
|
15870
|
+
if (enableSpellCheck !== false) {
|
|
15812
15871
|
configs.push(spelling({
|
|
15813
15872
|
...resolveSubOptions(options, "spellCheck"),
|
|
15814
15873
|
componentExts: componentExtensions,
|
|
15815
15874
|
isInEditor
|
|
15816
15875
|
}));
|
|
15817
|
-
if (stylisticOptions !== false && enableYaml !== false) configs.push(sortCspell());
|
|
15876
|
+
if (stylisticOptions !== false && enableYaml !== false && !typeAwareOnly) configs.push(sortCspell());
|
|
15818
15877
|
}
|
|
15819
|
-
writeHybridStatusForCwd(
|
|
15820
|
-
if (
|
|
15878
|
+
writeHybridStatusForCwd(oxlintMode !== "off");
|
|
15879
|
+
if (oxlintMode !== "off") configs.push([{
|
|
15821
15880
|
name: "isentinel/oxlint-marker",
|
|
15822
15881
|
settings: { "isentinel/oxlint": true }
|
|
15823
15882
|
}]);
|
|
15824
15883
|
configs.push(disables({ root: rootGlobs }));
|
|
15825
|
-
if (stylisticOptions !== false
|
|
15884
|
+
if (stylisticOptions !== false) configs.push(oxfmt({
|
|
15826
15885
|
componentExts: componentExtensions,
|
|
15827
|
-
formatters: formatters
|
|
15886
|
+
formatters: typeAwareOnly || formatters === false ? {
|
|
15828
15887
|
css: false,
|
|
15829
15888
|
graphql: false,
|
|
15830
15889
|
html: false,
|
|
15831
15890
|
json: false,
|
|
15832
15891
|
markdown: false,
|
|
15833
15892
|
yaml: false
|
|
15834
|
-
},
|
|
15893
|
+
} : formatters,
|
|
15835
15894
|
oxfmtConfigOptions,
|
|
15836
15895
|
oxfmtOptions: formatterOptions.oxfmtOptions,
|
|
15837
|
-
oxlint:
|
|
15896
|
+
oxlint: oxlintMode === "full",
|
|
15838
15897
|
prettierOptions: prettierSettings
|
|
15839
15898
|
}));
|
|
15840
15899
|
if ("files" in options) throw new Error("[@isentinel/eslint-config] The first argument should not contain the \"files\" property as the options are supposed to be global. Place it in the second or later config instead.");
|
|
@@ -15849,12 +15908,12 @@ async function isentinel(options, ...userConfigs) {
|
|
|
15849
15908
|
return [...previous, GLOB_MARKDOWN];
|
|
15850
15909
|
});
|
|
15851
15910
|
if (autoRenamePlugins) composer = composer.renamePlugins(defaultPluginRenaming);
|
|
15852
|
-
if (
|
|
15911
|
+
if (oxlintMode !== "off") {
|
|
15853
15912
|
const tsgolintAvailable = isPackageExists("oxlint-tsgolint");
|
|
15854
15913
|
if (!tsgolintAvailable) warnMissingTsgolint();
|
|
15855
15914
|
composer = composer.onResolved((resolved) => {
|
|
15856
|
-
if (options.oxlintWarnDeadRules !== false) warnDeadMappedRules(resolved);
|
|
15857
|
-
dropOxlintCoveredRules(resolved, tsgolintAvailable);
|
|
15915
|
+
if (options.oxlintWarnDeadRules !== false) warnDeadMappedRules(resolved, oxlintMode);
|
|
15916
|
+
dropOxlintCoveredRules(resolved, tsgolintAvailable, oxlintMode);
|
|
15858
15917
|
});
|
|
15859
15918
|
}
|
|
15860
15919
|
if (typeAwareMode !== void 0) composer = composer.onResolved((resolved) => {
|
|
@@ -15880,4 +15939,4 @@ async function isentinel(options, ...userConfigs) {
|
|
|
15880
15939
|
return composer;
|
|
15881
15940
|
}
|
|
15882
15941
|
//#endregion
|
|
15883
|
-
export { GLOB_ALL_JSON, GLOB_ALL_SRC, GLOB_BUILD_TOOLS, GLOB_CSS, GLOB_DTS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LINTABLE_EXTENSIONS, GLOB_LUA, GLOB_MARKDOWN, GLOB_MARKDOWN_BLOCKS, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_MISE, GLOB_PACKAGE_JSON, GLOB_PACKAGE_JSON_ROOT, GLOB_POSTCSS, GLOB_ROOT, GLOB_ROOT_SRC, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_SRC_EXTENSIONS, GLOB_STYLE, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSCONFIG, GLOB_TSX, GLOB_XML, GLOB_YAML, StylisticConfigDefaults, comments, isentinel as default, isentinel, defaultPluginRenaming, disables, e18e, eslintPlugin, flawless, gitignore, ignores, imports, isInAgentSession, isInEditorEnvironment, isInGitHooksOrLintStaged, javascript, jsdoc, jsonc, loadSmallRulesPlugin, markdown, naming, node, oxfmt, packageJson, perfectionist, pnpm, promise, react, roblox, smallRules, sonarjs, sortCspell, sortGithubAction, sortMiseToml, sortPnpmWorkspace, sortRojoProject, sortTsconfig, spelling, stylistic, test, toml, typescript, unicorn, yaml };
|
|
15942
|
+
export { GLOB_ALL_JSON, GLOB_ALL_SRC, GLOB_BUILD_TOOLS, GLOB_CSS, GLOB_DTS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_LINTABLE_EXTENSIONS, GLOB_LUA, GLOB_MARKDOWN, GLOB_MARKDOWN_BLOCKS, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_MISE, GLOB_PACKAGE_JSON, GLOB_PACKAGE_JSON_ROOT, GLOB_POSTCSS, GLOB_ROOT, GLOB_ROOT_SRC, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_SRC_EXTENSIONS, GLOB_STYLE, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSCONFIG, GLOB_TSX, GLOB_TYPE_TESTS, GLOB_XML, GLOB_YAML, StylisticConfigDefaults, comments, isentinel as default, isentinel, defaultPluginRenaming, disables, e18e, eslintPlugin, flawless, gitignore, ignores, imports, isInAgentSession, isInEditorEnvironment, isInGitHooksOrLintStaged, javascript, jsdoc, jsonc, loadSmallRulesPlugin, markdown, naming, node, oxfmt, packageJson, perfectionist, pnpm, promise, react, roblox, smallRules, sonarjs, sortCspell, sortGithubAction, sortMiseToml, sortPnpmWorkspace, sortRojoProject, sortTsconfig, spelling, stylistic, test, toml, typescript, unicorn, yaml };
|
package/dist/lint-cli.mjs
CHANGED
|
@@ -36,7 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
36
36
|
}) : target, mod));
|
|
37
37
|
//#endregion
|
|
38
38
|
//#region package.json
|
|
39
|
-
var version = "6.0.0-beta.
|
|
39
|
+
var version = "6.0.0-beta.14";
|
|
40
40
|
/**
|
|
41
41
|
* The real TS/JS-family file extensions {@link GLOB_SRC_EXT} encodes (the glob
|
|
42
42
|
* additionally matches non-existent combinations such as `cjsx`). Kept next to
|
|
@@ -3228,7 +3228,7 @@ function resolveIgnoredHelper() {
|
|
|
3228
3228
|
* The stderr warning emitted when the resolved ESLint config is not hybrid, so
|
|
3229
3229
|
* running oxlint too would double-lint every mapped rule. Oxlint is dropped.
|
|
3230
3230
|
*/
|
|
3231
|
-
const NON_HYBRID_WARNING = "isentinel-lint: the ESLint config does not enable hybrid mode (`oxlint: true`), so oxlint would re-run rules ESLint already checks. Running ESLint only; enable hybrid mode in your config or pass --oxlint to run oxlint explicitly.\n";
|
|
3231
|
+
const NON_HYBRID_WARNING = "isentinel-lint: the ESLint config does not enable hybrid mode (`oxlint: true` or `oxlint: \"native\"`), so oxlint would re-run rules ESLint already checks. Running ESLint only; enable hybrid mode in your config or pass --oxlint to run oxlint explicitly.\n";
|
|
3232
3232
|
/**
|
|
3233
3233
|
* The stderr warning emitted when the hybrid status cannot be determined (the
|
|
3234
3234
|
* probe failed). The run fails open: both engines run, as before.
|
package/dist/oxlint.d.mts
CHANGED
|
@@ -23955,9 +23955,14 @@ interface OptionsConfig extends OptionsComponentExtensions, OptionsProjectType {
|
|
|
23955
23955
|
* Requires installing the optional peer dependencies `oxlint` and
|
|
23956
23956
|
* `oxlint-tsgolint`.
|
|
23957
23957
|
*
|
|
23958
|
+
* `"native"` narrows the hand-off to the rules oxlint implements in Rust
|
|
23959
|
+
* (native rules plus the tsgolint type-aware ones): rules that would run in
|
|
23960
|
+
* oxlint as jsPlugins — and formatting — stay in ESLint. Pair it with
|
|
23961
|
+
* `jsPlugins: false` in the oxlint factory, or both engines run them.
|
|
23962
|
+
*
|
|
23958
23963
|
* @default false
|
|
23959
23964
|
*/
|
|
23960
|
-
oxlint?: boolean;
|
|
23965
|
+
oxlint?: "native" | boolean;
|
|
23961
23966
|
/**
|
|
23962
23967
|
* Warn at config-build time when a user config references a rule that
|
|
23963
23968
|
* oxlint owns in hybrid mode (`oxlint: true`), where the ESLint entry has
|
|
@@ -32097,7 +32102,7 @@ type OxlintOptionsConfig = Omit<OptionsConfig, "autoRenamePlugins" | "flawless"
|
|
|
32097
32102
|
* Combines oxlint config fields (`env`, `globals`, `rules`, ...) with the
|
|
32098
32103
|
* shared preset options and the top-level linter `options` object.
|
|
32099
32104
|
*/
|
|
32100
|
-
type OxlintFactoryOptions =
|
|
32105
|
+
type OxlintFactoryOptions = {
|
|
32101
32106
|
/**
|
|
32102
32107
|
* Rule categories to enable at the top level.
|
|
32103
32108
|
*
|
|
@@ -32107,6 +32112,21 @@ type OxlintFactoryOptions = Omit<TypedOxlintConfigItem, "files"> & OxlintOptions
|
|
|
32107
32112
|
* enabling one category leaves the rest off.
|
|
32108
32113
|
*/
|
|
32109
32114
|
categories?: RuleCategories$1;
|
|
32115
|
+
/**
|
|
32116
|
+
* Extra jsPlugins to load, or `false` to run oxlint with native rules
|
|
32117
|
+
* only.
|
|
32118
|
+
*
|
|
32119
|
+
* With `false` the factory drops every rule that would run through a
|
|
32120
|
+
* jsPlugin (spelling, the react and jest families, oxfmt formatting, ...),
|
|
32121
|
+
* leaving oxlint with its Rust rules and — when enabled — the tsgolint
|
|
32122
|
+
* type-aware ones. Pair it with `oxlint: "native"` in the ESLint factory,
|
|
32123
|
+
* which keeps exactly those rules in ESLint.
|
|
32124
|
+
*
|
|
32125
|
+
* `oxlint-comments` is the one exception: it lints the `oxlint-disable`
|
|
32126
|
+
* directives that native rules still need, ESLint cannot run it, and its
|
|
32127
|
+
* rules visit each file once, so it stays loaded.
|
|
32128
|
+
*/
|
|
32129
|
+
jsPlugins?: false | NonNullable<TypedOxlintConfigItem["jsPlugins"]>;
|
|
32110
32130
|
/**
|
|
32111
32131
|
* Top-level linter options emitted into the generated config
|
|
32112
32132
|
* (`typeAware`, `typeCheck`, `maxWarnings`, ...).
|
|
@@ -32124,7 +32144,7 @@ type OxlintFactoryOptions = Omit<TypedOxlintConfigItem, "files"> & OxlintOptions
|
|
|
32124
32144
|
* see no effect from this option.
|
|
32125
32145
|
*/
|
|
32126
32146
|
oxc?: boolean;
|
|
32127
|
-
};
|
|
32147
|
+
} & Omit<TypedOxlintConfigItem, "files" | "jsPlugins"> & OxlintOptionsConfig;
|
|
32128
32148
|
//#endregion
|
|
32129
32149
|
//#region src/oxlint/factory.d.ts
|
|
32130
32150
|
/**
|
|
@@ -32144,4 +32164,14 @@ type OxlintFactoryOptions = Omit<TypedOxlintConfigItem, "files"> & OxlintOptions
|
|
|
32144
32164
|
*/
|
|
32145
32165
|
declare function isentinel<const O extends OxlintFactoryOptions>(factoryOptions?: O & ValidateOxlintOptions<O>, ...userConfigs: Array<TypedOxlintConfigItem>): OxlintConfig$1;
|
|
32146
32166
|
//#endregion
|
|
32147
|
-
|
|
32167
|
+
//#region src/oxlint/utils.d.ts
|
|
32168
|
+
/**
|
|
32169
|
+
* Resolve a jsPlugin specifier, throwing when the package is not installed.
|
|
32170
|
+
*
|
|
32171
|
+
* @param specifier - The plugin package specifier.
|
|
32172
|
+
* @returns The absolute `file://` specifier.
|
|
32173
|
+
* @throws {Error} When the package cannot be resolved.
|
|
32174
|
+
*/
|
|
32175
|
+
declare function resolveJsPluginSpecifier(specifier: string): string;
|
|
32176
|
+
//#endregion
|
|
32177
|
+
export { type DummyRuleMap, type ExternalPluginEntry, type OxlintConfig, OxlintFactoryOptions, OxlintLinterOptions, OxlintNativeRuleName, type OxlintNativeRuleOptions, OxlintOptionsConfig, type OxlintOverride, OxlintPlugin, type OxlintRenamedJsPluginRuleOptions, type OxlintRuleOptions, type OxlintRules, OxlintSettings, type OxlintTarget, type RuleCategories, TypedOxlintConfigItem, isentinel as default, isentinel, isOxlintCovered, oxlintJsPlugins, oxlintRuleMapping, resolveJsPluginSpecifier, staysInEslint, translateRuleToOxlint };
|
package/dist/oxlint.mjs
CHANGED
|
@@ -978,10 +978,16 @@ const GLOB_SRC = "**/*.{,c,m}[jt]s{,x}";
|
|
|
978
978
|
const GLOB_JSX = "**/*.{,c,m}jsx";
|
|
979
979
|
const GLOB_TSX = "**/*.{,c,m}tsx";
|
|
980
980
|
const GLOB_DTS = "**/*.d.{,c,m}ts";
|
|
981
|
+
/**
|
|
982
|
+
* Type tests (`expectTypeOf` / `assertType`), run by Vitest's `typecheck`
|
|
983
|
+
* mode. They are test files, but assert nothing at runtime.
|
|
984
|
+
*/
|
|
985
|
+
const GLOB_TYPE_TESTS = `**/*.test-d.${GLOB_SRC_EXT}`;
|
|
981
986
|
const GLOB_TESTS = [
|
|
982
987
|
`**/__tests__/**/*.${GLOB_SRC_EXT}`,
|
|
983
988
|
`**/*.spec.${GLOB_SRC_EXT}`,
|
|
984
989
|
`**/*.test.${GLOB_SRC_EXT}`,
|
|
990
|
+
GLOB_TYPE_TESTS,
|
|
985
991
|
`**/*.bench.${GLOB_SRC_EXT}`,
|
|
986
992
|
`**/*.benchmark.${GLOB_SRC_EXT}`
|
|
987
993
|
];
|
|
@@ -1711,6 +1717,38 @@ function resolveJsPluginSpecifier(specifier) {
|
|
|
1711
1717
|
return resolved;
|
|
1712
1718
|
}
|
|
1713
1719
|
/**
|
|
1720
|
+
* The dedupe key for a jsPlugin entry (a bare specifier, or a named entry).
|
|
1721
|
+
*
|
|
1722
|
+
* @param entry - A bare package specifier, or a `{ name, specifier }` entry.
|
|
1723
|
+
* @returns The plugin name used to deduplicate registrations.
|
|
1724
|
+
*/
|
|
1725
|
+
function jsPluginKey(entry) {
|
|
1726
|
+
return typeof entry === "string" ? entry : entry.name;
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Drop every rule whose plugin prefix is not registered on the generated
|
|
1730
|
+
* config, mutating the overrides in place. Oxlint fails the whole config build
|
|
1731
|
+
* on a rule naming an unknown plugin, so entries left behind by a plugin that
|
|
1732
|
+
* native-only mode dropped have to go rather than sit inert.
|
|
1733
|
+
*
|
|
1734
|
+
* Keyed on what is actually registered, so a consumer's own jsPlugin keeps its
|
|
1735
|
+
* rules while a preset plugin that is no longer loaded loses them. Unprefixed
|
|
1736
|
+
* (core) rules are always kept.
|
|
1737
|
+
*
|
|
1738
|
+
* @param overrides - The merged overrides (mutated).
|
|
1739
|
+
* @param registeredPlugins - Every native plugin and jsPlugin name registered.
|
|
1740
|
+
*/
|
|
1741
|
+
function stripUnregisteredPluginRules(overrides, registeredPlugins) {
|
|
1742
|
+
for (const override of overrides) {
|
|
1743
|
+
const { rules } = override;
|
|
1744
|
+
if (rules === void 0) continue;
|
|
1745
|
+
for (const rule of Object.keys(rules)) {
|
|
1746
|
+
const slashIndex = rule.indexOf("/");
|
|
1747
|
+
if (slashIndex !== -1 && !registeredPlugins.has(rule.slice(0, slashIndex))) delete rules[rule];
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1714
1752
|
* Split a canonical (ESLint-named) rule map into oxlint-native rules and
|
|
1715
1753
|
* jsPlugin rules, translating rule names via the oxlint rule mapping.
|
|
1716
1754
|
*
|
|
@@ -3469,6 +3507,21 @@ function oxlintStylistic(options = {}) {
|
|
|
3469
3507
|
//#endregion
|
|
3470
3508
|
//#region src/rules/test.ts
|
|
3471
3509
|
/**
|
|
3510
|
+
* Rules that make no sense in a type test (`*.test-d.ts`): these files assert
|
|
3511
|
+
* with `expectTypeOf`/`assertType` at compile time, run no expectations, and
|
|
3512
|
+
* name their blocks after the types under test.
|
|
3513
|
+
*
|
|
3514
|
+
* @param prefix - The test-plugin prefix in use (`jest` or `vitest`).
|
|
3515
|
+
* @returns The rule map.
|
|
3516
|
+
*/
|
|
3517
|
+
function typeTestRules(prefix) {
|
|
3518
|
+
return {
|
|
3519
|
+
[`${prefix}/expect-expect`]: "off",
|
|
3520
|
+
[`${prefix}/prefer-expect-assertions`]: "off",
|
|
3521
|
+
[`${prefix}/prefer-lowercase-title`]: "off"
|
|
3522
|
+
};
|
|
3523
|
+
}
|
|
3524
|
+
/**
|
|
3472
3525
|
* Jest-extended rules shared between the ESLint and oxlint factories.
|
|
3473
3526
|
*
|
|
3474
3527
|
* @returns The rule map.
|
|
@@ -3690,6 +3743,11 @@ function oxlintTest({ files = GLOB_TESTS, isInEditor = false, jest = false, over
|
|
|
3690
3743
|
globalPackage: "@rbxts/jest-globals",
|
|
3691
3744
|
version: 27
|
|
3692
3745
|
} }
|
|
3746
|
+
}), ...createOxlintConfigs({
|
|
3747
|
+
name: "isentinel/test/jest/type-tests",
|
|
3748
|
+
files: [GLOB_TYPE_TESTS],
|
|
3749
|
+
keepUnmappedOff: true,
|
|
3750
|
+
rules: typeTestRules("jest")
|
|
3693
3751
|
}));
|
|
3694
3752
|
if (enableVitest) configs.push(...createOxlintConfigs({
|
|
3695
3753
|
name: "isentinel/test/vitest",
|
|
@@ -3705,6 +3763,11 @@ function oxlintTest({ files = GLOB_TESTS, isInEditor = false, jest = false, over
|
|
|
3705
3763
|
...vitestOptions.overrides
|
|
3706
3764
|
},
|
|
3707
3765
|
settings: { vitest: { typecheck: vitestOptions.typecheck ?? false } }
|
|
3766
|
+
}), ...createOxlintConfigs({
|
|
3767
|
+
name: "isentinel/test/vitest/type-tests",
|
|
3768
|
+
files: [GLOB_TYPE_TESTS],
|
|
3769
|
+
keepUnmappedOff: true,
|
|
3770
|
+
rules: typeTestRules("vitest")
|
|
3708
3771
|
}));
|
|
3709
3772
|
return configs;
|
|
3710
3773
|
}
|
|
@@ -4186,6 +4249,16 @@ const DEFAULT_CATEGORIES = {
|
|
|
4186
4249
|
suspicious: "off"
|
|
4187
4250
|
};
|
|
4188
4251
|
/**
|
|
4252
|
+
* JsPlugins the preset keeps even under `jsPlugins: false`.
|
|
4253
|
+
*
|
|
4254
|
+
* `oxlint-comments` lints the `oxlint-disable` directives that native rules
|
|
4255
|
+
* still need, and the ESLint side cannot take it over: its rules use oxlint's
|
|
4256
|
+
* `createOnce` API, which ESLint rejects. Its rules visit `Program` once per
|
|
4257
|
+
* file, so the cost is negligible next to the jsPlugin rule set that native-only
|
|
4258
|
+
* mode exists to avoid.
|
|
4259
|
+
*/
|
|
4260
|
+
const NATIVE_ONLY_JS_PLUGINS = /* @__PURE__ */ new Set(["oxlint-comments"]);
|
|
4261
|
+
/**
|
|
4189
4262
|
* Implementation signature; the public overload above carries the
|
|
4190
4263
|
* redundant-override validation generics.
|
|
4191
4264
|
*
|
|
@@ -4196,9 +4269,10 @@ const DEFAULT_CATEGORIES = {
|
|
|
4196
4269
|
*/
|
|
4197
4270
|
function isentinel(factoryOptions, ...userConfigs) {
|
|
4198
4271
|
const options = factoryOptions ?? { name: "isentinel" };
|
|
4199
|
-
const { categories, componentExts: componentExtensions = [], e18e: enableE18e = true, env, eslintPlugin: enableEslintPlugin = false, formatters, gitignore: enableGitignore = true, globals, ignores, jsdoc: enableJsdoc = true, jsx: enableJsx = true, options: linterOptions, oxc: enableOxc = true, react: enableReact = false, root: customRootGlobs, rules = {}, spellCheck: enableSpellCheck, test: enableTest = false } = options;
|
|
4272
|
+
const { categories, componentExts: componentExtensions = [], e18e: enableE18e = true, env, eslintPlugin: enableEslintPlugin = false, formatters, gitignore: enableGitignore = true, globals, ignores, jsdoc: enableJsdoc = true, jsPlugins: userJsPlugins, jsx: enableJsx = true, options: linterOptions, oxc: enableOxc = true, react: enableReact = false, root: customRootGlobs, rules = {}, spellCheck: enableSpellCheck, test: enableTest = false } = options;
|
|
4200
4273
|
const rootGlobs = mergeGlobs(GLOB_ROOT, customRootGlobs);
|
|
4201
4274
|
const enableRoblox = options.roblox !== false;
|
|
4275
|
+
const nativeOnly = userJsPlugins === false;
|
|
4202
4276
|
const robloxScopedFiles = typeof options.roblox === "object" && options.roblox.files !== void 0 ? options.roblox.files.flat() : void 0;
|
|
4203
4277
|
const hasComplement = !enableRoblox || robloxScopedFiles !== void 0;
|
|
4204
4278
|
const needsComplementOverlay = enableRoblox && robloxScopedFiles !== void 0;
|
|
@@ -4344,20 +4418,27 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
4344
4418
|
...gitignorePatterns,
|
|
4345
4419
|
...ignores ?? []
|
|
4346
4420
|
];
|
|
4421
|
+
/**
|
|
4422
|
+
* Merge a fragment into the accumulated overrides.
|
|
4423
|
+
*
|
|
4424
|
+
* @param config - The fragment to merge.
|
|
4425
|
+
*/
|
|
4347
4426
|
function mergeFragment(config) {
|
|
4427
|
+
const fragmentJsPlugins = config.jsPlugins ?? [];
|
|
4348
4428
|
const fragmentPlugins = config.plugins ?? [];
|
|
4349
4429
|
for (const plugin of fragmentPlugins) nativePlugins.add(plugin);
|
|
4350
|
-
const fragmentJsPlugins
|
|
4351
|
-
for (const jsPlugin of fragmentJsPlugins) {
|
|
4352
|
-
const key = typeof jsPlugin === "string" ? jsPlugin : jsPlugin.name;
|
|
4353
|
-
jsPlugins.set(key, jsPlugin);
|
|
4354
|
-
}
|
|
4430
|
+
for (const jsPlugin of fragmentJsPlugins) jsPlugins.set(jsPluginKey(jsPlugin), jsPlugin);
|
|
4355
4431
|
if (config.settings) Object.assign(mergedSettings, config.settings);
|
|
4356
4432
|
const { name: _name, plugins: _plugins, settings: _settings, ...override } = config;
|
|
4357
4433
|
overrides.push(override);
|
|
4358
4434
|
}
|
|
4359
|
-
const
|
|
4360
|
-
|
|
4435
|
+
for (const fragment of configs.flat()) {
|
|
4436
|
+
if (nativeOnly && droppedByNativeOnly(fragment)) {
|
|
4437
|
+
if (fragment.settings) Object.assign(mergedSettings, fragment.settings);
|
|
4438
|
+
continue;
|
|
4439
|
+
}
|
|
4440
|
+
mergeFragment(fragment);
|
|
4441
|
+
}
|
|
4361
4442
|
if (Object.keys(rules).length > 0) {
|
|
4362
4443
|
const optionsFragments = createOxlintConfigs({
|
|
4363
4444
|
name: "isentinel/options-rules",
|
|
@@ -4365,7 +4446,10 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
4365
4446
|
keepUnmappedOff: true,
|
|
4366
4447
|
rules
|
|
4367
4448
|
});
|
|
4368
|
-
for (const fragment of optionsFragments)
|
|
4449
|
+
for (const fragment of optionsFragments) {
|
|
4450
|
+
const { jsPlugins: _fragmentJsPlugins, ...withoutJsPlugins } = fragment;
|
|
4451
|
+
mergeFragment(nativeOnly ? withoutJsPlugins : fragment);
|
|
4452
|
+
}
|
|
4369
4453
|
}
|
|
4370
4454
|
if (globals && Object.keys(globals).length > 0) mergeFragment({
|
|
4371
4455
|
name: "isentinel/options-globals",
|
|
@@ -4373,6 +4457,8 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
4373
4457
|
globals
|
|
4374
4458
|
});
|
|
4375
4459
|
for (const userConfig of userConfigs) mergeFragment(userConfig);
|
|
4460
|
+
if (Array.isArray(userJsPlugins)) for (const jsPlugin of userJsPlugins) jsPlugins.set(jsPluginKey(jsPlugin), jsPlugin);
|
|
4461
|
+
if (nativeOnly) stripUnregisteredPluginRules(overrides, /* @__PURE__ */ new Set([...nativePlugins, ...jsPlugins.keys()]));
|
|
4376
4462
|
if (defaultSeverity) {
|
|
4377
4463
|
const severityExcludeRules = /* @__PURE__ */ new Set(["sonar/todo-tag"]);
|
|
4378
4464
|
for (const override of overrides) if (override.rules) override.rules = overrideRuleSeverity(override.rules, defaultSeverity, severityExcludeRules);
|
|
@@ -4395,5 +4481,16 @@ function isentinel(factoryOptions, ...userConfigs) {
|
|
|
4395
4481
|
settings: mergedSettings
|
|
4396
4482
|
});
|
|
4397
4483
|
}
|
|
4484
|
+
/**
|
|
4485
|
+
* Whether native-only mode drops a preset fragment: it needs a jsPlugin, and at
|
|
4486
|
+
* least one of them is not kept in that mode.
|
|
4487
|
+
*
|
|
4488
|
+
* @param fragment - The preset fragment.
|
|
4489
|
+
* @returns Whether the fragment is dropped.
|
|
4490
|
+
*/
|
|
4491
|
+
function droppedByNativeOnly(fragment) {
|
|
4492
|
+
const fragmentJsPlugins = fragment.jsPlugins ?? [];
|
|
4493
|
+
return fragmentJsPlugins.length > 0 && fragmentJsPlugins.some((entry) => !NATIVE_ONLY_JS_PLUGINS.has(jsPluginKey(entry)));
|
|
4494
|
+
}
|
|
4398
4495
|
//#endregion
|
|
4399
|
-
export { isentinel as default, isentinel, isOxlintCovered, oxlintJsPlugins, oxlintRuleMapping, staysInEslint, translateRuleToOxlint };
|
|
4496
|
+
export { isentinel as default, isentinel, isOxlintCovered, oxlintJsPlugins, oxlintRuleMapping, resolveJsPluginSpecifier, staysInEslint, translateRuleToOxlint };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@isentinel/eslint-config",
|
|
3
|
-
"version": "6.0.0-beta.
|
|
3
|
+
"version": "6.0.0-beta.14",
|
|
4
4
|
"description": "iSentinel's ESLint config",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint-config",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"typescript": "6.0.3",
|
|
139
139
|
"unplugin-unused": "0.5.7",
|
|
140
140
|
"vitest": "4.1.10",
|
|
141
|
-
"@isentinel/eslint-config": "6.0.0-beta.
|
|
141
|
+
"@isentinel/eslint-config": "6.0.0-beta.14"
|
|
142
142
|
},
|
|
143
143
|
"peerDependencies": {
|
|
144
144
|
"@vitest/eslint-plugin": "^1.6.4",
|