@oxlint/migrate 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-present VoidZero Inc. & Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # oxlint-migrate
2
+
3
+ Generates a `.oxlintrc.json` from a existing eslint v9 configuration
4
+
5
+ 🚧 Still under development
6
+
7
+ ## Usage
8
+
9
+ `npx oxlint-migrate <optional-eslint-v9-config-path>`
10
+
11
+ When no config file provided, we look at the default eslint config filenames in the current directory.
12
+
13
+ ### User Flow
14
+
15
+ - Upgrade `oxlint` and `oxlint-migrate` to the same version.
16
+ - Execute `npx oxlint-migrate`
17
+ - (Optional): Disable supported rules via [eslint-plugin-oxlint](https://github.com/oxc-project/eslint-plugin-oxlint)
18
+
19
+ ## Contributing
20
+
21
+ ### Generate rules
22
+
23
+ Generates the rules from installed oxlint version
24
+
25
+ ```shell
26
+ pnpm generate
27
+ pnpm format
28
+ ```
29
+
30
+ ### Vitest + Integration Test
31
+
32
+ ```shell
33
+ pnpm vitest
34
+ ```
35
+
36
+ ### Manual Testing
37
+
38
+ ```shell
39
+ pnpm manual-test
40
+ ```
@@ -0,0 +1,21 @@
1
+ import { existsSync } from "fs";
2
+ import path from "node:path";
3
+ const FLAT_CONFIG_FILENAMES = [
4
+ "eslint.config.js",
5
+ "eslint.config.mjs",
6
+ "eslint.config.cjs",
7
+ "eslint.config.ts",
8
+ "eslint.config.mts",
9
+ "eslint.config.cts"
10
+ ];
11
+ const getAutodetectedEslintConfigName = (cwd) => {
12
+ for (const filename of FLAT_CONFIG_FILENAMES) {
13
+ const filePath = path.join(cwd, filename);
14
+ if (existsSync(filePath)) {
15
+ return filePath;
16
+ }
17
+ }
18
+ };
19
+ export {
20
+ getAutodetectedEslintConfigName
21
+ };
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import { program } from "commander";
3
+ import { getAutodetectedEslintConfigName } from "./autoDetectConfigFile.mjs";
4
+ import { existsSync, renameSync, writeFileSync } from "fs";
5
+ import main from "../src/index.mjs";
6
+ import path from "path";
7
+ program.name("oxlint-migrate").version("0.0.0").argument("<eslint-config>", "The path to the eslint v9 config file");
8
+ program.parse();
9
+ let [filePath] = program.args;
10
+ let cwd = process.cwd();
11
+ if (filePath === "") {
12
+ filePath = getAutodetectedEslintConfigName(cwd) ?? "";
13
+ } else {
14
+ filePath = path.join(cwd, filePath);
15
+ }
16
+ if (!existsSync(filePath)) {
17
+ program.error(`eslint config file not found: ${filePath}`);
18
+ } else {
19
+ const eslintConfigs = await import(filePath);
20
+ const oxlintConfig = "default" in eslintConfigs ? await main(eslintConfigs.default, console.warn) : await main(eslintConfigs, console.warn);
21
+ const oxlintFilePath = path.join(cwd, ".oxlintrc.json");
22
+ if (existsSync(oxlintFilePath)) {
23
+ renameSync(oxlintFilePath, `${oxlintFilePath}.bak`);
24
+ }
25
+ writeFileSync(oxlintFilePath, JSON.stringify(oxlintConfig, null, 2));
26
+ }
@@ -0,0 +1,2 @@
1
+ import { OxlintConfigOrOverride } from './types.js';
2
+ export declare const cleanUpOxlintConfig: (config: OxlintConfigOrOverride) => void;
@@ -0,0 +1,127 @@
1
+ import { removeGlobalsWithAreCoveredByEnv, ES_VERSIONS } from "./env_globals.mjs";
2
+ const isEqualDeep = (a, b) => {
3
+ if (a === b) {
4
+ return true;
5
+ }
6
+ const bothAreObjects = a && b && typeof a === "object" && typeof b === "object";
7
+ return Boolean(
8
+ bothAreObjects && Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => isEqualDeep(v, b[k]))
9
+ );
10
+ };
11
+ const TS_ESLINT_DEFAULT_OVERRIDE = {
12
+ files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
13
+ rules: {
14
+ "constructor-super": "off",
15
+ "getter-return": "off",
16
+ "no-class-assign": "off",
17
+ "no-const-assign": "off",
18
+ "no-dupe-class-members": "off",
19
+ "no-dupe-keys": "off",
20
+ "no-func-assign": "off",
21
+ "no-import-assign": "off",
22
+ "no-new-native-nonconstructor": "off",
23
+ "no-obj-calls": "off",
24
+ "no-redeclare": "off",
25
+ "no-setter-return": "off",
26
+ "no-this-before-super": "off",
27
+ "no-undef": "off",
28
+ "no-unreachable": "off",
29
+ "no-unsafe-negation": "off",
30
+ "no-var": "error",
31
+ "prefer-rest-params": "error",
32
+ "prefer-spread": "error"
33
+ }
34
+ };
35
+ const cleanUpDefaultTypeScriptOverridesForEslint = (config) => {
36
+ if (config.overrides === void 0) {
37
+ return;
38
+ }
39
+ const indexesToDelete = [];
40
+ for (const index in config.overrides) {
41
+ const override = config.overrides[index];
42
+ if (isEqualDeep(override, TS_ESLINT_DEFAULT_OVERRIDE)) {
43
+ indexesToDelete.push(index);
44
+ }
45
+ }
46
+ indexesToDelete.forEach((index) => delete config.overrides[index]);
47
+ if (Object.keys(config.overrides).length === 0) {
48
+ delete config.overrides;
49
+ }
50
+ };
51
+ const cleanUpUselessOverridesEntries = (config) => {
52
+ if (config.overrides === void 0) {
53
+ return;
54
+ }
55
+ config.overrides = config.overrides.filter(
56
+ (overrides) => Object.keys(overrides).length > 0
57
+ );
58
+ if (config.plugins !== void 0) {
59
+ for (const override of config.overrides) {
60
+ if (override.plugins === void 0) {
61
+ continue;
62
+ }
63
+ override.plugins = override.plugins.filter(
64
+ (overridePlugin) => !config.plugins.includes(overridePlugin)
65
+ );
66
+ if (override.plugins.length === 0) {
67
+ delete override.plugins;
68
+ }
69
+ }
70
+ }
71
+ if (config.env !== void 0) {
72
+ for (const override of config.overrides) {
73
+ if (override.env === void 0) {
74
+ continue;
75
+ }
76
+ for (const [overrideEnv, overrideEnvConfig] of Object.entries(
77
+ override.env
78
+ )) {
79
+ if (overrideEnv in config.env && config.env[overrideEnv] === overrideEnvConfig) {
80
+ delete override.env[overrideEnv];
81
+ }
82
+ }
83
+ if (Object.keys(override.env).length === 0) {
84
+ delete override.env;
85
+ }
86
+ }
87
+ }
88
+ if (config.overrides.length === 0) {
89
+ delete config.overrides;
90
+ }
91
+ };
92
+ const cleanUpOxlintConfig = (config) => {
93
+ removeGlobalsWithAreCoveredByEnv(config);
94
+ if (config.globals !== void 0 && Object.keys(config.globals).length === 0) {
95
+ delete config.globals;
96
+ }
97
+ if (config.env !== void 0) {
98
+ delete config.env.es3;
99
+ delete config.env.es5;
100
+ delete config.env.es2015;
101
+ let detected = false;
102
+ for (const esVersion of ES_VERSIONS.reverse()) {
103
+ if (detected) {
104
+ delete config.env[`es${esVersion}`];
105
+ } else if (config.env[`es${esVersion}`] === true) {
106
+ detected = true;
107
+ }
108
+ }
109
+ }
110
+ if (config.rules !== void 0 && Object.keys(config.rules).length === 0) {
111
+ delete config.rules;
112
+ }
113
+ if ("files" in config) {
114
+ if (config.plugins !== void 0 && Object.keys(config.plugins).length === 0) {
115
+ delete config.plugins;
116
+ }
117
+ if (Object.keys(config).length === 1) {
118
+ delete config.files;
119
+ }
120
+ } else {
121
+ cleanUpDefaultTypeScriptOverridesForEslint(config);
122
+ cleanUpUselessOverridesEntries(config);
123
+ }
124
+ };
125
+ export {
126
+ cleanUpOxlintConfig
127
+ };
@@ -0,0 +1 @@
1
+ export declare const rulesPrefixesForPlugins: Record<string, string>;
@@ -0,0 +1,17 @@
1
+ const rulesPrefixesForPlugins = {
2
+ import: "import",
3
+ jest: "jest",
4
+ jsdoc: "jsdoc",
5
+ "jsx-a11y": "jsx-a11y",
6
+ "@next/next": "nextjs",
7
+ node: "node",
8
+ promise: "promise",
9
+ react: "react",
10
+ "react-perf": "react",
11
+ "@typescript-eslint": "typescript",
12
+ unicorn: "unicorn",
13
+ vitest: "vitest"
14
+ };
15
+ export {
16
+ rulesPrefixesForPlugins
17
+ };
@@ -0,0 +1,6 @@
1
+ import { OxlintConfig, OxlintConfigOrOverride, Reporter } from './types.js';
2
+ import { Linter } from 'eslint';
3
+ export declare const ES_VERSIONS: number[];
4
+ export declare const removeGlobalsWithAreCoveredByEnv: (config: OxlintConfig) => void;
5
+ export declare const detectEnvironmentByGlobals: (config: OxlintConfig) => void;
6
+ export declare const transformEnvAndGlobals: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, reporter?: Reporter) => void;
@@ -0,0 +1,125 @@
1
+ import globals from "globals";
2
+ const ES_VERSIONS = [
3
+ 6,
4
+ 2016,
5
+ 2017,
6
+ 2018,
7
+ 2019,
8
+ 2020,
9
+ 2021,
10
+ 2022,
11
+ 2023,
12
+ 2024,
13
+ 2025
14
+ ];
15
+ const OTHER_SUPPORTED_ENVS = [
16
+ "browser",
17
+ "node",
18
+ "shared-node-browser",
19
+ "worker",
20
+ "serviceworker",
21
+ "commonjs",
22
+ "amd",
23
+ "mocha",
24
+ "jasmine",
25
+ "jest",
26
+ "phantomjs",
27
+ "jquery",
28
+ "qunit",
29
+ "prototypejs",
30
+ "shelljs",
31
+ "meteor",
32
+ "mongo",
33
+ "protractor",
34
+ "applescript",
35
+ "nashorn",
36
+ "atomtest",
37
+ "embertest",
38
+ "webextensions",
39
+ "greasemonkey"
40
+ ];
41
+ const SUPPORTED_ESLINT_PARSERS = ["typescript-eslint/parser"];
42
+ const normalizeGlobValue = (value) => {
43
+ if (value === "readable" || value === "readonly" || value === false) {
44
+ return false;
45
+ }
46
+ if (value === "off") {
47
+ return void 0;
48
+ }
49
+ return true;
50
+ };
51
+ const removeGlobalsWithAreCoveredByEnv = (config) => {
52
+ if (config.globals === void 0 || config.env === void 0) {
53
+ return;
54
+ }
55
+ for (const [env, entries] of Object.entries(globals)) {
56
+ if (config.env[env] === true) {
57
+ for (const entry of Object.keys(entries)) {
58
+ if (normalizeGlobValue(config.globals[entry]) === entries[entry]) {
59
+ delete config.globals[entry];
60
+ }
61
+ }
62
+ }
63
+ }
64
+ };
65
+ const detectEnvironmentByGlobals = (config) => {
66
+ if (config.globals === void 0) {
67
+ return;
68
+ }
69
+ for (const [env, entries] of Object.entries(globals)) {
70
+ if (!env.startsWith("es") && !OTHER_SUPPORTED_ENVS.includes(env)) {
71
+ continue;
72
+ }
73
+ let search = Object.keys(entries);
74
+ let matches = search.filter(
75
+ (entry) => (
76
+ // @ts-ignore -- we already checked for undefined
77
+ entry in config.globals && // @ts-ignore -- filtering makes the key to any
78
+ normalizeGlobValue(config.globals[entry]) === entries[entry]
79
+ )
80
+ );
81
+ if (search.length === matches.length) {
82
+ if (config.env === void 0) {
83
+ config.env = {};
84
+ }
85
+ config.env[env] = true;
86
+ }
87
+ }
88
+ };
89
+ const transformEnvAndGlobals = (eslintConfig, targetConfig, reporter) => {
90
+ if (eslintConfig.languageOptions?.parser !== void 0 && !SUPPORTED_ESLINT_PARSERS.includes(
91
+ eslintConfig.languageOptions.parser.meta?.name
92
+ )) {
93
+ reporter !== void 0 && reporter(
94
+ "special parser detected: " + eslintConfig.languageOptions.parser.meta?.name
95
+ );
96
+ }
97
+ if (eslintConfig.languageOptions?.globals !== void 0) {
98
+ if (targetConfig.globals === void 0) {
99
+ targetConfig.globals = {};
100
+ }
101
+ Object.assign(targetConfig.globals, eslintConfig.languageOptions.globals);
102
+ }
103
+ if (eslintConfig.languageOptions?.ecmaVersion !== void 0) {
104
+ if (targetConfig.globals === void 0) {
105
+ targetConfig.globals = {};
106
+ }
107
+ if (eslintConfig.languageOptions?.ecmaVersion === "latest") {
108
+ if (targetConfig.env === void 0) {
109
+ targetConfig.env = {};
110
+ }
111
+ targetConfig.env[`es${ES_VERSIONS[ES_VERSIONS.length - 1]}`] = true;
112
+ } else if (ES_VERSIONS.includes(eslintConfig.languageOptions?.ecmaVersion)) {
113
+ if (targetConfig.env === void 0) {
114
+ targetConfig.env = {};
115
+ }
116
+ targetConfig.env[`es${eslintConfig.languageOptions?.ecmaVersion}`] = true;
117
+ }
118
+ }
119
+ };
120
+ export {
121
+ ES_VERSIONS,
122
+ detectEnvironmentByGlobals,
123
+ removeGlobalsWithAreCoveredByEnv,
124
+ transformEnvAndGlobals
125
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ declare const rules: string[];
2
+ export default rules;
@@ -0,0 +1,529 @@
1
+ const rules = [
2
+ "array-callback-return",
3
+ "constructor-super",
4
+ "default-case",
5
+ "default-case-last",
6
+ "default-param-last",
7
+ "eqeqeq",
8
+ "for-direction",
9
+ "func-names",
10
+ "getter-return",
11
+ "guard-for-in",
12
+ "max-classes-per-file",
13
+ "max-lines",
14
+ "max-params",
15
+ "new-cap",
16
+ "no-useless-call",
17
+ "no-extra-label",
18
+ "no-multi-assign",
19
+ "no-nested-ternary",
20
+ "no-labels",
21
+ "no-lone-blocks",
22
+ "no-restricted-imports",
23
+ "no-object-constructor",
24
+ "no-duplicate-imports",
25
+ "no-alert",
26
+ "no-array-constructor",
27
+ "no-async-promise-executor",
28
+ "no-await-in-loop",
29
+ "no-bitwise",
30
+ "no-caller",
31
+ "no-case-declarations",
32
+ "no-class-assign",
33
+ "no-compare-neg-zero",
34
+ "no-cond-assign",
35
+ "no-console",
36
+ "no-const-assign",
37
+ "no-constant-binary-expression",
38
+ "no-constant-condition",
39
+ "no-constructor-return",
40
+ "no-continue",
41
+ "no-control-regex",
42
+ "no-debugger",
43
+ "no-delete-var",
44
+ "no-div-regex",
45
+ "no-dupe-class-members",
46
+ "no-dupe-else-if",
47
+ "no-dupe-keys",
48
+ "no-duplicate-case",
49
+ "no-else-return",
50
+ "no-empty-character-class",
51
+ "no-empty-function",
52
+ "no-empty-pattern",
53
+ "no-empty-static-block",
54
+ "no-empty",
55
+ "no-eq-null",
56
+ "no-eval",
57
+ "no-ex-assign",
58
+ "no-extend-native",
59
+ "no-extra-boolean-cast",
60
+ "no-fallthrough",
61
+ "no-func-assign",
62
+ "no-global-assign",
63
+ "no-import-assign",
64
+ "no-inner-declarations",
65
+ "no-invalid-regexp",
66
+ "no-irregular-whitespace",
67
+ "no-iterator",
68
+ "no-label-var",
69
+ "no-loss-of-precision",
70
+ "no-magic-numbers",
71
+ "no-negated-condition",
72
+ "no-multi-str",
73
+ "no-new-func",
74
+ "no-new-native-nonconstructor",
75
+ "no-new-wrappers",
76
+ "no-new",
77
+ "no-nonoctal-decimal-escape",
78
+ "no-obj-calls",
79
+ "no-plusplus",
80
+ "no-proto",
81
+ "no-prototype-builtins",
82
+ "no-redeclare",
83
+ "no-regex-spaces",
84
+ "no-restricted-globals",
85
+ "no-return-assign",
86
+ "no-script-url",
87
+ "no-self-assign",
88
+ "no-self-compare",
89
+ "no-setter-return",
90
+ "no-shadow-restricted-names",
91
+ "no-sparse-arrays",
92
+ "no-template-curly-in-string",
93
+ "no-ternary",
94
+ "no-this-before-super",
95
+ "no-throw-literal",
96
+ "no-undef",
97
+ "no-undefined",
98
+ "no-unexpected-multiline",
99
+ "no-unreachable",
100
+ "no-unsafe-finally",
101
+ "no-unsafe-negation",
102
+ "no-unsafe-optional-chaining",
103
+ "no-unused-expressions",
104
+ "no-unused-labels",
105
+ "no-unused-private-class-members",
106
+ "no-unused-vars",
107
+ "no-useless-catch",
108
+ "no-useless-concat",
109
+ "no-useless-constructor",
110
+ "no-useless-escape",
111
+ "no-useless-rename",
112
+ "no-var",
113
+ "no-void",
114
+ "no-with",
115
+ "prefer-promise-reject-errors",
116
+ "prefer-exponentiation-operator",
117
+ "prefer-numeric-literals",
118
+ "prefer-object-has-own",
119
+ "prefer-object-spread",
120
+ "prefer-rest-params",
121
+ "prefer-spread",
122
+ "radix",
123
+ "require-await",
124
+ "require-yield",
125
+ "sort-imports",
126
+ "sort-keys",
127
+ "sort-vars",
128
+ "symbol-description",
129
+ "unicode-bom",
130
+ "use-isnan",
131
+ "valid-typeof",
132
+ "vars-on-top",
133
+ "yoda",
134
+ "import/default",
135
+ "import/export",
136
+ "import/first",
137
+ "import/no-named-default",
138
+ "import/no-namespace",
139
+ "import/max-dependencies",
140
+ "import/named",
141
+ "import/namespace",
142
+ "import/no-amd",
143
+ "import/no-commonjs",
144
+ "import/no-cycle",
145
+ "import/no-default-export",
146
+ "import/no-duplicates",
147
+ "import/no-dynamic-require",
148
+ "import/no-named-as-default",
149
+ "import/no-named-as-default-member",
150
+ "import/no-self-import",
151
+ "import/no-webpack-loader-syntax",
152
+ "import/unambiguous",
153
+ "jest/consistent-test-it",
154
+ "jest/expect-expect",
155
+ "jest/max-expects",
156
+ "jest/max-nested-describe",
157
+ "jest/no-alias-methods",
158
+ "jest/no-commented-out-tests",
159
+ "jest/no-conditional-expect",
160
+ "jest/no-conditional-in-test",
161
+ "jest/no-confusing-set-timeout",
162
+ "jest/no-deprecated-functions",
163
+ "jest/no-disabled-tests",
164
+ "jest/no-done-callback",
165
+ "jest/no-duplicate-hooks",
166
+ "jest/no-export",
167
+ "jest/no-focused-tests",
168
+ "jest/no-hooks",
169
+ "jest/no-identical-title",
170
+ "jest/no-interpolation-in-snapshots",
171
+ "jest/no-jasmine-globals",
172
+ "jest/no-large-snapshots",
173
+ "jest/no-mocks-import",
174
+ "jest/no-restricted-jest-methods",
175
+ "jest/no-restricted-matchers",
176
+ "jest/no-standalone-expect",
177
+ "jest/no-test-prefixes",
178
+ "jest/no-test-return-statement",
179
+ "jest/no-untyped-mock-factory",
180
+ "jest/prefer-each",
181
+ "jest/prefer-called-with",
182
+ "jest/prefer-comparison-matcher",
183
+ "jest/prefer-equality-matcher",
184
+ "jest/prefer-expect-resolves",
185
+ "jest/prefer-hooks-in-order",
186
+ "jest/prefer-hooks-on-top",
187
+ "jest/prefer-jest-mocked",
188
+ "jest/prefer-lowercase-title",
189
+ "jest/prefer-mock-promise-shorthand",
190
+ "jest/prefer-spy-on",
191
+ "jest/prefer-strict-equal",
192
+ "jest/prefer-to-be",
193
+ "jest/prefer-to-contain",
194
+ "jest/prefer-to-have-length",
195
+ "jest/prefer-todo",
196
+ "jest/require-hook",
197
+ "jest/require-to-throw-message",
198
+ "jest/require-top-level-describe",
199
+ "jest/valid-describe-callback",
200
+ "jest/valid-expect",
201
+ "jest/valid-title",
202
+ "jsdoc/check-access",
203
+ "jsdoc/check-property-names",
204
+ "jsdoc/check-tag-names",
205
+ "jsdoc/empty-tags",
206
+ "jsdoc/implements-on-classes",
207
+ "jsdoc/no-defaults",
208
+ "jsdoc/require-param",
209
+ "jsdoc/require-param-description",
210
+ "jsdoc/require-param-name",
211
+ "jsdoc/require-param-type",
212
+ "jsdoc/require-property",
213
+ "jsdoc/require-property-description",
214
+ "jsdoc/require-property-name",
215
+ "jsdoc/require-property-type",
216
+ "jsdoc/require-returns",
217
+ "jsdoc/require-returns-description",
218
+ "jsdoc/require-returns-type",
219
+ "jsdoc/require-yields",
220
+ "jsx-a11y/alt-text",
221
+ "jsx-a11y/anchor-has-content",
222
+ "jsx-a11y/anchor-is-valid",
223
+ "jsx-a11y/aria-activedescendant-has-tabindex",
224
+ "jsx-a11y/aria-props",
225
+ "jsx-a11y/aria-role",
226
+ "jsx-a11y/aria-unsupported-elements",
227
+ "jsx-a11y/autocomplete-valid",
228
+ "jsx-a11y/click-events-have-key-events",
229
+ "jsx-a11y/heading-has-content",
230
+ "jsx-a11y/html-has-lang",
231
+ "jsx-a11y/iframe-has-title",
232
+ "jsx-a11y/img-redundant-alt",
233
+ "jsx-a11y/label-has-associated-control",
234
+ "jsx-a11y/lang",
235
+ "jsx-a11y/media-has-caption",
236
+ "jsx-a11y/mouse-events-have-key-events",
237
+ "jsx-a11y/no-noninteractive-tabindex",
238
+ "jsx-a11y/no-access-key",
239
+ "jsx-a11y/no-aria-hidden-on-focusable",
240
+ "jsx-a11y/no-autofocus",
241
+ "jsx-a11y/no-distracting-elements",
242
+ "jsx-a11y/no-redundant-roles",
243
+ "jsx-a11y/prefer-tag-over-role",
244
+ "jsx-a11y/role-has-required-aria-props",
245
+ "jsx-a11y/role-supports-aria-props",
246
+ "jsx-a11y/scope",
247
+ "jsx-a11y/tabindex-no-positive",
248
+ "jsx-a11y/anchor-ambiguous-text",
249
+ "@next/next/google-font-display",
250
+ "@next/next/google-font-preconnect",
251
+ "@next/next/inline-script-id",
252
+ "@next/next/next-script-for-ga",
253
+ "@next/next/no-assign-module-variable",
254
+ "@next/next/no-async-client-component",
255
+ "@next/next/no-before-interactive-script-outside-document",
256
+ "@next/next/no-css-tags",
257
+ "@next/next/no-document-import-in-page",
258
+ "@next/next/no-duplicate-head",
259
+ "@next/next/no-head-element",
260
+ "@next/next/no-head-import-in-document",
261
+ "@next/next/no-img-element",
262
+ "@next/next/no-page-custom-font",
263
+ "@next/next/no-script-component-in-head",
264
+ "@next/next/no-styled-jsx-in-document",
265
+ "@next/next/no-sync-scripts",
266
+ "@next/next/no-title-in-document-head",
267
+ "@next/next/no-typos",
268
+ "@next/next/no-unwanted-polyfillio",
269
+ "node/no-exports-assign",
270
+ "node/no-new-require",
271
+ "oxc/approx-constant",
272
+ "oxc/bad-array-method-on-arguments",
273
+ "oxc/bad-bitwise-operator",
274
+ "oxc/bad-char-at-comparison",
275
+ "oxc/bad-comparison-sequence",
276
+ "oxc/bad-min-max-func",
277
+ "oxc/bad-object-literal-comparison",
278
+ "oxc/bad-replace-all-arg",
279
+ "oxc/const-comparisons",
280
+ "oxc/double-comparisons",
281
+ "oxc/erasing-op",
282
+ "oxc/misrefactored-assign-op",
283
+ "oxc/missing-throw",
284
+ "oxc/no-accumulating-spread",
285
+ "oxc/no-async-await",
286
+ "oxc/no-async-endpoint-handlers",
287
+ "oxc/no-barrel-file",
288
+ "oxc/no-const-enum",
289
+ "oxc/no-map-spread",
290
+ "oxc/no-optional-chaining",
291
+ "oxc/no-rest-spread-properties",
292
+ "oxc/number-arg-out-of-range",
293
+ "oxc/only-used-in-recursion",
294
+ "oxc/uninvoked-array-callback",
295
+ "promise/avoid-new",
296
+ "promise/catch-or-return",
297
+ "promise/no-promise-in-callback",
298
+ "promise/no-callback-in-promise",
299
+ "promise/no-new-statics",
300
+ "promise/no-return-in-finally",
301
+ "promise/param-names",
302
+ "promise/prefer-await-to-callbacks",
303
+ "promise/prefer-await-to-then",
304
+ "promise/spec-only",
305
+ "promise/valid-params",
306
+ "react/button-has-type",
307
+ "react/checked-requires-onchange-or-readonly",
308
+ "react-hooks/exhaustive-deps",
309
+ "react/iframe-missing-sandbox",
310
+ "react/jsx-boolean-value",
311
+ "react/jsx-curly-brace-presence",
312
+ "react/jsx-key",
313
+ "react/jsx-no-comment-textnodes",
314
+ "react/jsx-no-duplicate-props",
315
+ "react/jsx-no-script-url",
316
+ "react/jsx-no-target-blank",
317
+ "react/jsx-no-undef",
318
+ "react/jsx-no-useless-fragment",
319
+ "react/jsx-props-no-spread-multi",
320
+ "react/no-array-index-key",
321
+ "react/no-children-prop",
322
+ "react/no-danger-with-children",
323
+ "react/no-danger",
324
+ "react/no-direct-mutation-state",
325
+ "react/no-find-dom-node",
326
+ "react/no-is-mounted",
327
+ "react/no-render-return-value",
328
+ "react/no-set-state",
329
+ "react/no-string-refs",
330
+ "react/no-unescaped-entities",
331
+ "react/no-unknown-property",
332
+ "react/prefer-es6-class",
333
+ "react/react-in-jsx-scope",
334
+ "react/require-render-return",
335
+ "react-hooks/rules-of-hooks",
336
+ "react/self-closing-comp",
337
+ "react/style-prop-object",
338
+ "react/void-dom-elements-no-children",
339
+ "react-perf/jsx-no-jsx-as-prop",
340
+ "react-perf/jsx-no-new-array-as-prop",
341
+ "react-perf/jsx-no-new-function-as-prop",
342
+ "react-perf/jsx-no-new-object-as-prop",
343
+ "@typescript-eslint/adjacent-overload-signatures",
344
+ "@typescript-eslint/array-type",
345
+ "@typescript-eslint/ban-ts-comment",
346
+ "@typescript-eslint/ban-tslint-comment",
347
+ "@typescript-eslint/ban-types",
348
+ "@typescript-eslint/consistent-generic-constructors",
349
+ "@typescript-eslint/consistent-indexed-object-style",
350
+ "@typescript-eslint/consistent-type-definitions",
351
+ "@typescript-eslint/consistent-type-imports",
352
+ "@typescript-eslint/explicit-function-return-type",
353
+ "@typescript-eslint/no-inferrable-types",
354
+ "@typescript-eslint/no-confusing-non-null-assertion",
355
+ "@typescript-eslint/no-duplicate-enum-values",
356
+ "@typescript-eslint/no-dynamic-delete",
357
+ "@typescript-eslint/no-empty-interface",
358
+ "@typescript-eslint/no-empty-object-type",
359
+ "@typescript-eslint/no-explicit-any",
360
+ "@typescript-eslint/no-extra-non-null-assertion",
361
+ "@typescript-eslint/no-extraneous-class",
362
+ "@typescript-eslint/no-import-type-side-effects",
363
+ "@typescript-eslint/no-misused-new",
364
+ "@typescript-eslint/no-namespace",
365
+ "@typescript-eslint/no-non-null-asserted-nullish-coalescing",
366
+ "@typescript-eslint/no-non-null-asserted-optional-chain",
367
+ "@typescript-eslint/no-non-null-assertion",
368
+ "@typescript-eslint/no-require-imports",
369
+ "@typescript-eslint/no-this-alias",
370
+ "@typescript-eslint/no-unnecessary-type-constraint",
371
+ "@typescript-eslint/no-unsafe-declaration-merging",
372
+ "@typescript-eslint/no-unsafe-function-type",
373
+ "@typescript-eslint/no-useless-empty-export",
374
+ "@typescript-eslint/no-var-requires",
375
+ "@typescript-eslint/no-wrapper-object-types",
376
+ "@typescript-eslint/prefer-as-const",
377
+ "@typescript-eslint/prefer-enum-initializers",
378
+ "@typescript-eslint/prefer-for-of",
379
+ "@typescript-eslint/prefer-function-type",
380
+ "@typescript-eslint/prefer-literal-enum-member",
381
+ "@typescript-eslint/prefer-namespace-keyword",
382
+ "@typescript-eslint/prefer-ts-expect-error",
383
+ "@typescript-eslint/triple-slash-reference",
384
+ "unicorn/catch-error-name",
385
+ "unicorn/consistent-empty-array-spread",
386
+ "unicorn/consistent-existence-index-check",
387
+ "unicorn/consistent-function-scoping",
388
+ "unicorn/empty-brace-spaces",
389
+ "unicorn/error-message",
390
+ "unicorn/escape-case",
391
+ "unicorn/explicit-length-check",
392
+ "unicorn/filename-case",
393
+ "unicorn/new-for-builtins",
394
+ "unicorn/no-abusive-eslint-disable",
395
+ "unicorn/no-anonymous-default-export",
396
+ "unicorn/no-array-for-each",
397
+ "unicorn/no-array-reduce",
398
+ "unicorn/no-await-expression-member",
399
+ "unicorn/no-await-in-promise-methods",
400
+ "unicorn/no-console-spaces",
401
+ "unicorn/no-document-cookie",
402
+ "unicorn/no-empty-file",
403
+ "unicorn/no-hex-escape",
404
+ "unicorn/no-instanceof-array",
405
+ "unicorn/no-invalid-remove-event-listener",
406
+ "unicorn/no-length-as-slice-end",
407
+ "unicorn/no-lonely-if",
408
+ "unicorn/no-magic-array-flat-depth",
409
+ "unicorn/no-negation-in-equality-check",
410
+ "unicorn/no-nested-ternary",
411
+ "unicorn/no-new-array",
412
+ "unicorn/no-new-buffer",
413
+ "unicorn/no-null",
414
+ "unicorn/no-object-as-default-parameter",
415
+ "unicorn/no-process-exit",
416
+ "unicorn/no-single-promise-in-promise-methods",
417
+ "unicorn/no-static-only-class",
418
+ "unicorn/no-thenable",
419
+ "unicorn/no-this-assignment",
420
+ "unicorn/no-typeof-undefined",
421
+ "unicorn/no-unnecessary-await",
422
+ "unicorn/no-unreadable-array-destructuring",
423
+ "unicorn/no-unreadable-iife",
424
+ "unicorn/no-useless-fallback-in-spread",
425
+ "unicorn/no-useless-length-check",
426
+ "unicorn/no-useless-promise-resolve-reject",
427
+ "unicorn/no-useless-spread",
428
+ "unicorn/no-useless-switch-case",
429
+ "unicorn/no-useless-undefined",
430
+ "unicorn/no-zero-fractions",
431
+ "unicorn/number-literal-case",
432
+ "unicorn/numeric-separators-style",
433
+ "unicorn/prefer-spread",
434
+ "unicorn/prefer-add-event-listener",
435
+ "unicorn/prefer-array-flat",
436
+ "unicorn/prefer-array-flat-map",
437
+ "unicorn/prefer-array-some",
438
+ "unicorn/prefer-blob-reading-methods",
439
+ "unicorn/prefer-code-point",
440
+ "unicorn/prefer-date-now",
441
+ "unicorn/prefer-dom-node-append",
442
+ "unicorn/prefer-dom-node-dataset",
443
+ "unicorn/prefer-dom-node-remove",
444
+ "unicorn/prefer-dom-node-text-content",
445
+ "unicorn/prefer-event-target",
446
+ "unicorn/prefer-includes",
447
+ "unicorn/prefer-logical-operator-over-ternary",
448
+ "unicorn/prefer-math-min-max",
449
+ "unicorn/prefer-math-trunc",
450
+ "unicorn/prefer-modern-dom-apis",
451
+ "unicorn/prefer-modern-math-apis",
452
+ "unicorn/prefer-native-coercion-functions",
453
+ "unicorn/prefer-negative-index",
454
+ "unicorn/prefer-node-protocol",
455
+ "unicorn/prefer-number-properties",
456
+ "unicorn/prefer-optional-catch-binding",
457
+ "unicorn/prefer-prototype-methods",
458
+ "unicorn/prefer-query-selector",
459
+ "unicorn/prefer-reflect-apply",
460
+ "unicorn/prefer-regexp-test",
461
+ "unicorn/prefer-set-has",
462
+ "unicorn/prefer-set-size",
463
+ "unicorn/prefer-string-raw",
464
+ "unicorn/prefer-string-replace-all",
465
+ "unicorn/prefer-string-slice",
466
+ "unicorn/prefer-string-starts-ends-with",
467
+ "unicorn/prefer-string-trim-start-end",
468
+ "unicorn/prefer-structured-clone",
469
+ "unicorn/prefer-type-error",
470
+ "unicorn/require-array-join-separator",
471
+ "unicorn/require-number-to-fixed-digits-argument",
472
+ "unicorn/switch-case-braces",
473
+ "unicorn/text-encoding-identifier-case",
474
+ "unicorn/throw-new-error",
475
+ "vitest/no-conditional-tests",
476
+ "vitest/no-import-node-test",
477
+ "vitest/prefer-to-be-falsy",
478
+ "vitest/prefer-to-be-object",
479
+ "vitest/prefer-to-be-truthy",
480
+ "vitest/require-local-test-context-for-concurrent-snapshots",
481
+ "@typescript-eslint/default-param-last",
482
+ "@typescript-eslint/max-params",
483
+ "@typescript-eslint/no-restricted-imports",
484
+ "@typescript-eslint/no-array-constructor",
485
+ "@typescript-eslint/no-dupe-class-members",
486
+ "@typescript-eslint/no-empty-function",
487
+ "@typescript-eslint/no-loss-of-precision",
488
+ "@typescript-eslint/no-magic-numbers",
489
+ "unicorn/no-negated-condition",
490
+ "@typescript-eslint/no-redeclare",
491
+ "@typescript-eslint/no-unused-expressions",
492
+ "@typescript-eslint/no-unused-vars",
493
+ "@typescript-eslint/no-useless-constructor",
494
+ "vitest/consistent-test-it",
495
+ "vitest/expect-expect",
496
+ "vitest/max-expects",
497
+ "vitest/max-nested-describe",
498
+ "vitest/no-alias-methods",
499
+ "vitest/no-commented-out-tests",
500
+ "vitest/no-conditional-expect",
501
+ "vitest/no-conditional-in-test",
502
+ "vitest/no-disabled-tests",
503
+ "vitest/no-duplicate-hooks",
504
+ "vitest/no-focused-tests",
505
+ "vitest/no-hooks",
506
+ "vitest/no-identical-title",
507
+ "vitest/no-interpolation-in-snapshots",
508
+ "vitest/no-restricted-jest-methods",
509
+ "vitest/no-restricted-matchers",
510
+ "vitest/no-test-prefixes",
511
+ "vitest/no-test-return-statement",
512
+ "vitest/prefer-each",
513
+ "vitest/prefer-comparison-matcher",
514
+ "vitest/prefer-equality-matcher",
515
+ "vitest/prefer-expect-resolves",
516
+ "vitest/prefer-hooks-in-order",
517
+ "vitest/prefer-hooks-on-top",
518
+ "vitest/prefer-mock-promise-shorthand",
519
+ "vitest/prefer-strict-equal",
520
+ "vitest/prefer-to-have-length",
521
+ "vitest/prefer-todo",
522
+ "vitest/require-to-throw-message",
523
+ "vitest/require-top-level-describe",
524
+ "vitest/valid-describe-callback",
525
+ "vitest/valid-expect"
526
+ ];
527
+ export {
528
+ rules as default
529
+ };
@@ -0,0 +1,3 @@
1
+ import { Linter } from 'eslint';
2
+ import { OxlintConfigOrOverride, Reporter } from './types.js';
3
+ export declare const transformIgnorePatterns: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, reporter: Reporter) => void;
@@ -0,0 +1,19 @@
1
+ const transformIgnorePatterns = (eslintConfig, targetConfig, reporter) => {
2
+ if (eslintConfig.ignores === void 0) {
3
+ return;
4
+ }
5
+ if ("files" in targetConfig) {
6
+ reporter !== void 0 && reporter("ignore list inside overrides is not supported");
7
+ return;
8
+ }
9
+ if (targetConfig.ignorePatterns === void 0) {
10
+ targetConfig.ignorePatterns = [];
11
+ }
12
+ targetConfig.ignorePatterns.push(...eslintConfig.ignores);
13
+ eslintConfig.ignores.filter((ignore) => ignore.startsWith("!")).forEach(
14
+ (ignore) => reporter !== void 0 && reporter(`ignore allow list is currently not supported: ${ignore}`)
15
+ );
16
+ };
17
+ export {
18
+ transformIgnorePatterns
19
+ };
@@ -0,0 +1,4 @@
1
+ import { Linter } from 'eslint';
2
+ import { OxlintConfig, Reporter } from './types.js';
3
+ declare const main: (configs: Linter.Config | Linter.Config[] | Promise<Linter.Config> | Promise<Linter.Config[]>, reporter?: Reporter) => Promise<OxlintConfig>;
4
+ export default main;
@@ -0,0 +1,54 @@
1
+ import { transformEnvAndGlobals, detectEnvironmentByGlobals } from "./env_globals.mjs";
2
+ import { cleanUpOxlintConfig } from "./cleanup.mjs";
3
+ import { transformIgnorePatterns } from "./ignorePatterns.mjs";
4
+ import { transformRuleEntry, detectNeededRulesPlugins } from "./plugins_rules.mjs";
5
+ const buildConfig = (configs, reporter) => {
6
+ const oxlintConfig = {
7
+ // disable all plugins and check later
8
+ plugins: [],
9
+ env: {
10
+ builtin: true
11
+ },
12
+ categories: {
13
+ // default category
14
+ correctness: "off"
15
+ }
16
+ };
17
+ const overrides = [];
18
+ for (const config of configs) {
19
+ if (config.name?.startsWith("oxlint/")) {
20
+ continue;
21
+ }
22
+ let targetConfig;
23
+ if (config.files === void 0) {
24
+ targetConfig = oxlintConfig;
25
+ } else {
26
+ targetConfig = {
27
+ files: Array.isArray(config.files) ? config.files : [config.files]
28
+ };
29
+ overrides.push(targetConfig);
30
+ }
31
+ if (config.plugins !== void 0) ;
32
+ if (config.settings !== void 0) ;
33
+ transformIgnorePatterns(config, targetConfig, reporter);
34
+ transformRuleEntry(config, targetConfig, reporter);
35
+ transformEnvAndGlobals(config, targetConfig, reporter);
36
+ if ("files" in targetConfig) {
37
+ detectNeededRulesPlugins(targetConfig, reporter);
38
+ detectEnvironmentByGlobals(targetConfig);
39
+ cleanUpOxlintConfig(targetConfig);
40
+ }
41
+ }
42
+ oxlintConfig.overrides = overrides;
43
+ detectNeededRulesPlugins(oxlintConfig, reporter);
44
+ detectEnvironmentByGlobals(oxlintConfig);
45
+ cleanUpOxlintConfig(oxlintConfig);
46
+ return oxlintConfig;
47
+ };
48
+ const main = async (configs, reporter = void 0) => {
49
+ const resolved = await Promise.resolve(configs);
50
+ return Array.isArray(resolved) ? buildConfig(resolved, reporter) : buildConfig([resolved], reporter);
51
+ };
52
+ export {
53
+ main as default
54
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import { Linter } from 'eslint';
2
+ import { OxlintConfigOrOverride, Reporter } from './types.js';
3
+ export declare const transformRuleEntry: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, reporter: Reporter) => void;
4
+ export declare const detectNeededRulesPlugins: (targetConfig: OxlintConfigOrOverride, reporter: Reporter) => void;
@@ -0,0 +1,48 @@
1
+ import rules from "./generated/rules.mjs";
2
+ import { rulesPrefixesForPlugins } from "./constants.mjs";
3
+ const isValueInSet = (value, validSet) => validSet.includes(value) || Array.isArray(value) && validSet.includes(value[0]);
4
+ const isActiveValue = (value) => isValueInSet(value, ["error", "warn", 1, 2]);
5
+ const transformRuleEntry = (eslintConfig, targetConfig, reporter) => {
6
+ if (eslintConfig.rules === void 0) {
7
+ return;
8
+ }
9
+ if (targetConfig.rules === void 0) {
10
+ targetConfig.rules = {};
11
+ }
12
+ for (const [rule, config] of Object.entries(eslintConfig.rules)) {
13
+ if (rules.includes(rule)) {
14
+ targetConfig.rules[rule] = config;
15
+ } else {
16
+ if (isActiveValue(config)) {
17
+ reporter !== void 0 && reporter(`unsupported rule: ${rule}`);
18
+ }
19
+ }
20
+ }
21
+ };
22
+ const detectNeededRulesPlugins = (targetConfig, reporter) => {
23
+ if (targetConfig.rules === void 0) {
24
+ return;
25
+ }
26
+ if (targetConfig.plugins === void 0) {
27
+ targetConfig.plugins = [];
28
+ }
29
+ for (const rule of Object.keys(targetConfig.rules)) {
30
+ if (!rule.includes("/")) {
31
+ continue;
32
+ }
33
+ let found = false;
34
+ for (const [prefix, plugin] of Object.entries(rulesPrefixesForPlugins)) {
35
+ if (rule.startsWith(`${prefix}/`) && !targetConfig.plugins.includes(plugin)) {
36
+ targetConfig.plugins.push(plugin);
37
+ found = true;
38
+ }
39
+ }
40
+ if (!found) {
41
+ reporter !== void 0 && reporter(`unsupported plugin for rule: ${rule}`);
42
+ }
43
+ }
44
+ };
45
+ export {
46
+ detectNeededRulesPlugins,
47
+ transformRuleEntry
48
+ };
@@ -0,0 +1,24 @@
1
+ import { Linter } from 'eslint';
2
+ type OxlintConfigPlugins = string[];
3
+ type OxlintConfigCategories = Record<string, unknown>;
4
+ type OxlintConfigEnv = Record<string, boolean>;
5
+ type OxlintConfigIgnorePatterns = string[];
6
+ export type OxlintConfigOverride = {
7
+ files: string[];
8
+ env?: OxlintConfigEnv;
9
+ globals?: Linter.Globals;
10
+ plugins?: OxlintConfigPlugins;
11
+ rules?: Partial<Linter.RulesRecord>;
12
+ };
13
+ export type OxlintConfig = {
14
+ env?: OxlintConfigEnv;
15
+ globals?: Linter.Globals;
16
+ plugins?: OxlintConfigPlugins;
17
+ categories?: OxlintConfigCategories;
18
+ rules?: Partial<Linter.RulesRecord>;
19
+ overrides?: OxlintConfigOverride[];
20
+ ignorePatterns?: OxlintConfigIgnorePatterns;
21
+ };
22
+ export type OxlintConfigOrOverride = OxlintConfig | OxlintConfigOverride;
23
+ export type Reporter = ((warning: string) => void) | undefined;
24
+ export {};
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@oxlint/migrate",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "oxlint-migrate": "./dist/bin/oxlint-migrate.mjs"
9
+ },
10
+ "files": [
11
+ "dist/*",
12
+ "README.md"
13
+ ],
14
+ "keywords": [
15
+ "oxc",
16
+ "oxlint",
17
+ "eslint",
18
+ "rules"
19
+ ],
20
+ "author": "Sysix <sysix@sysix-coding.de>",
21
+ "license": "MIT",
22
+ "devDependencies": {
23
+ "@oxc-node/core": "^0.0.19",
24
+ "@types/node": "^22.13.1",
25
+ "eslint": "^9.20.1",
26
+ "husky": "^9.1.7",
27
+ "lint-staged": "^15.4.3",
28
+ "oxlint": "^0.15.10",
29
+ "prettier": "^3.5.0",
30
+ "typescript": "^5.7.3",
31
+ "vite": "^6.1.0",
32
+ "vite-plugin-dts": "^4.5.0",
33
+ "vitest": "^3.0.5"
34
+ },
35
+ "lint-staged": {
36
+ "*": "prettier --ignore-unknown --write"
37
+ },
38
+ "dependencies": {
39
+ "commander": "^13.1.0",
40
+ "globals": "^15.14.0"
41
+ },
42
+ "scripts": {
43
+ "generate": "node --import @oxc-node/core/register ./scripts/generate.ts",
44
+ "format": "npx prettier --write .",
45
+ "type-check": "tsc --noEmit",
46
+ "test": "vitest",
47
+ "build": "vite build",
48
+ "manual-test": "pnpm build; chmod +x dist/bin/oxlint-migrate.mjs; npx . integration_test/projects/autoprefixer.eslint.config.mjs"
49
+ }
50
+ }