@oxlint/migrate 1.49.0 → 1.51.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 +14 -14
- package/dist/bin/oxlint-migrate.mjs +19 -7
- package/dist/{settings-Bb6227Gq.mjs → settings-R7dCJ7Y3.mjs} +126 -20
- package/dist/src/index.d.mts +85 -2649
- package/dist/src/index.mjs +10 -2
- package/package.json +14 -9
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @oxlint/migrate
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-
[](https://
|
|
5
|
-
[](https://
|
|
4
|
+
[](https://npmx.dev/package/@oxlint/migrate)
|
|
5
|
+
[](https://npmx.dev/package/@oxlint/migrate)
|
|
6
6
|
|
|
7
7
|
Generates a `.oxlintrc.json` from an existing ESLint flat config.
|
|
8
8
|
|
|
@@ -18,15 +18,15 @@ When no config file is provided, the script searches for the default ESLint conf
|
|
|
18
18
|
|
|
19
19
|
### Options
|
|
20
20
|
|
|
21
|
-
| Options | Description
|
|
22
|
-
| --------------------------- |
|
|
23
|
-
| `--merge` | \* merge ESLint configuration with an existing .oxlintrc.json configuration
|
|
24
|
-
| `--type-aware` | Include type aware rules
|
|
25
|
-
| `--with-nursery` | Include oxlint rules which are currently under development
|
|
26
|
-
| `--js-plugins`
|
|
27
|
-
| `--details` | List rules that could not be migrated to oxlint
|
|
28
|
-
| `--output-file <file>` | The oxlint configuration file where ESLint v9 rules will be written to, default: `.oxlintrc.json`
|
|
29
|
-
| `--replace-eslint-comments` | Search in the project files for ESLint comments and replaces them with oxlint. Some ESLint comments are not supported and will be reported.
|
|
21
|
+
| Options | Description |
|
|
22
|
+
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| `--merge` | \* merge ESLint configuration with an existing .oxlintrc.json configuration |
|
|
24
|
+
| `--type-aware` | Include type aware rules. These rules are supported with `oxlint --type-aware` and [oxlint-tsgolint](https://github.com/oxc-project/tsgolint). This will also enable the `typeAware` option in the generated configuration. |
|
|
25
|
+
| `--with-nursery` | Include oxlint rules which are currently under development |
|
|
26
|
+
| `--js-plugins [bool]` | \*\* Include ESLint plugins via `jsPlugins` key (enabled by default). Use `--js-plugins=false` to disable. |
|
|
27
|
+
| `--details` | List rules that could not be migrated to oxlint |
|
|
28
|
+
| `--output-file <file>` | The oxlint configuration file where ESLint v9 rules will be written to, default: `.oxlintrc.json` |
|
|
29
|
+
| `--replace-eslint-comments` | Search in the project files for ESLint comments and replaces them with oxlint. Some ESLint comments are not supported and will be reported. |
|
|
30
30
|
|
|
31
31
|
\* WARNING: When some `categories` are enabled, this tools will enable more rules with the combination of `plugins`.
|
|
32
32
|
Else we need to disable each rule `plugin/categories` combination, which is not covered by your ESLint configuration.
|
|
@@ -49,7 +49,7 @@ TypeScript configuration files, like `eslint.config.mts`, are supported in the f
|
|
|
49
49
|
- **Deno and Bun**: TypeScript configuration files are natively supported.
|
|
50
50
|
- **Node.js >=22.18.0**: TypeScript configuration files are supported natively with built-in type-stripping enabled by default.
|
|
51
51
|
- **Node.js >=22.6.0**: TypeScript configuration files can be used by setting `NODE_OPTIONS=--experimental-strip-types`.
|
|
52
|
-
- **Node.js <22.6.0**: TypeScript configuration files can be used by setting `NODE_OPTIONS=--import @oxc-node/core/register` and installing [@oxc-node/core](https://
|
|
52
|
+
- **Node.js <22.6.0**: TypeScript configuration files can be used by setting `NODE_OPTIONS=--import @oxc-node/core/register` and installing [@oxc-node/core](https://npmx.dev/package/@oxc-node/core) as a dev dependency.
|
|
53
53
|
|
|
54
54
|
If you attempt to use a TypeScript configuration file without the proper setup for your Node.js version, Node.js will throw an error when trying to import the file.
|
|
55
55
|
|
|
@@ -65,7 +65,7 @@ Here are some known caveats to be aware of:
|
|
|
65
65
|
|
|
66
66
|
**`settings` field migration**
|
|
67
67
|
|
|
68
|
-
The `settings` field (e.g. for setting the React version) is migrated for known oxlint-supported plugins: `jsx-a11y`, `next`, `react`, `jsdoc`, and `vitest`. By default, other settings keys are
|
|
68
|
+
The `settings` field (e.g. for setting the React version) is migrated for known oxlint-supported plugins: `jsx-a11y`, `next`, `react`, `jsdoc`, and `vitest`. By default, other settings keys are also migrated to support JS Plugins. Use `--js-plugins=false` to skip migrating unknown settings keys.
|
|
69
69
|
|
|
70
70
|
Note: Oxlint does not support `settings` in override configs. If your ESLint config has settings in configs with `files` patterns, those settings will be skipped and a warning will be shown.
|
|
71
71
|
|
|
@@ -73,7 +73,7 @@ Not all `settings` options are supported by oxlint, and so rule behavior in cert
|
|
|
73
73
|
|
|
74
74
|
**Local ESLint Plugins imported via path are not migrated**
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
JS plugin migration cannot migrate ESLint plugins from file paths in the same repo currently (e.g. if you have `../eslint-plugin-myplugin` in your `eslint.config.mjs`). You will need to copy them over into the `jsPlugins` manually. See [the JS Plugins docs]() for more info.
|
|
77
77
|
|
|
78
78
|
**`globals` field with large number of values**
|
|
79
79
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as preFixForJsPlugins, f as buildUnsupportedRuleExplanations, m as rules_exports, p as nurseryRules, u as isOffValue } from "../settings-
|
|
2
|
+
import { a as preFixForJsPlugins, f as buildUnsupportedRuleExplanations, m as rules_exports, p as nurseryRules, u as isOffValue } from "../settings-R7dCJ7Y3.mjs";
|
|
3
3
|
import main from "../src/index.mjs";
|
|
4
4
|
import { program } from "commander";
|
|
5
5
|
import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -33,7 +33,7 @@ const loadESLintConfig = async (filePath) => {
|
|
|
33
33
|
|
|
34
34
|
//#endregion
|
|
35
35
|
//#region package.json
|
|
36
|
-
var version = "1.
|
|
36
|
+
var version = "1.51.0";
|
|
37
37
|
|
|
38
38
|
//#endregion
|
|
39
39
|
//#region src/walker/comments/replaceRuleDirectiveComment.ts
|
|
@@ -357,7 +357,7 @@ function detectMissingFlags(byCategory, cliOptions) {
|
|
|
357
357
|
const missingFlags = [];
|
|
358
358
|
if (byCategory.nursery.length > 0 && !cliOptions.withNursery) missingFlags.push("--with-nursery");
|
|
359
359
|
if (byCategory["type-aware"].length > 0 && !cliOptions.typeAware) missingFlags.push("--type-aware");
|
|
360
|
-
if (byCategory["js-plugins"].length > 0 && !cliOptions.jsPlugins) missingFlags.push("--js-plugins");
|
|
360
|
+
if (byCategory["js-plugins"].length > 0 && !cliOptions.jsPlugins) missingFlags.push("--js-plugins=true");
|
|
361
361
|
return missingFlags;
|
|
362
362
|
}
|
|
363
363
|
/**
|
|
@@ -399,14 +399,25 @@ function formatMigrationOutput(data) {
|
|
|
399
399
|
}
|
|
400
400
|
return output;
|
|
401
401
|
}
|
|
402
|
+
function formatWarningsOutput(warnings) {
|
|
403
|
+
if (warnings.length === 0) return "";
|
|
404
|
+
let output = `⚠️ Warnings (${warnings.length}):\n`;
|
|
405
|
+
for (const warning of warnings) {
|
|
406
|
+
const [message, ...details] = warning.split("\n");
|
|
407
|
+
output += ` * ${message}\n`;
|
|
408
|
+
for (const detail of details.filter((line) => line.trim().length)) output += ` * ${detail}\n`;
|
|
409
|
+
}
|
|
410
|
+
return output.trimEnd();
|
|
411
|
+
}
|
|
402
412
|
function displayMigrationResult(outputMessage, warnings) {
|
|
403
413
|
console.log(outputMessage);
|
|
404
|
-
|
|
414
|
+
if (warnings.length > 0) console.warn(formatWarningsOutput(warnings));
|
|
405
415
|
}
|
|
406
416
|
|
|
407
417
|
//#endregion
|
|
408
418
|
//#region bin/oxlint-migrate.ts
|
|
409
419
|
const cwd = process.cwd();
|
|
420
|
+
const parseCliBoolean = (value) => value === "false" ? false : !!value;
|
|
410
421
|
const getFileContent = (absoluteFilePath) => {
|
|
411
422
|
try {
|
|
412
423
|
return readFileSync(absoluteFilePath, "utf-8");
|
|
@@ -429,8 +440,9 @@ const countEnabledRules = (config) => {
|
|
|
429
440
|
}
|
|
430
441
|
return enabledRules.size;
|
|
431
442
|
};
|
|
432
|
-
program.name("oxlint-migrate").version(version).argument("[eslint-config]", "The path to the eslint v9 config file").option("--output-file <file>", "The oxlint configuration file where to eslint v9 rules will be written to", ".oxlintrc.json").option("--merge", "Merge eslint configuration with an existing .oxlintrc.json configuration", false).option("--with-nursery", "Include oxlint rules which are currently under development", false).option("--replace-eslint-comments", "Search in the project files for eslint comments and replaces them with oxlint. Some eslint comments are not supported and will be reported.").option("--type-aware", "Includes supported type-aware rules. Needs the same flag in `oxlint` to enable it.").option("--js-plugins", "Tries to convert unsupported oxlint plugins with `jsPlugins`.").option("--details", "List rules that could not be migrated to oxlint.", false).action(async (filePath) => {
|
|
443
|
+
program.name("oxlint-migrate").version(version).argument("[eslint-config]", "The path to the eslint v9 config file").option("--output-file <file>", "The oxlint configuration file where to eslint v9 rules will be written to", ".oxlintrc.json").option("--merge", "Merge eslint configuration with an existing .oxlintrc.json configuration", false).option("--with-nursery", "Include oxlint rules which are currently under development", false).option("--replace-eslint-comments", "Search in the project files for eslint comments and replaces them with oxlint. Some eslint comments are not supported and will be reported.").option("--type-aware", "Includes supported type-aware rules. Needs the same flag in `oxlint` or the `typeAware` config option to enable it.").option("--js-plugins [bool]", "Tries to convert unsupported oxlint plugins with `jsPlugins`. Enabled by default; pass `--js-plugins=false` to disable.", true).option("--details", "List rules that could not be migrated to oxlint.", false).action(async (filePath) => {
|
|
433
444
|
const cliOptions = program.opts();
|
|
445
|
+
const jsPlugins = parseCliBoolean(cliOptions.jsPlugins);
|
|
434
446
|
const oxlintFilePath = path.join(cwd, cliOptions.outputFile);
|
|
435
447
|
const reporter = new DefaultReporter();
|
|
436
448
|
const options = {
|
|
@@ -438,7 +450,7 @@ program.name("oxlint-migrate").version(version).argument("[eslint-config]", "The
|
|
|
438
450
|
merge: !!cliOptions.merge,
|
|
439
451
|
withNursery: !!cliOptions.withNursery,
|
|
440
452
|
typeAware: !!cliOptions.typeAware,
|
|
441
|
-
jsPlugins
|
|
453
|
+
jsPlugins
|
|
442
454
|
};
|
|
443
455
|
if (cliOptions.replaceEslintComments) {
|
|
444
456
|
await walkAndReplaceProjectFiles(await getAllProjectFiles(), (filePath) => getFileContent(filePath), (filePath, content) => writeFile(filePath, content, "utf-8"), options);
|
|
@@ -467,7 +479,7 @@ program.name("oxlint-migrate").version(version).argument("[eslint-config]", "The
|
|
|
467
479
|
withNursery: !!cliOptions.withNursery,
|
|
468
480
|
typeAware: !!cliOptions.typeAware,
|
|
469
481
|
details: !!cliOptions.details,
|
|
470
|
-
jsPlugins
|
|
482
|
+
jsPlugins
|
|
471
483
|
},
|
|
472
484
|
eslintConfigPath: filePath
|
|
473
485
|
}), reporter.getWarnings());
|
|
@@ -476,6 +476,7 @@ const styleRules = [
|
|
|
476
476
|
"unicorn/prefer-string-raw",
|
|
477
477
|
"unicorn/prefer-string-trim-start-end",
|
|
478
478
|
"unicorn/prefer-structured-clone",
|
|
479
|
+
"unicorn/prefer-ternary",
|
|
479
480
|
"unicorn/relative-url-style",
|
|
480
481
|
"unicorn/require-array-join-separator",
|
|
481
482
|
"unicorn/require-module-attributes",
|
|
@@ -682,6 +683,7 @@ const restrictionRules = [
|
|
|
682
683
|
"unicorn/no-process-exit",
|
|
683
684
|
"unicorn/no-useless-error-capture-stack-trace",
|
|
684
685
|
"unicorn/prefer-modern-math-apis",
|
|
686
|
+
"unicorn/prefer-module",
|
|
685
687
|
"unicorn/prefer-node-protocol",
|
|
686
688
|
"unicorn/prefer-number-properties",
|
|
687
689
|
"vue/max-props",
|
|
@@ -1069,13 +1071,47 @@ const ignorePlugins = new Set([
|
|
|
1069
1071
|
...Object.values(rulesPrefixesForPlugins),
|
|
1070
1072
|
"local"
|
|
1071
1073
|
]);
|
|
1072
|
-
const
|
|
1074
|
+
const tryResolvePackage = (packageName) => {
|
|
1075
|
+
try {
|
|
1076
|
+
import.meta.resolve(packageName);
|
|
1077
|
+
return true;
|
|
1078
|
+
} catch {
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
const pluginNameCache = /* @__PURE__ */ new Map();
|
|
1083
|
+
/**
|
|
1084
|
+
* Resolves the npm package name for an ESLint plugin given its scope name.
|
|
1085
|
+
*
|
|
1086
|
+
* For scoped plugin names (starting with `@`), the mapping is unambiguous:
|
|
1087
|
+
* - `@scope` -> `@scope/eslint-plugin`
|
|
1088
|
+
* - `@scope/sub` -> `@scope/eslint-plugin-sub`
|
|
1089
|
+
*
|
|
1090
|
+
* For non-scoped names, the npm package could follow either convention:
|
|
1091
|
+
* - `eslint-plugin-{name}` (e.g. `eslint-plugin-mocha`)
|
|
1092
|
+
* - `@{name}/eslint-plugin` (e.g. `@e18e/eslint-plugin`)
|
|
1093
|
+
*
|
|
1094
|
+
* We try to resolve both candidates against the installed packages and
|
|
1095
|
+
* use the one that is actually present, falling back to the standard
|
|
1096
|
+
* `eslint-plugin-{name}` convention when neither can be resolved.
|
|
1097
|
+
*/
|
|
1098
|
+
const resolveEslintPluginName = (pluginName) => {
|
|
1099
|
+
const cached = pluginNameCache.get(pluginName);
|
|
1100
|
+
if (cached !== void 0) return cached;
|
|
1101
|
+
let result;
|
|
1073
1102
|
if (pluginName.startsWith("@")) {
|
|
1074
1103
|
const [scope, maybeSub] = pluginName.split("/");
|
|
1075
|
-
if (maybeSub)
|
|
1076
|
-
|
|
1104
|
+
if (maybeSub) result = `${scope}/eslint-plugin-${maybeSub}`;
|
|
1105
|
+
else result = `${scope}/eslint-plugin`;
|
|
1106
|
+
} else {
|
|
1107
|
+
const standardName = `eslint-plugin-${pluginName}`;
|
|
1108
|
+
const scopedName = `@${pluginName}/eslint-plugin`;
|
|
1109
|
+
if (tryResolvePackage(standardName)) result = standardName;
|
|
1110
|
+
else if (tryResolvePackage(scopedName)) result = scopedName;
|
|
1111
|
+
else result = standardName;
|
|
1077
1112
|
}
|
|
1078
|
-
|
|
1113
|
+
pluginNameCache.set(pluginName, result);
|
|
1114
|
+
return result;
|
|
1079
1115
|
};
|
|
1080
1116
|
const extractPluginId = (ruleId) => {
|
|
1081
1117
|
const firstSlash = ruleId.indexOf("/");
|
|
@@ -1091,15 +1127,68 @@ const isIgnoredPluginRule = (ruleId) => {
|
|
|
1091
1127
|
if (pluginName === void 0) return true;
|
|
1092
1128
|
return ignorePlugins.has(pluginName);
|
|
1093
1129
|
};
|
|
1094
|
-
|
|
1130
|
+
/**
|
|
1131
|
+
* Derives the npm package name for a plugin from its `meta.name` field.
|
|
1132
|
+
*
|
|
1133
|
+
* If `meta.name` already looks like a full npm package name (contains
|
|
1134
|
+
* "eslint-plugin"), it is returned as-is. Otherwise it is fed through
|
|
1135
|
+
* {@link resolveEslintPluginName} for the usual heuristic resolution.
|
|
1136
|
+
*/
|
|
1137
|
+
const resolveFromMetaName = (metaName) => {
|
|
1138
|
+
if (metaName.includes("eslint-plugin")) return metaName;
|
|
1139
|
+
return resolveEslintPluginName(metaName);
|
|
1140
|
+
};
|
|
1141
|
+
/**
|
|
1142
|
+
* Derives the rule-ID prefix that an npm package exposes.
|
|
1143
|
+
*
|
|
1144
|
+
* Examples:
|
|
1145
|
+
* `eslint-plugin-react-dom` -> `react-dom`
|
|
1146
|
+
* `eslint-plugin-mocha` -> `mocha`
|
|
1147
|
+
* `@stylistic/eslint-plugin` -> `@stylistic`
|
|
1148
|
+
* `@stylistic/eslint-plugin-ts` -> `@stylistic/ts`
|
|
1149
|
+
*/
|
|
1150
|
+
const deriveRulePrefix = (packageName) => {
|
|
1151
|
+
if (packageName.startsWith("@")) {
|
|
1152
|
+
const slashIdx = packageName.indexOf("/");
|
|
1153
|
+
const scope = packageName.substring(0, slashIdx);
|
|
1154
|
+
const rest = packageName.substring(slashIdx + 1);
|
|
1155
|
+
if (rest === "eslint-plugin") return scope;
|
|
1156
|
+
if (rest.startsWith("eslint-plugin-")) return `${scope}/${rest.substring(14)}`;
|
|
1157
|
+
return packageName;
|
|
1158
|
+
}
|
|
1159
|
+
if (packageName.startsWith("eslint-plugin-")) return packageName.substring(14);
|
|
1160
|
+
return packageName;
|
|
1161
|
+
};
|
|
1162
|
+
/**
|
|
1163
|
+
* Resolves the canonical rule name for a jsPlugin rule.
|
|
1164
|
+
*
|
|
1165
|
+
* When a plugin is registered under an alias (e.g. `@eslint-react/dom`) but
|
|
1166
|
+
* its `meta.name` reveals a different canonical package (`eslint-plugin-react-dom`),
|
|
1167
|
+
* the rule must be rewritten so that oxlint can match it to the loaded plugin.
|
|
1168
|
+
*
|
|
1169
|
+
* For example:
|
|
1170
|
+
* `@eslint-react/dom/no-find-dom-node` -> `react-dom/no-find-dom-node`
|
|
1171
|
+
*/
|
|
1172
|
+
const resolveJsPluginRuleName = (rule, plugins) => {
|
|
1173
|
+
const pluginName = extractPluginId(rule);
|
|
1174
|
+
if (pluginName === void 0) return rule;
|
|
1175
|
+
const metaName = plugins?.[pluginName]?.meta?.name;
|
|
1176
|
+
if (!metaName || !metaName.includes("eslint-plugin")) return rule;
|
|
1177
|
+
const canonicalPrefix = deriveRulePrefix(metaName);
|
|
1178
|
+
if (canonicalPrefix === pluginName) return rule;
|
|
1179
|
+
return `${canonicalPrefix}/${rule.substring(pluginName.length + 1)}`;
|
|
1180
|
+
};
|
|
1181
|
+
const enableJsPluginRule = (targetConfig, rule, ruleEntry, plugins) => {
|
|
1095
1182
|
const pluginName = extractPluginId(rule);
|
|
1096
1183
|
if (pluginName === void 0) return false;
|
|
1097
1184
|
if (ignorePlugins.has(pluginName)) return false;
|
|
1098
1185
|
if (targetConfig.jsPlugins === void 0) targetConfig.jsPlugins = [];
|
|
1099
|
-
const
|
|
1186
|
+
const metaName = plugins?.[pluginName]?.meta?.name;
|
|
1187
|
+
const eslintPluginName = metaName ? resolveFromMetaName(metaName) : resolveEslintPluginName(pluginName);
|
|
1100
1188
|
if (!targetConfig.jsPlugins.includes(eslintPluginName)) targetConfig.jsPlugins.push(eslintPluginName);
|
|
1189
|
+
const resolvedRule = resolveJsPluginRuleName(rule, plugins);
|
|
1101
1190
|
targetConfig.rules = targetConfig.rules || {};
|
|
1102
|
-
targetConfig.rules[
|
|
1191
|
+
targetConfig.rules[resolvedRule] = ruleEntry;
|
|
1103
1192
|
return true;
|
|
1104
1193
|
};
|
|
1105
1194
|
|
|
@@ -1144,6 +1233,7 @@ var unsupportedRules = {
|
|
|
1144
1233
|
"import/no-deprecated": "No need to implement, already implemented by `typescript/no-deprecated` via tsgolint.",
|
|
1145
1234
|
"n/no-restricted-import": "No need to implement, already implemented by `no-restricted-imports` rule.",
|
|
1146
1235
|
"n/no-restricted-require": "No need to implement, already implemented by `no-restricted-imports` rule.",
|
|
1236
|
+
"import/order": "Not implementing this in Oxlint as its behavior is covered very well by [Oxfmt's import sorting](https://oxc.rs/docs/guide/usage/formatter/sorting.html).",
|
|
1147
1237
|
"jsdoc/type-formatting": "Experimental rule in the original plugin, may reconsider once stable.",
|
|
1148
1238
|
"jsdoc/convert-to-jsdoc-comments": "Experimental rule in the original plugin, may reconsider once stable.",
|
|
1149
1239
|
"jsdoc/check-examples": "Deprecated.",
|
|
@@ -1569,12 +1659,22 @@ const mergeRuleConfig = (existingConfig, newConfig) => {
|
|
|
1569
1659
|
if (Array.isArray(newConfig) && newConfig.length === 1 && existingIsArray && existingConfig.length > 1) return [newConfig[0], ...existingConfig.slice(1)];
|
|
1570
1660
|
return newConfig;
|
|
1571
1661
|
};
|
|
1572
|
-
const transformRuleEntry = (eslintConfig, targetConfig, baseConfig, options, overrides) => {
|
|
1662
|
+
const transformRuleEntry = (eslintConfig, targetConfig, baseConfig, options, overrides, globalPlugins) => {
|
|
1573
1663
|
if (eslintConfig.rules === void 0) return;
|
|
1574
1664
|
if (targetConfig.rules === void 0) targetConfig.rules = {};
|
|
1665
|
+
const effectivePlugins = globalPlugins ? {
|
|
1666
|
+
...globalPlugins,
|
|
1667
|
+
...eslintConfig.plugins
|
|
1668
|
+
} : eslintConfig.plugins;
|
|
1575
1669
|
for (const [rule, config] of Object.entries(eslintConfig.rules)) {
|
|
1576
1670
|
const normalizedConfig = normalizeSeverityValue(config);
|
|
1577
|
-
if (!options?.merge)
|
|
1671
|
+
if (!options?.merge) {
|
|
1672
|
+
removePreviousOverrideRule(rule, eslintConfig, overrides);
|
|
1673
|
+
if (options?.jsPlugins) {
|
|
1674
|
+
const resolved = resolveJsPluginRuleName(rule, effectivePlugins);
|
|
1675
|
+
if (resolved !== rule) removePreviousOverrideRule(resolved, eslintConfig, overrides);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1578
1678
|
if (allRules.includes(rule)) {
|
|
1579
1679
|
if (!options?.withNursery && nurseryRules.includes(rule)) {
|
|
1580
1680
|
options?.reporter?.markSkipped(rule, "nursery");
|
|
@@ -1593,8 +1693,9 @@ const transformRuleEntry = (eslintConfig, targetConfig, baseConfig, options, ove
|
|
|
1593
1693
|
} else {
|
|
1594
1694
|
if (options?.jsPlugins) {
|
|
1595
1695
|
if (isOffValue(normalizedConfig)) {
|
|
1596
|
-
|
|
1597
|
-
|
|
1696
|
+
const resolvedRule = resolveJsPluginRuleName(rule, effectivePlugins);
|
|
1697
|
+
if (eslintConfig.files === void 0) delete targetConfig.rules[resolvedRule];
|
|
1698
|
+
else if (!isIgnoredPluginRule(rule)) targetConfig.rules[resolvedRule] = normalizedConfig;
|
|
1598
1699
|
if (eslintConfig.files === void 0) {
|
|
1599
1700
|
options?.reporter?.removeSkipped(rule, "js-plugins");
|
|
1600
1701
|
options?.reporter?.removeSkipped(rule, "not-implemented");
|
|
@@ -1602,7 +1703,7 @@ const transformRuleEntry = (eslintConfig, targetConfig, baseConfig, options, ove
|
|
|
1602
1703
|
}
|
|
1603
1704
|
continue;
|
|
1604
1705
|
}
|
|
1605
|
-
if (!enableJsPluginRule(targetConfig, rule, normalizedConfig)) {
|
|
1706
|
+
if (!enableJsPluginRule(targetConfig, rule, normalizedConfig, effectivePlugins)) {
|
|
1606
1707
|
const category = unsupportedRuleExplanations[rule] ? "unsupported" : "not-implemented";
|
|
1607
1708
|
options?.reporter?.markSkipped(rule, category);
|
|
1608
1709
|
}
|
|
@@ -1989,6 +2090,13 @@ const isSupportedSettingsKey = (key) => {
|
|
|
1989
2090
|
return OXLINT_SUPPORTED_SETTINGS_KEYS.includes(key);
|
|
1990
2091
|
};
|
|
1991
2092
|
/**
|
|
2093
|
+
* Format a list of settings keys into a newline-separated, backtick-quoted
|
|
2094
|
+
* string for warning output.
|
|
2095
|
+
*/
|
|
2096
|
+
const formatSettingsKeyList = (keys) => {
|
|
2097
|
+
return keys.map((key) => `\`${key}\``).join("\n");
|
|
2098
|
+
};
|
|
2099
|
+
/**
|
|
1992
2100
|
* Transform ESLint settings to oxlint settings.
|
|
1993
2101
|
*
|
|
1994
2102
|
* Only processes settings for the base config (not overrides) since oxlint
|
|
@@ -2025,24 +2133,22 @@ const transformSettings = (eslintConfig, targetConfig, options) => {
|
|
|
2025
2133
|
}
|
|
2026
2134
|
let settingsValue = value;
|
|
2027
2135
|
if (key === "react" && settingsValue.version === "detect") {
|
|
2028
|
-
options?.reporter?.addWarning("react.version \"detect\" is not supported
|
|
2136
|
+
options?.reporter?.addWarning("react.version \"detect\" is not supported. Specify an explicit version (e.g., \"18.2.0\") in your oxlint config.");
|
|
2029
2137
|
const { version: _, ...restReactSettings } = settingsValue;
|
|
2030
2138
|
settingsValue = restReactSettings;
|
|
2031
2139
|
}
|
|
2032
2140
|
const unsupportedSubKeys = UNSUPPORTED_SETTINGS_SUB_KEYS[key];
|
|
2033
2141
|
if (unsupportedSubKeys !== void 0) {
|
|
2034
|
-
const strippedKeys = [];
|
|
2035
2142
|
for (const subKey of unsupportedSubKeys) if (subKey in settingsValue) {
|
|
2036
|
-
|
|
2143
|
+
skippedKeys.push(`${key}.${subKey}`);
|
|
2037
2144
|
const { [subKey]: _, ...rest } = settingsValue;
|
|
2038
2145
|
settingsValue = rest;
|
|
2039
2146
|
}
|
|
2040
|
-
if (strippedKeys.length > 0) options?.reporter?.addWarning(`Settings not migrated (not supported by oxlint): ${strippedKeys.join(", ")}.`);
|
|
2041
2147
|
}
|
|
2042
2148
|
if (Object.keys(settingsValue).length === 0) continue;
|
|
2043
2149
|
filteredSettings[key] = settingsValue;
|
|
2044
2150
|
}
|
|
2045
|
-
if (skippedKeys.length > 0) options?.reporter?.addWarning(`Settings not migrated (not supported by oxlint)
|
|
2151
|
+
if (skippedKeys.length > 0) options?.reporter?.addWarning(`Settings not migrated (not supported by oxlint):\n${formatSettingsKeyList(skippedKeys)}`);
|
|
2046
2152
|
if (Object.keys(filteredSettings).length === 0) return;
|
|
2047
2153
|
if (targetConfig.settings === void 0) targetConfig.settings = {};
|
|
2048
2154
|
if (options?.merge) deepMerge(targetConfig.settings, filteredSettings);
|
|
@@ -2057,10 +2163,10 @@ const transformSettings = (eslintConfig, targetConfig, options) => {
|
|
|
2057
2163
|
*/
|
|
2058
2164
|
const warnSettingsInOverride = (eslintConfig, options) => {
|
|
2059
2165
|
if (eslintConfig.settings !== void 0 && eslintConfig.settings !== null && Object.keys(eslintConfig.settings).length > 0) {
|
|
2060
|
-
const settingsKeys = Object.keys(eslintConfig.settings)
|
|
2061
|
-
options?.reporter?.addWarning(
|
|
2166
|
+
const settingsKeys = Object.keys(eslintConfig.settings);
|
|
2167
|
+
options?.reporter?.addWarning("Settings found under a 'files' pattern — oxlint does not support settings in overrides and they will be skipped:\n" + formatSettingsKeyList(settingsKeys));
|
|
2062
2168
|
}
|
|
2063
2169
|
};
|
|
2064
2170
|
|
|
2065
2171
|
//#endregion
|
|
2066
|
-
export { preFixForJsPlugins as a, cleanUpOxlintConfig as c, transformRuleEntry as d, buildUnsupportedRuleExplanations as f,
|
|
2172
|
+
export { transformEnvAndGlobals as _, preFixForJsPlugins as a, cleanUpOxlintConfig as c, transformRuleEntry as d, buildUnsupportedRuleExplanations as f, detectEnvironmentByGlobals as g, typeAwareRules as h, fixForJsPlugins as i, detectNeededRulesPlugins as l, rules_exports as m, warnSettingsInOverride as n, detectSameOverride as o, nurseryRules as p, processConfigFiles as r, transformIgnorePatterns as s, transformSettings as t, isOffValue as u };
|