@oxlint/migrate 1.25.0 → 1.26.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 +5 -0
- package/dist/bin/oxlint-migrate.mjs +5 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/generated/rules.mjs +3 -1
- package/dist/src/index.mjs +2 -2
- package/dist/src/jsPlugins.d.ts +3 -0
- package/dist/src/jsPlugins.mjs +52 -0
- package/dist/src/js_plugin_fixes.mjs +2 -1
- package/dist/src/plugins_rules.d.ts +1 -1
- package/dist/src/plugins_rules.mjs +13 -11
- package/dist/src/types.d.ts +4 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ When no config file provided, the script searches for the default eslint config
|
|
|
21
21
|
| `--merge` | \* merge eslint configuration with an existing .oxlintrc.json configuration |
|
|
22
22
|
| `--type-aware` | Include type aware rules, which are supported with `oxlint --type-aware` |
|
|
23
23
|
| `--with-nursery` | Include oxlint rules which are currently under development |
|
|
24
|
+
| `--js-plugins` | \*\* Include ESLint plugins via `jsPlugins` key. |
|
|
24
25
|
| `--output-file <file>` | The oxlint configuration file where to eslint v9 rules will be written to, default: `.oxlintrc.json` |
|
|
25
26
|
| `--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. |
|
|
26
27
|
|
|
@@ -28,6 +29,10 @@ When no config file provided, the script searches for the default eslint config
|
|
|
28
29
|
Else we need to disable each rule `plugin/categories` combination, which is not covered by your eslint configuration.
|
|
29
30
|
This behavior can change in the future.
|
|
30
31
|
|
|
32
|
+
\*\* WARNING: Tries to guess the plugin name. Should work with most of the plugin names.
|
|
33
|
+
Not every ESLint API is integrated with `oxlint`.
|
|
34
|
+
Tested ESLint Plugins with `oxlint` can be found in this [Oxc Discussion](https://github.com/oxc-project/oxc/discussions/14862).
|
|
35
|
+
|
|
31
36
|
### User Flow
|
|
32
37
|
|
|
33
38
|
- Upgrade `oxlint` and `@oxlint/migrate` to the same version.
|
|
@@ -36,6 +36,9 @@ program.name("oxlint-migrate").version(packageJson.version).argument("[eslint-co
|
|
|
36
36
|
).option(
|
|
37
37
|
"--type-aware",
|
|
38
38
|
"Includes supported type-aware rules. Needs the same flag in `oxlint` to enable it."
|
|
39
|
+
).option(
|
|
40
|
+
"--js-plugins",
|
|
41
|
+
"Tries to convert unsupported oxlint plugins with `jsPlugins`."
|
|
39
42
|
).action(async (filePath) => {
|
|
40
43
|
const cliOptions = program.opts();
|
|
41
44
|
const oxlintFilePath = path.join(cwd, cliOptions.outputFile);
|
|
@@ -44,7 +47,8 @@ program.name("oxlint-migrate").version(packageJson.version).argument("[eslint-co
|
|
|
44
47
|
reporter,
|
|
45
48
|
merge: !!cliOptions.merge,
|
|
46
49
|
withNursery: !!cliOptions.withNursery,
|
|
47
|
-
typeAware: !!cliOptions.typeAware
|
|
50
|
+
typeAware: !!cliOptions.typeAware,
|
|
51
|
+
jsPlugins: !!cliOptions.jsPlugins
|
|
48
52
|
};
|
|
49
53
|
if (cliOptions.replaceEslintComments) {
|
|
50
54
|
await walkAndReplaceProjectFiles(
|
package/dist/package.json.mjs
CHANGED
|
@@ -35,6 +35,7 @@ const pedanticRules = [
|
|
|
35
35
|
"jsdoc/require-returns-description",
|
|
36
36
|
"jsdoc/require-returns-type",
|
|
37
37
|
"react/checked-requires-onchange-or-readonly",
|
|
38
|
+
"react/jsx-no-target-blank",
|
|
38
39
|
"react/jsx-no-useless-fragment",
|
|
39
40
|
"react/no-unescaped-entities",
|
|
40
41
|
"react-hooks/rules-of-hooks",
|
|
@@ -42,6 +43,7 @@ const pedanticRules = [
|
|
|
42
43
|
"@typescript-eslint/ban-types",
|
|
43
44
|
"@typescript-eslint/no-misused-promises",
|
|
44
45
|
"@typescript-eslint/no-confusing-void-expression",
|
|
46
|
+
"@typescript-eslint/no-deprecated",
|
|
45
47
|
"@typescript-eslint/no-mixed-enums",
|
|
46
48
|
"@typescript-eslint/no-unsafe-argument",
|
|
47
49
|
"@typescript-eslint/no-unsafe-assignment",
|
|
@@ -216,6 +218,7 @@ const styleRules = [
|
|
|
216
218
|
"react/no-set-state",
|
|
217
219
|
"react/prefer-es6-class",
|
|
218
220
|
"react/self-closing-comp",
|
|
221
|
+
"react/state-in-constructor",
|
|
219
222
|
"@typescript-eslint/adjacent-overload-signatures",
|
|
220
223
|
"@typescript-eslint/array-type",
|
|
221
224
|
"@typescript-eslint/ban-tslint-comment",
|
|
@@ -595,7 +598,6 @@ const correctnessRules = [
|
|
|
595
598
|
"react/forward-ref-uses-ref",
|
|
596
599
|
"react/jsx-key",
|
|
597
600
|
"react/jsx-no-duplicate-props",
|
|
598
|
-
"react/jsx-no-target-blank",
|
|
599
601
|
"react/jsx-no-undef",
|
|
600
602
|
"react/jsx-props-no-spread-multi",
|
|
601
603
|
"react/no-children-prop",
|
package/dist/src/index.mjs
CHANGED
|
@@ -59,13 +59,13 @@ const buildConfig = (configs, oxlintConfig, options) => {
|
|
|
59
59
|
transformRuleEntry(config, targetConfig, options);
|
|
60
60
|
transformEnvAndGlobals(config, targetConfig, options);
|
|
61
61
|
if ("files" in targetConfig) {
|
|
62
|
-
detectNeededRulesPlugins(targetConfig
|
|
62
|
+
detectNeededRulesPlugins(targetConfig);
|
|
63
63
|
detectEnvironmentByGlobals(targetConfig);
|
|
64
64
|
cleanUpOxlintConfig(targetConfig);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
oxlintConfig.overrides = overrides;
|
|
68
|
-
detectNeededRulesPlugins(oxlintConfig
|
|
68
|
+
detectNeededRulesPlugins(oxlintConfig);
|
|
69
69
|
detectEnvironmentByGlobals(oxlintConfig);
|
|
70
70
|
cleanUpOxlintConfig(oxlintConfig);
|
|
71
71
|
return oxlintConfig;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { rulesPrefixesForPlugins } from "./constants.mjs";
|
|
2
|
+
const ignorePlugins = /* @__PURE__ */ new Set([
|
|
3
|
+
...Object.keys(rulesPrefixesForPlugins),
|
|
4
|
+
...Object.values(rulesPrefixesForPlugins),
|
|
5
|
+
"local"
|
|
6
|
+
// ToDo: handle local plugin rules
|
|
7
|
+
]);
|
|
8
|
+
const guessEslintPluginName = (pluginName) => {
|
|
9
|
+
if (pluginName.startsWith("@")) {
|
|
10
|
+
const [scope, maybeSub] = pluginName.split("/");
|
|
11
|
+
if (maybeSub) {
|
|
12
|
+
return `${scope}/eslint-plugin-${maybeSub}`;
|
|
13
|
+
}
|
|
14
|
+
return `${scope}/eslint-plugin`;
|
|
15
|
+
}
|
|
16
|
+
return `eslint-plugin-${pluginName}`;
|
|
17
|
+
};
|
|
18
|
+
const extractPluginId = (ruleId) => {
|
|
19
|
+
const firstSlash = ruleId.indexOf("/");
|
|
20
|
+
if (firstSlash === -1) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (ruleId.startsWith("@")) {
|
|
24
|
+
const secondSlash = ruleId.indexOf("/", firstSlash + 1);
|
|
25
|
+
if (secondSlash !== -1) {
|
|
26
|
+
return ruleId.substring(0, secondSlash);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return ruleId.substring(0, firstSlash);
|
|
30
|
+
};
|
|
31
|
+
const enableJsPluginRule = (targetConfig, rule, ruleEntry) => {
|
|
32
|
+
const pluginName = extractPluginId(rule);
|
|
33
|
+
if (pluginName === void 0) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (ignorePlugins.has(pluginName)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (targetConfig.jsPlugins === void 0) {
|
|
40
|
+
targetConfig.jsPlugins = [];
|
|
41
|
+
}
|
|
42
|
+
const eslintPluginName = guessEslintPluginName(pluginName);
|
|
43
|
+
if (!targetConfig.jsPlugins.includes(eslintPluginName)) {
|
|
44
|
+
targetConfig.jsPlugins.push(eslintPluginName);
|
|
45
|
+
}
|
|
46
|
+
targetConfig.rules = targetConfig.rules || {};
|
|
47
|
+
targetConfig.rules[rule] = ruleEntry;
|
|
48
|
+
return true;
|
|
49
|
+
};
|
|
50
|
+
export {
|
|
51
|
+
enableJsPluginRule
|
|
52
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Linter } from 'eslint';
|
|
2
2
|
import { Options, OxlintConfig, OxlintConfigOrOverride } from './types.js';
|
|
3
3
|
export declare const transformRuleEntry: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, options?: Options) => void;
|
|
4
|
-
export declare const detectNeededRulesPlugins: (targetConfig: OxlintConfigOrOverride
|
|
4
|
+
export declare const detectNeededRulesPlugins: (targetConfig: OxlintConfigOrOverride) => void;
|
|
5
5
|
export declare const cleanUpUselessOverridesPlugins: (config: OxlintConfig) => void;
|
|
6
6
|
export declare const cleanUpUselessOverridesRules: (config: OxlintConfig) => void;
|
|
7
7
|
export declare const cleanUpRulesWhichAreCoveredByCategory: (config: OxlintConfigOrOverride) => void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as rules from "./generated/rules.mjs";
|
|
2
2
|
import { nurseryRules } from "./generated/rules.mjs";
|
|
3
3
|
import { typescriptTypeAwareRules, rulesPrefixesForPlugins, typescriptRulesExtendEslintRules } from "./constants.mjs";
|
|
4
|
+
import { enableJsPluginRule } from "./jsPlugins.mjs";
|
|
4
5
|
const allRules = Object.values(rules).flat();
|
|
5
6
|
const isValueInSet = (value, validSet) => validSet.includes(value) || Array.isArray(value) && validSet.includes(value[0]);
|
|
6
7
|
const isActiveValue = (value) => isValueInSet(value, ["error", "warn", 1, 2]);
|
|
@@ -62,13 +63,21 @@ const transformRuleEntry = (eslintConfig, targetConfig, options) => {
|
|
|
62
63
|
targetConfig.rules[rule] = normalizeSeverityValue(config);
|
|
63
64
|
}
|
|
64
65
|
} else {
|
|
65
|
-
if (
|
|
66
|
+
if (options?.jsPlugins) {
|
|
67
|
+
if (isActiveValue(config) && !enableJsPluginRule(
|
|
68
|
+
targetConfig,
|
|
69
|
+
rule,
|
|
70
|
+
normalizeSeverityValue(config)
|
|
71
|
+
)) {
|
|
72
|
+
options?.reporter?.report(`unsupported rule: ${rule}`);
|
|
73
|
+
}
|
|
74
|
+
} else if (isActiveValue(config)) {
|
|
66
75
|
options?.reporter?.report(`unsupported rule: ${rule}`);
|
|
67
76
|
}
|
|
68
77
|
}
|
|
69
78
|
}
|
|
70
79
|
};
|
|
71
|
-
const detectNeededRulesPlugins = (targetConfig
|
|
80
|
+
const detectNeededRulesPlugins = (targetConfig) => {
|
|
72
81
|
if (targetConfig.rules === void 0) {
|
|
73
82
|
return;
|
|
74
83
|
}
|
|
@@ -79,18 +88,11 @@ const detectNeededRulesPlugins = (targetConfig, options) => {
|
|
|
79
88
|
if (!rule.includes("/")) {
|
|
80
89
|
continue;
|
|
81
90
|
}
|
|
82
|
-
let found = false;
|
|
83
91
|
for (const [prefix, plugin] of Object.entries(rulesPrefixesForPlugins)) {
|
|
84
|
-
if (rule.startsWith(`${prefix}/`)) {
|
|
85
|
-
|
|
86
|
-
targetConfig.plugins.push(plugin);
|
|
87
|
-
}
|
|
88
|
-
found = true;
|
|
92
|
+
if (rule.startsWith(`${prefix}/`) && !targetConfig.plugins.includes(plugin)) {
|
|
93
|
+
targetConfig.plugins.push(plugin);
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
|
-
if (!found) {
|
|
92
|
-
options?.reporter?.report(`unsupported plugin for rule: ${rule}`);
|
|
93
|
-
}
|
|
94
96
|
}
|
|
95
97
|
if ("files" in targetConfig && targetConfig.plugins.length === 0) {
|
|
96
98
|
delete targetConfig.plugins;
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Linter } from 'eslint';
|
|
2
2
|
type OxlintConfigPlugins = string[];
|
|
3
|
+
type OxlintConfigJsPlugins = string[];
|
|
3
4
|
type OxlintConfigCategories = Record<string, unknown>;
|
|
4
5
|
type OxlintConfigEnv = Record<string, boolean>;
|
|
5
6
|
type OxlintConfigIgnorePatterns = string[];
|
|
@@ -8,6 +9,7 @@ export type OxlintConfigOverride = {
|
|
|
8
9
|
env?: OxlintConfigEnv;
|
|
9
10
|
globals?: Linter.Globals;
|
|
10
11
|
plugins?: OxlintConfigPlugins;
|
|
12
|
+
jsPlugins?: OxlintConfigJsPlugins;
|
|
11
13
|
categories?: OxlintConfigCategories;
|
|
12
14
|
rules?: Partial<Linter.RulesRecord>;
|
|
13
15
|
};
|
|
@@ -16,6 +18,7 @@ export type OxlintConfig = {
|
|
|
16
18
|
env?: OxlintConfigEnv;
|
|
17
19
|
globals?: Linter.Globals;
|
|
18
20
|
plugins?: OxlintConfigPlugins;
|
|
21
|
+
jsPlugins?: OxlintConfigJsPlugins;
|
|
19
22
|
categories?: OxlintConfigCategories;
|
|
20
23
|
rules?: Partial<Linter.RulesRecord>;
|
|
21
24
|
overrides?: OxlintConfigOverride[];
|
|
@@ -31,5 +34,6 @@ export type Options = {
|
|
|
31
34
|
merge?: boolean;
|
|
32
35
|
withNursery?: boolean;
|
|
33
36
|
typeAware?: boolean;
|
|
37
|
+
jsPlugins?: boolean;
|
|
34
38
|
};
|
|
35
39
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxlint/migrate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "Generates a `.oxlintrc.json` from a existing eslint flat config",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"jiti": "^2.4.2",
|
|
70
70
|
"lint-staged": "^16.1.2",
|
|
71
71
|
"next": "^16.0.0",
|
|
72
|
-
"oxlint": "^1.
|
|
72
|
+
"oxlint": "^1.26.0",
|
|
73
73
|
"oxlint-tsgolint": "^0.2.0",
|
|
74
74
|
"prettier": "^3.6.1",
|
|
75
75
|
"typescript": "^5.8.3",
|
|
@@ -84,11 +84,11 @@
|
|
|
84
84
|
"dependencies": {
|
|
85
85
|
"commander": "^14.0.0",
|
|
86
86
|
"globals": "^16.3.0",
|
|
87
|
-
"oxc-parser": "^0.
|
|
87
|
+
"oxc-parser": "^0.96.0",
|
|
88
88
|
"tinyglobby": "^0.2.14"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
91
|
"jiti": "*"
|
|
92
92
|
},
|
|
93
|
-
"packageManager": "pnpm@10.
|
|
93
|
+
"packageManager": "pnpm@10.20.0"
|
|
94
94
|
}
|