@oxlint/migrate 1.43.0 → 1.46.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 CHANGED
@@ -44,31 +44,18 @@ Tested ESLint Plugins with `oxlint` can be found in this [Oxc Discussion](https:
44
44
 
45
45
  ### TypeScript ESLint Configuration Files
46
46
 
47
- For Deno and Bun, TypeScript configuration files, like `eslint.config.mts`, are natively supported.
48
- For Node.js, you must install [jiti](https://www.npmjs.com/package/jiti) as a dev dependency.
47
+ TypeScript configuration files, like `eslint.config.mts`, are supported in the following environments:
49
48
 
50
- ## Contributing
51
-
52
- ### Generate rules
49
+ - **Deno and Bun**: TypeScript configuration files are natively supported.
50
+ - **Node.js >=22.18.0**: TypeScript configuration files are supported natively with built-in type-stripping enabled by default.
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://www.npmjs.com/package/@oxc-node/core) as a dev dependency.
53
53
 
54
- Generates the rules from installed oxlint version
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
 
56
- ```shell
57
- pnpm generate
58
- pnpm format
59
- ```
60
-
61
- ### Unit + Integration Test
62
-
63
- ```shell
64
- pnpm vitest
65
- ```
66
-
67
- ### Manual Testing
56
+ ## Contributing
68
57
 
69
- ```shell
70
- pnpm manual-test
71
- ```
58
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for details on how to contribute to this project.
72
59
 
73
60
  ## Caveats
74
61
 
@@ -76,9 +63,11 @@ The migration tool has been tested to work quite well for simple ESLint flat con
76
63
 
77
64
  Here are some known caveats to be aware of:
78
65
 
79
- **`settings` field not migrated**
66
+ **`settings` field migration**
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 skipped since they aren't supported by oxlint. If using the `--js-plugins` flag, other settings keys will also be migrated in order to support JS Plugins.
80
69
 
81
- The `settings` field (e.g. for setting the React version) is not migrated to the oxlint config yet. You may need to copy it over manually if you have any settings specified.
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.
82
71
 
83
72
  Not all `settings` options are supported by oxlint, and so rule behavior in certain edge-cases may differ. See [the Settings docs](https://oxc.rs/docs/guide/usage/linter/config-file-reference.html#settings) for more info.
84
73
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as rules_exports, i as nurseryRules, n as preFixForJsPlugins, r as isOffValue, t as src_default } from "../src-BMWXAQvA.mjs";
2
+ import { a as preFixForJsPlugins, f as nurseryRules, p as rules_exports, u as isOffValue } from "../settings-C8UlaScv.mjs";
3
+ import main from "../src/index.mjs";
3
4
  import { program } from "commander";
4
5
  import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
6
  import path from "node:path";
@@ -27,20 +28,12 @@ const loadESLintConfig = async (filePath) => {
27
28
  if (filePath.endsWith("json")) throw new Error(`json format is not supported. @oxlint/migrate only supports the eslint flat configuration`);
28
29
  let url = pathToFileURL(filePath).toString();
29
30
  if (!existsSync(filePath)) throw new Error(`eslint config file not found: ${filePath}`);
30
- if ("Bun" in globalThis || "Deno" in globalThis) return import(url);
31
- if (filePath.endsWith(".ts") || filePath.endsWith(".mts") || filePath.endsWith(".cts")) {
32
- const { createJiti } = await import("jiti");
33
- return createJiti(filePath, {
34
- interopDefault: false,
35
- moduleCache: false
36
- }).import(url);
37
- }
38
31
  return import(url);
39
32
  };
40
33
 
41
34
  //#endregion
42
35
  //#region package.json
43
- var version = "1.43.0";
36
+ var version = "1.46.0";
44
37
 
45
38
  //#endregion
46
39
  //#region src/walker/comments/replaceRuleDirectiveComment.ts
@@ -449,7 +442,7 @@ program.name("oxlint-migrate").version(version).argument("[eslint-config]", "The
449
442
  encoding: "utf8",
450
443
  flag: "r"
451
444
  }));
452
- const oxlintConfig = "default" in eslintConfigs ? await src_default(eslintConfigs.default, config, options) : await src_default(eslintConfigs, config, options);
445
+ const oxlintConfig = "default" in eslintConfigs ? await main(eslintConfigs.default, config, options) : await main(eslintConfigs, config, options);
453
446
  if (existsSync(oxlintFilePath)) renameSync(oxlintFilePath, `${oxlintFilePath}.bak`);
454
447
  writeFileSync(oxlintFilePath, JSON.stringify(oxlintConfig, null, 2));
455
448
  const enabledRulesCount = countEnabledRules(oxlintConfig);
@@ -1,8 +1,8 @@
1
1
  import globals from "globals";
2
2
 
3
- //#region rolldown:runtime
3
+ //#region \0rolldown/runtime.js
4
4
  var __defProp = Object.defineProperty;
5
- var __exportAll = (all, symbols) => {
5
+ var __exportAll = (all, no_symbols) => {
6
6
  let target = {};
7
7
  for (var name in all) {
8
8
  __defProp(target, name, {
@@ -10,7 +10,7 @@ var __exportAll = (all, symbols) => {
10
10
  enumerable: true
11
11
  });
12
12
  }
13
- if (symbols) {
13
+ if (!no_symbols) {
14
14
  __defProp(target, Symbol.toStringTag, { value: "Module" });
15
15
  }
16
16
  return target;
@@ -427,6 +427,7 @@ const styleRules = [
427
427
  "@typescript-eslint/ban-tslint-comment",
428
428
  "@typescript-eslint/consistent-generic-constructors",
429
429
  "@typescript-eslint/consistent-indexed-object-style",
430
+ "@typescript-eslint/consistent-type-assertions",
430
431
  "@typescript-eslint/consistent-type-definitions",
431
432
  "@typescript-eslint/consistent-type-imports",
432
433
  "@typescript-eslint/no-empty-interface",
@@ -471,6 +472,7 @@ const styleRules = [
471
472
  "unicorn/prefer-string-raw",
472
473
  "unicorn/prefer-string-trim-start-end",
473
474
  "unicorn/prefer-structured-clone",
475
+ "unicorn/relative-url-style",
474
476
  "unicorn/require-array-join-separator",
475
477
  "unicorn/require-module-attributes",
476
478
  "unicorn/switch-case-braces",
@@ -482,6 +484,7 @@ const styleRules = [
482
484
  "vitest/prefer-called-once",
483
485
  "vitest/prefer-called-times",
484
486
  "vitest/prefer-describe-function-title",
487
+ "vitest/prefer-expect-type-of",
485
488
  "vitest/prefer-to-be-falsy",
486
489
  "vitest/prefer-to-be-object",
487
490
  "vitest/prefer-to-be-truthy",
@@ -605,7 +608,6 @@ const restrictionRules = [
605
608
  "no-empty",
606
609
  "no-empty-function",
607
610
  "no-eq-null",
608
- "no-iterator",
609
611
  "no-param-reassign",
610
612
  "no-plusplus",
611
613
  "no-proto",
@@ -717,7 +719,9 @@ const correctnessRules = [
717
719
  "no-import-assign",
718
720
  "no-invalid-regexp",
719
721
  "no-irregular-whitespace",
722
+ "no-iterator",
720
723
  "no-loss-of-precision",
724
+ "no-misleading-character-class",
721
725
  "no-new-native-nonconstructor",
722
726
  "no-nonoctal-decimal-escape",
723
727
  "no-obj-calls",
@@ -903,7 +907,6 @@ const correctnessRules = [
903
907
  ];
904
908
  const nurseryRules = [
905
909
  "getter-return",
906
- "no-misleading-character-class",
907
910
  "no-undef",
908
911
  "no-unreachable",
909
912
  "import/export",
@@ -1533,59 +1536,105 @@ function processConfigFiles(files, reporter) {
1533
1536
  }
1534
1537
 
1535
1538
  //#endregion
1536
- //#region src/index.ts
1537
- const buildConfig = (configs, oxlintConfig, options) => {
1538
- if (oxlintConfig === void 0) if (options?.merge) oxlintConfig = {
1539
- plugins: [
1540
- "oxc",
1541
- "typescript",
1542
- "unicorn",
1543
- "react"
1544
- ],
1545
- categories: { correctness: "warn" }
1546
- };
1547
- else oxlintConfig = {
1548
- $schema: "./node_modules/oxlint/configuration_schema.json",
1549
- plugins: [],
1550
- categories: { correctness: "off" }
1551
- };
1552
- if (oxlintConfig.$schema === void 0 && options?.merge) oxlintConfig.$schema = "./node_modules/oxlint/configuration_schema.json";
1553
- if (oxlintConfig.env?.builtin === void 0) {
1554
- if (oxlintConfig.env === void 0) oxlintConfig.env = {};
1555
- oxlintConfig.env.builtin = true;
1556
- }
1557
- const overrides = options?.merge ? oxlintConfig.overrides ?? [] : [];
1558
- for (const config of configs) {
1559
- if (config.name?.startsWith("oxlint/")) continue;
1560
- let targetConfig;
1561
- if (config.files === void 0) targetConfig = oxlintConfig;
1562
- else {
1563
- const validFiles = processConfigFiles(config.files, options?.reporter);
1564
- if (validFiles.length === 0) continue;
1565
- targetConfig = { files: validFiles };
1566
- const [push, result] = detectSameOverride(oxlintConfig, targetConfig);
1567
- if (push) overrides.push(result);
1539
+ //#region src/settings.ts
1540
+ const OXLINT_SUPPORTED_SETTINGS_KEYS = [
1541
+ "jsx-a11y",
1542
+ "next",
1543
+ "react",
1544
+ "jsdoc",
1545
+ "vitest"
1546
+ ];
1547
+ const UNSUPPORTED_SETTINGS_SUB_KEYS = {
1548
+ react: ["pragma", "fragment"],
1549
+ vitest: ["vitestImports"]
1550
+ };
1551
+ /**
1552
+ * Deep merge source into target, combining nested objects rather than replacing them.
1553
+ * Arrays are replaced, not merged. Mutates `target` in place.
1554
+ */
1555
+ const deepMerge = (target, source) => {
1556
+ for (const [key, value] of Object.entries(source)) if (value !== null && typeof value === "object" && !Array.isArray(value) && key in target && target[key] !== null && typeof target[key] === "object" && !Array.isArray(target[key])) deepMerge(target[key], value);
1557
+ else target[key] = value;
1558
+ };
1559
+ /**
1560
+ * Check if a settings key is known to be supported by oxlint.
1561
+ */
1562
+ const isSupportedSettingsKey = (key) => {
1563
+ return OXLINT_SUPPORTED_SETTINGS_KEYS.includes(key);
1564
+ };
1565
+ /**
1566
+ * Transform ESLint settings to oxlint settings.
1567
+ *
1568
+ * Only processes settings for the base config (not overrides) since oxlint
1569
+ * does not support settings in overrides.
1570
+ *
1571
+ * Only known oxlint-supported settings keys are migrated:
1572
+ * - jsx-a11y
1573
+ * - next
1574
+ * - react
1575
+ * - jsdoc
1576
+ * - vitest
1577
+ *
1578
+ * @param eslintConfig - The source ESLint config
1579
+ * @param targetConfig - The target oxlint config (must be base config, not override)
1580
+ * @param options - Migration options
1581
+ */
1582
+ const transformSettings = (eslintConfig, targetConfig, options) => {
1583
+ if (eslintConfig.settings === void 0 || eslintConfig.settings === null || Object.keys(eslintConfig.settings).length === 0) return;
1584
+ const eslintSettings = eslintConfig.settings;
1585
+ const filteredSettings = {};
1586
+ const skippedKeys = [];
1587
+ for (const [key, value] of Object.entries(eslintSettings)) {
1588
+ if (value === null || typeof value !== "object") {
1589
+ skippedKeys.push(key);
1590
+ continue;
1591
+ }
1592
+ if (!options?.jsPlugins && !isSupportedSettingsKey(key)) {
1593
+ skippedKeys.push(key);
1594
+ continue;
1568
1595
  }
1569
- transformIgnorePatterns(config, targetConfig, options);
1570
- transformRuleEntry(config, targetConfig, config.files !== void 0 ? oxlintConfig : void 0, options);
1571
- transformEnvAndGlobals(config, targetConfig, options);
1572
- if ("files" in targetConfig) {
1573
- detectNeededRulesPlugins(targetConfig);
1574
- detectEnvironmentByGlobals(targetConfig);
1575
- cleanUpOxlintConfig(targetConfig);
1596
+ if (key === "import" || key.startsWith("import/")) {
1597
+ skippedKeys.push(key);
1598
+ continue;
1576
1599
  }
1600
+ let settingsValue = value;
1601
+ if (key === "react" && settingsValue.version === "detect") {
1602
+ options?.reporter?.addWarning("react.version \"detect\" is not supported by oxlint. Please specify an explicit version (e.g., \"18.2.0\") in your oxlint config.");
1603
+ const { version: _, ...restReactSettings } = settingsValue;
1604
+ settingsValue = restReactSettings;
1605
+ }
1606
+ const unsupportedSubKeys = UNSUPPORTED_SETTINGS_SUB_KEYS[key];
1607
+ if (unsupportedSubKeys !== void 0) {
1608
+ const strippedKeys = [];
1609
+ for (const subKey of unsupportedSubKeys) if (subKey in settingsValue) {
1610
+ strippedKeys.push(`${key}.${subKey}`);
1611
+ const { [subKey]: _, ...rest } = settingsValue;
1612
+ settingsValue = rest;
1613
+ }
1614
+ if (strippedKeys.length > 0) options?.reporter?.addWarning(`Settings not migrated (not supported by oxlint): ${strippedKeys.join(", ")}.`);
1615
+ }
1616
+ if (Object.keys(settingsValue).length === 0) continue;
1617
+ filteredSettings[key] = settingsValue;
1577
1618
  }
1578
- oxlintConfig.overrides = overrides;
1579
- detectNeededRulesPlugins(oxlintConfig);
1580
- detectEnvironmentByGlobals(oxlintConfig);
1581
- cleanUpOxlintConfig(oxlintConfig);
1582
- return oxlintConfig;
1619
+ if (skippedKeys.length > 0) options?.reporter?.addWarning(`Settings not migrated (not supported by oxlint): ${skippedKeys.join(", ")}.`);
1620
+ if (Object.keys(filteredSettings).length === 0) return;
1621
+ if (targetConfig.settings === void 0) targetConfig.settings = {};
1622
+ if (options?.merge) deepMerge(targetConfig.settings, filteredSettings);
1623
+ else Object.assign(targetConfig.settings, filteredSettings);
1583
1624
  };
1584
- const main = async (configs, oxlintConfig, options) => {
1585
- const resolved = await Promise.resolve(fixForJsPlugins(configs));
1586
- return buildConfig(Array.isArray(resolved) ? resolved : [resolved], oxlintConfig, options);
1625
+ /**
1626
+ * Warn when settings are found in an override config, since oxlint does not
1627
+ * support settings in overrides.
1628
+ *
1629
+ * @param eslintConfig - The ESLint config being processed
1630
+ * @param options - Migration options
1631
+ */
1632
+ const warnSettingsInOverride = (eslintConfig, options) => {
1633
+ if (eslintConfig.settings !== void 0 && eslintConfig.settings !== null && Object.keys(eslintConfig.settings).length > 0) {
1634
+ const settingsKeys = Object.keys(eslintConfig.settings).join(", ");
1635
+ options?.reporter?.addWarning(`Settings found in config with 'files' pattern (${settingsKeys}). Oxlint does not support settings in overrides, these settings will be skipped.`);
1636
+ }
1587
1637
  };
1588
- var src_default = main;
1589
1638
 
1590
1639
  //#endregion
1591
- export { rules_exports as a, nurseryRules as i, preFixForJsPlugins as n, isOffValue as r, src_default as t };
1640
+ export { preFixForJsPlugins as a, cleanUpOxlintConfig as c, transformRuleEntry as d, nurseryRules as f, transformEnvAndGlobals as h, fixForJsPlugins as i, detectNeededRulesPlugins as l, detectEnvironmentByGlobals as m, warnSettingsInOverride as n, detectSameOverride as o, rules_exports as p, processConfigFiles as r, transformIgnorePatterns as s, transformSettings as t, isOffValue as u };
@@ -2671,6 +2671,8 @@ type OxlintConfigJsPlugins = string[];
2671
2671
  type OxlintConfigCategories = Partial<Record<Category, unknown>>;
2672
2672
  type OxlintConfigEnv = Record<string, boolean>;
2673
2673
  type OxlintConfigIgnorePatterns = string[];
2674
+ type OxlintSupportedSettingsKey = 'jsx-a11y' | 'next' | 'react' | 'jsdoc' | 'vitest';
2675
+ type OxlintSettings = { [K in OxlintSupportedSettingsKey]?: Record<string, unknown> } & Record<string, Record<string, unknown> | undefined>;
2674
2676
  type OxlintConfigOverride = {
2675
2677
  files: string[];
2676
2678
  env?: OxlintConfigEnv;
@@ -2690,6 +2692,7 @@ type OxlintConfig = {
2690
2692
  rules?: Partial<Linter.RulesRecord>;
2691
2693
  overrides?: OxlintConfigOverride[];
2692
2694
  ignorePatterns?: OxlintConfigIgnorePatterns;
2695
+ settings?: OxlintSettings;
2693
2696
  };
2694
2697
  type RuleSkippedCategory = 'nursery' | 'type-aware' | 'unsupported' | 'js-plugins';
2695
2698
  type SkippedCategoryGroup = Record<RuleSkippedCategory, string[]>;
@@ -1,3 +1,59 @@
1
- import { t as src_default } from "../src-BMWXAQvA.mjs";
1
+ import { c as cleanUpOxlintConfig, d as transformRuleEntry, h as transformEnvAndGlobals, i as fixForJsPlugins, l as detectNeededRulesPlugins, m as detectEnvironmentByGlobals, n as warnSettingsInOverride, o as detectSameOverride, r as processConfigFiles, s as transformIgnorePatterns, t as transformSettings } from "../settings-C8UlaScv.mjs";
2
2
 
3
- export { src_default as default };
3
+ //#region src/index.ts
4
+ const buildConfig = (configs, oxlintConfig, options) => {
5
+ if (oxlintConfig === void 0) if (options?.merge) oxlintConfig = {
6
+ plugins: [
7
+ "oxc",
8
+ "typescript",
9
+ "unicorn",
10
+ "react"
11
+ ],
12
+ categories: { correctness: "warn" }
13
+ };
14
+ else oxlintConfig = {
15
+ $schema: "./node_modules/oxlint/configuration_schema.json",
16
+ plugins: [],
17
+ categories: { correctness: "off" }
18
+ };
19
+ if (oxlintConfig.$schema === void 0 && options?.merge) oxlintConfig.$schema = "./node_modules/oxlint/configuration_schema.json";
20
+ if (oxlintConfig.env?.builtin === void 0) {
21
+ if (oxlintConfig.env === void 0) oxlintConfig.env = {};
22
+ oxlintConfig.env.builtin = true;
23
+ }
24
+ const overrides = options?.merge ? oxlintConfig.overrides ?? [] : [];
25
+ for (const config of configs) {
26
+ if (config.name?.startsWith("oxlint/")) continue;
27
+ let targetConfig;
28
+ if (config.files === void 0) targetConfig = oxlintConfig;
29
+ else {
30
+ const validFiles = processConfigFiles(config.files, options?.reporter);
31
+ if (validFiles.length === 0) continue;
32
+ targetConfig = { files: validFiles };
33
+ const [push, result] = detectSameOverride(oxlintConfig, targetConfig);
34
+ if (push) overrides.push(result);
35
+ }
36
+ transformIgnorePatterns(config, targetConfig, options);
37
+ transformRuleEntry(config, targetConfig, config.files !== void 0 ? oxlintConfig : void 0, options);
38
+ transformEnvAndGlobals(config, targetConfig, options);
39
+ if (config.files === void 0) transformSettings(config, oxlintConfig, options);
40
+ else warnSettingsInOverride(config, options);
41
+ if ("files" in targetConfig) {
42
+ detectNeededRulesPlugins(targetConfig);
43
+ detectEnvironmentByGlobals(targetConfig);
44
+ cleanUpOxlintConfig(targetConfig);
45
+ }
46
+ }
47
+ oxlintConfig.overrides = overrides;
48
+ detectNeededRulesPlugins(oxlintConfig);
49
+ detectEnvironmentByGlobals(oxlintConfig);
50
+ cleanUpOxlintConfig(oxlintConfig);
51
+ return oxlintConfig;
52
+ };
53
+ const main = async (configs, oxlintConfig, options) => {
54
+ const resolved = await Promise.resolve(fixForJsPlugins(configs));
55
+ return buildConfig(Array.isArray(resolved) ? resolved : [resolved], oxlintConfig, options);
56
+ };
57
+
58
+ //#endregion
59
+ export { main as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxlint/migrate",
3
- "version": "1.43.0",
3
+ "version": "1.46.0",
4
4
  "description": "Generates a `.oxlintrc.json` from a existing eslint flat config",
5
5
  "keywords": [
6
6
  "eslint",
@@ -68,24 +68,20 @@
68
68
  "eslint-plugin-react": "^7.37.5",
69
69
  "eslint-plugin-react-hooks": "^7.0.1",
70
70
  "eslint-plugin-react-perf": "^3.3.3",
71
- "eslint-plugin-react-refresh": "^0.4.26",
71
+ "eslint-plugin-react-refresh": "^0.5.0",
72
72
  "eslint-plugin-regexp": "^3.0.0",
73
73
  "eslint-plugin-tsdoc": "^0.5.0",
74
74
  "eslint-plugin-unicorn": "^62.0.0",
75
75
  "husky": "^9.1.7",
76
- "jiti": "^2.4.2",
77
76
  "lint-staged": "^16.1.2",
78
77
  "next": "^16.0.0",
79
78
  "oxfmt": "^0.28.0",
80
- "oxlint": "^1.43.0",
79
+ "oxlint": "^1.46.0",
81
80
  "oxlint-tsgolint": "^0.11.3",
82
81
  "tsdown": "^0.20.0",
83
82
  "typescript-eslint": "^8.35.0",
84
83
  "vitest": "^4.0.0"
85
84
  },
86
- "peerDependencies": {
87
- "jiti": "*"
88
- },
89
85
  "lint-staged": {
90
86
  "*": "oxfmt --no-error-on-unmatched-pattern"
91
87
  },