@oxlint/migrate 1.23.0 → 1.25.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.
@@ -9,6 +9,7 @@ import { walkAndReplaceProjectFiles } from "../src/walker/index.mjs";
9
9
  import { getAllProjectFiles } from "./project-loader.mjs";
10
10
  import { writeFile } from "node:fs/promises";
11
11
  import { preFixForJsPlugins } from "../src/js_plugin_fixes.mjs";
12
+ import { DefaultReporter } from "../src/reporter.mjs";
12
13
  const cwd = process.cwd();
13
14
  const getFileContent = (absoluteFilePath) => {
14
15
  try {
@@ -38,8 +39,9 @@ program.name("oxlint-migrate").version(packageJson.version).argument("[eslint-co
38
39
  ).action(async (filePath) => {
39
40
  const cliOptions = program.opts();
40
41
  const oxlintFilePath = path.join(cwd, cliOptions.outputFile);
42
+ const reporter = new DefaultReporter();
41
43
  const options = {
42
- reporter: console.warn,
44
+ reporter,
43
45
  merge: !!cliOptions.merge,
44
46
  withNursery: !!cliOptions.withNursery,
45
47
  typeAware: !!cliOptions.typeAware
@@ -75,5 +77,8 @@ program.name("oxlint-migrate").version(packageJson.version).argument("[eslint-co
75
77
  renameSync(oxlintFilePath, `${oxlintFilePath}.bak`);
76
78
  }
77
79
  writeFileSync(oxlintFilePath, JSON.stringify(oxlintConfig, null, 2));
80
+ for (const report of reporter.getReports()) {
81
+ console.warn(report);
82
+ }
78
83
  });
79
84
  program.parse();
@@ -1,4 +1,4 @@
1
- const version = "1.23.0";
1
+ const version = "1.25.0";
2
2
  const packageJson = {
3
3
  version
4
4
  };
@@ -1,5 +1,5 @@
1
1
  import { removeGlobalsWithAreCoveredByEnv, transformBoolGlobalToString, ES_VERSIONS, cleanUpUselessOverridesEnv } from "./env_globals.mjs";
2
- import { replaceTypescriptAliasRules, replaceNodePluginName, cleanUpRulesWhichAreCoveredByCategory, cleanUpUselessOverridesRules, cleanUpUselessOverridesPlugins } from "./plugins_rules.mjs";
2
+ import { replaceTypescriptAliasRules, replaceNodePluginName, cleanUpRulesWhichAreCoveredByCategory, cleanUpDisabledRootRules, cleanUpUselessOverridesRules, cleanUpUselessOverridesPlugins } from "./plugins_rules.mjs";
3
3
  import { isEqualDeep } from "./utilities.mjs";
4
4
  const TS_ESLINT_DEFAULT_OVERRIDE = {
5
5
  files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
@@ -81,6 +81,7 @@ const cleanUpOxlintConfig = (config) => {
81
81
  }
82
82
  if (!("files" in config)) {
83
83
  cleanUpUselessOverridesEntries(config);
84
+ cleanUpDisabledRootRules(config);
84
85
  }
85
86
  };
86
87
  export {
@@ -107,14 +107,16 @@ const detectEnvironmentByGlobals = (config) => {
107
107
  }
108
108
  };
109
109
  const transformEnvAndGlobals = (eslintConfig, targetConfig, options) => {
110
- if (eslintConfig.languageOptions?.parser !== void 0 && !SUPPORTED_ESLINT_PARSERS.includes(
110
+ if (eslintConfig.languageOptions?.parser !== void 0 && eslintConfig.languageOptions?.parser !== null && typeof eslintConfig.languageOptions.parser === "object" && "meta" in eslintConfig.languageOptions.parser && !SUPPORTED_ESLINT_PARSERS.includes(
111
+ // @ts-ignore
111
112
  eslintConfig.languageOptions.parser.meta?.name
112
113
  )) {
113
- options?.reporter !== void 0 && options.reporter(
114
- "special parser detected: " + eslintConfig.languageOptions.parser.meta?.name
114
+ options?.reporter?.report(
115
+ "special parser detected: " + // @ts-ignore
116
+ eslintConfig.languageOptions.parser.meta?.name
115
117
  );
116
118
  }
117
- if (eslintConfig.languageOptions?.globals !== void 0) {
119
+ if (eslintConfig.languageOptions?.globals !== void 0 && eslintConfig.languageOptions?.globals !== null) {
118
120
  if (targetConfig.globals === void 0) {
119
121
  targetConfig.globals = {};
120
122
  }
@@ -131,7 +133,7 @@ const transformEnvAndGlobals = (eslintConfig, targetConfig, options) => {
131
133
  }
132
134
  }
133
135
  if (eslintConfig.languageOptions?.ecmaVersion !== void 0) {
134
- if (eslintConfig.languageOptions?.ecmaVersion === "latest") {
136
+ if (eslintConfig.languageOptions.ecmaVersion === "latest") {
135
137
  if (targetConfig.env === void 0) {
136
138
  targetConfig.env = {};
137
139
  }
@@ -139,11 +141,11 @@ const transformEnvAndGlobals = (eslintConfig, targetConfig, options) => {
139
141
  if (!(latestVersion in targetConfig.env)) {
140
142
  targetConfig.env[latestVersion] = true;
141
143
  }
142
- } else if (ES_VERSIONS.includes(eslintConfig.languageOptions?.ecmaVersion)) {
144
+ } else if (typeof eslintConfig.languageOptions.ecmaVersion === "number" && ES_VERSIONS.includes(eslintConfig.languageOptions.ecmaVersion)) {
143
145
  if (targetConfig.env === void 0) {
144
146
  targetConfig.env = {};
145
147
  }
146
- const targetVersion = `es${eslintConfig.languageOptions?.ecmaVersion}`;
148
+ const targetVersion = `es${eslintConfig.languageOptions.ecmaVersion}`;
147
149
  if (!(targetVersion in targetConfig.env)) {
148
150
  targetConfig.env[targetVersion] = true;
149
151
  }
@@ -2,6 +2,6 @@ export declare const pedanticRules: string[];
2
2
  export declare const styleRules: string[];
3
3
  export declare const suspiciousRules: string[];
4
4
  export declare const restrictionRules: string[];
5
- export declare const correctnessRules: string[];
6
5
  export declare const nurseryRules: string[];
6
+ export declare const correctnessRules: string[];
7
7
  export declare const perfRules: string[];
@@ -20,6 +20,7 @@ const pedanticRules = [
20
20
  "no-redeclare",
21
21
  "no-self-compare",
22
22
  "no-throw-literal",
23
+ "no-warning-comments",
23
24
  "radix",
24
25
  "require-await",
25
26
  "sort-vars",
@@ -56,6 +57,7 @@ const pedanticRules = [
56
57
  "@typescript-eslint/require-await",
57
58
  "@typescript-eslint/restrict-plus-operands",
58
59
  "@typescript-eslint/return-await",
60
+ "@typescript-eslint/strict-boolean-expressions",
59
61
  "@typescript-eslint/switch-exhaustiveness-check",
60
62
  "unicorn/consistent-assert",
61
63
  "unicorn/consistent-empty-array-spread",
@@ -267,9 +269,9 @@ const styleRules = [
267
269
  "vitest/prefer-to-be-falsy",
268
270
  "vitest/prefer-to-be-object",
269
271
  "vitest/prefer-to-be-truthy",
270
- "vue/define-props-destructuring",
271
272
  "vue/define-emits-declaration",
272
273
  "vue/define-props-declaration",
274
+ "vue/define-props-destructuring",
273
275
  "vue/require-typed-ref",
274
276
  "@typescript-eslint/default-param-last",
275
277
  "@typescript-eslint/init-declarations",
@@ -402,6 +404,7 @@ const restrictionRules = [
402
404
  "promise/catch-or-return",
403
405
  "promise/spec-only",
404
406
  "react/button-has-type",
407
+ "react/forbid-dom-props",
405
408
  "react/forbid-elements",
406
409
  "react/jsx-filename-extension",
407
410
  "react/no-danger",
@@ -449,6 +452,19 @@ const restrictionRules = [
449
452
  "import-x/no-webpack-loader-syntax",
450
453
  "import-x/unambiguous"
451
454
  ];
455
+ const nurseryRules = [
456
+ "constructor-super",
457
+ "getter-return",
458
+ "no-misleading-character-class",
459
+ "no-undef",
460
+ "no-unreachable",
461
+ "import/export",
462
+ "import/named",
463
+ "promise/no-return-in-finally",
464
+ "react/require-render-return",
465
+ "import-x/export",
466
+ "import-x/named"
467
+ ];
452
468
  const correctnessRules = [
453
469
  "for-direction",
454
470
  "no-unassigned-vars",
@@ -649,18 +665,6 @@ const correctnessRules = [
649
665
  "vitest/valid-describe-callback",
650
666
  "vitest/valid-expect"
651
667
  ];
652
- const nurseryRules = [
653
- "getter-return",
654
- "no-misleading-character-class",
655
- "no-undef",
656
- "no-unreachable",
657
- "import/export",
658
- "import/named",
659
- "promise/no-return-in-finally",
660
- "react/require-render-return",
661
- "import-x/export",
662
- "import-x/named"
663
- ];
664
668
  const perfRules = [
665
669
  "no-await-in-loop",
666
670
  "no-useless-call",
@@ -3,7 +3,7 @@ const transformIgnorePatterns = (eslintConfig, targetConfig, options) => {
3
3
  return;
4
4
  }
5
5
  if ("files" in targetConfig) {
6
- options?.reporter !== void 0 && options.reporter("ignore list inside overrides is not supported");
6
+ options?.reporter?.report("ignore list inside overrides is not supported");
7
7
  return;
8
8
  }
9
9
  if (targetConfig.ignorePatterns === void 0) {
@@ -5,6 +5,7 @@ export declare const detectNeededRulesPlugins: (targetConfig: OxlintConfigOrOver
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;
8
+ export declare const cleanUpDisabledRootRules: (config: OxlintConfig) => void;
8
9
  export declare const replaceTypescriptAliasRules: (config: OxlintConfigOrOverride) => void;
9
10
  /**
10
11
  * Oxlint support them only under the node plugin name
@@ -43,11 +43,13 @@ const transformRuleEntry = (eslintConfig, targetConfig, options) => {
43
43
  for (const [rule, config] of Object.entries(eslintConfig.rules)) {
44
44
  if (allRules.includes(rule)) {
45
45
  if (!options?.withNursery && nurseryRules.includes(rule)) {
46
- options?.reporter !== void 0 && options.reporter(`unsupported rule, but in development: ${rule}`);
46
+ options?.reporter?.report(
47
+ `unsupported rule, but in development: ${rule}`
48
+ );
47
49
  continue;
48
50
  }
49
51
  if (!options?.typeAware && typescriptTypeAwareRules.includes(rule)) {
50
- options?.reporter !== void 0 && options.reporter(
52
+ options?.reporter?.report(
51
53
  `type-aware rule detected, but \`--type-aware\` is not enabled: ${rule}`
52
54
  );
53
55
  continue;
@@ -61,7 +63,7 @@ const transformRuleEntry = (eslintConfig, targetConfig, options) => {
61
63
  }
62
64
  } else {
63
65
  if (isActiveValue(config)) {
64
- options?.reporter !== void 0 && options.reporter(`unsupported rule: ${rule}`);
66
+ options?.reporter?.report(`unsupported rule: ${rule}`);
65
67
  }
66
68
  }
67
69
  }
@@ -87,7 +89,7 @@ const detectNeededRulesPlugins = (targetConfig, options) => {
87
89
  }
88
90
  }
89
91
  if (!found) {
90
- options?.reporter !== void 0 && options.reporter(`unsupported plugin for rule: ${rule}`);
92
+ options?.reporter?.report(`unsupported plugin for rule: ${rule}`);
91
93
  }
92
94
  }
93
95
  if ("files" in targetConfig && targetConfig.plugins.length === 0) {
@@ -146,6 +148,36 @@ const cleanUpRulesWhichAreCoveredByCategory = (config) => {
146
148
  }
147
149
  }
148
150
  };
151
+ const getEnabledCategories = (config) => {
152
+ if (config.categories === void 0) {
153
+ return ["correctness"];
154
+ }
155
+ const categories = Object.entries(config.categories).filter(([, severity]) => severity === "warn" || severity === "error").map(([category]) => category);
156
+ if (Object.keys(config.categories).includes("correctness")) {
157
+ return categories;
158
+ }
159
+ return [...categories, "correctness"];
160
+ };
161
+ const isRuleInEnabledCategory = (rule, enabledCategories) => {
162
+ for (const category of enabledCategories) {
163
+ if (`${category}Rules` in rules && // @ts-expect-error -- ts can not resolve the type
164
+ rules[`${category}Rules`].includes(rule)) {
165
+ return true;
166
+ }
167
+ }
168
+ return false;
169
+ };
170
+ const cleanUpDisabledRootRules = (config) => {
171
+ if (config.rules === void 0) {
172
+ return;
173
+ }
174
+ const enabledCategories = getEnabledCategories(config);
175
+ for (const [rule, settings] of Object.entries(config.rules)) {
176
+ if (isOffValue(settings) && !isRuleInEnabledCategory(rule, enabledCategories)) {
177
+ delete config.rules[rule];
178
+ }
179
+ }
180
+ };
149
181
  const replaceTypescriptAliasRules = (config) => {
150
182
  if (config.rules === void 0) {
151
183
  return;
@@ -181,6 +213,7 @@ const replaceNodePluginName = (config) => {
181
213
  }
182
214
  };
183
215
  export {
216
+ cleanUpDisabledRootRules,
184
217
  cleanUpRulesWhichAreCoveredByCategory,
185
218
  cleanUpUselessOverridesPlugins,
186
219
  cleanUpUselessOverridesRules,
@@ -0,0 +1,10 @@
1
+ import { Reporter } from './types.js';
2
+ export declare class DefaultReporter implements Reporter {
3
+ private reports;
4
+ report(message: string): void;
5
+ getReports(): string[];
6
+ }
7
+ export declare class SilentReporter implements Reporter {
8
+ report(_message: string): void;
9
+ getReports(): string[];
10
+ }
@@ -0,0 +1,12 @@
1
+ class DefaultReporter {
2
+ reports = /* @__PURE__ */ new Set();
3
+ report(message) {
4
+ this.reports.add(message);
5
+ }
6
+ getReports() {
7
+ return Array.from(this.reports);
8
+ }
9
+ }
10
+ export {
11
+ DefaultReporter
12
+ };
@@ -22,7 +22,10 @@ export type OxlintConfig = {
22
22
  ignorePatterns?: OxlintConfigIgnorePatterns;
23
23
  };
24
24
  export type OxlintConfigOrOverride = OxlintConfig | OxlintConfigOverride;
25
- type Reporter = (warning: string) => void;
25
+ export type Reporter = {
26
+ report(message: string): void;
27
+ getReports(): string[];
28
+ };
26
29
  export type Options = {
27
30
  reporter?: Reporter;
28
31
  merge?: boolean;
@@ -10,8 +10,8 @@ const getComments = (absoluteFilePath, partialSourceText, options) => {
10
10
  sourceType: partialSourceText.sourceType
11
11
  }
12
12
  );
13
- if (parserResult.errors.length > 0 && options.reporter) {
14
- options.reporter(`${absoluteFilePath}: failed to parse`);
13
+ if (parserResult.errors.length > 0) {
14
+ options.reporter?.report(`${absoluteFilePath}: failed to parse`);
15
15
  }
16
16
  return parserResult.comments;
17
17
  };
@@ -26,8 +26,8 @@ function replaceCommentsInSourceText(absoluteFilePath, partialSourceText, option
26
26
  sourceText = sourceText.slice(0, comment.start) + newComment + sourceText.slice(comment.end);
27
27
  }
28
28
  } catch (error) {
29
- if (error instanceof Error && options.reporter) {
30
- options.reporter(
29
+ if (error instanceof Error) {
30
+ options.reporter?.report(
31
31
  `${absoluteFilePath}, char offset ${comment.start + partialSourceText.offset}: ${error.message}`
32
32
  );
33
33
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxlint/migrate",
3
- "version": "1.23.0",
3
+ "version": "1.25.0",
4
4
  "description": "Generates a `.oxlintrc.json` from a existing eslint flat config",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,10 +37,9 @@
37
37
  "author": "Sysix <sysix@sysix-coding.de>",
38
38
  "license": "MIT",
39
39
  "devDependencies": {
40
- "@antfu/eslint-config": "^5.0.0",
41
- "@eslint/eslintrc": "^3.3.1",
40
+ "@antfu/eslint-config": "^6.0.0",
42
41
  "@eslint/js": "^9.29.0",
43
- "@logux/eslint-config": "^56.0.0",
42
+ "@logux/eslint-config": "^57.0.0",
44
43
  "@oxc-node/core": "^0.0.32",
45
44
  "@stylistic/eslint-plugin": "^5.0.0",
46
45
  "@stylistic/eslint-plugin-ts": "^4.4.1",
@@ -48,33 +47,36 @@
48
47
  "@types/node": "^24.0.4",
49
48
  "@typescript-eslint/eslint-plugin": "^8.35.0",
50
49
  "@typescript-eslint/parser": "^8.35.0",
51
- "@vitest/coverage-v8": "^3.2.4",
50
+ "@vitest/coverage-v8": "^4.0.0",
52
51
  "eslint": "^9.29.0",
53
- "eslint-config-next": "^15.5.0",
52
+ "eslint-config-next": "^16.0.0",
54
53
  "eslint-config-prettier": "^10.1.5",
55
54
  "eslint-plugin-header": "^3.1.1",
56
55
  "eslint-plugin-import": "^2.32.0",
57
56
  "eslint-plugin-import-x": "^4.16.0",
58
- "eslint-plugin-jsdoc": "^60.0.0",
57
+ "eslint-plugin-jsdoc": "^61.0.0",
59
58
  "eslint-plugin-local": "^6.0.0",
59
+ "eslint-plugin-mocha": "^11.2.0",
60
60
  "eslint-plugin-oxlint": "^1.3.0",
61
+ "eslint-plugin-prettier": "^5.5.4",
61
62
  "eslint-plugin-react": "^7.37.5",
62
- "eslint-plugin-react-hooks": "^5.2.0",
63
+ "eslint-plugin-react-hooks": "^7.0.1",
63
64
  "eslint-plugin-react-perf": "^3.3.3",
64
65
  "eslint-plugin-regexp": "^2.9.0",
65
- "eslint-plugin-unicorn": "^61.0.0",
66
+ "eslint-plugin-tsdoc": "^0.4.0",
67
+ "eslint-plugin-unicorn": "^62.0.0",
66
68
  "husky": "^9.1.7",
67
69
  "jiti": "^2.4.2",
68
70
  "lint-staged": "^16.1.2",
69
- "next": "^15.5.0",
70
- "oxlint": "^1.23.0",
71
+ "next": "^16.0.0",
72
+ "oxlint": "^1.25.0",
71
73
  "oxlint-tsgolint": "^0.2.0",
72
74
  "prettier": "^3.6.1",
73
75
  "typescript": "^5.8.3",
74
76
  "typescript-eslint": "^8.35.0",
75
77
  "vite": "^7.0.0",
76
78
  "vite-plugin-dts": "^4.5.4",
77
- "vitest": "^3.2.4"
79
+ "vitest": "^4.0.0"
78
80
  },
79
81
  "lint-staged": {
80
82
  "*": "prettier --ignore-unknown --write"
@@ -82,11 +84,11 @@
82
84
  "dependencies": {
83
85
  "commander": "^14.0.0",
84
86
  "globals": "^16.3.0",
85
- "oxc-parser": "^0.94.0",
87
+ "oxc-parser": "^0.95.0",
86
88
  "tinyglobby": "^0.2.14"
87
89
  },
88
90
  "peerDependencies": {
89
91
  "jiti": "*"
90
92
  },
91
- "packageManager": "pnpm@10.18.2"
93
+ "packageManager": "pnpm@10.19.0"
92
94
  }