@oxlint/migrate 0.0.3 → 0.0.5

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
@@ -1,14 +1,21 @@
1
1
  # oxlint-migrate
2
2
 
3
- Generates a `.oxlintrc.json` from a existing eslint v9 configuration
3
+ ![test](https://github.com/oxc-project/oxlint-migrate/actions/workflows/test.yml/badge.svg)
4
+ [![NPM Version](https://img.shields.io/npm/v/%40oxlint%2Fmigrate)](https://www.npmjs.com/package/@oxlint/migrate)
5
+ [![NPM Downloads](https://img.shields.io/npm/dm/%40oxlint%2Fmigrate)](https://www.npmjs.com/package/@oxlint/migrate)
6
+
7
+ Generates a `.oxlintrc.json` from a existing eslint flat config.
4
8
 
5
9
  🚧 Still under development
6
10
 
7
11
  ## Usage
8
12
 
9
- `npx oxlint-migrate <optional-eslint-v9-config-path>`
13
+ ```shell
14
+ pnpm install @oxlint/migrate
15
+ npx oxlint-migrate <optional-eslint-flat-config-path>
16
+ ```
10
17
 
11
- When no config file provided, we look at the default eslint config filenames in the current directory.
18
+ When no config file provided, the script searches for the default eslint config filenames in the current directory.
12
19
 
13
20
  ### User Flow
14
21
 
@@ -5,26 +5,27 @@ import { existsSync, renameSync, writeFileSync } from "fs";
5
5
  import main from "../src/index.mjs";
6
6
  import path from "path";
7
7
  import packageJson from "../package.json.mjs";
8
- program.name("oxlint-migrate").version(packageJson.version).argument("<eslint-config>", "The path to the eslint v9 config file", "");
9
- program.parse();
10
- let [filePath] = program.args;
11
- let cwd = process.cwd();
12
- if (filePath === "") {
13
- filePath = getAutodetectedEslintConfigName(cwd) ?? "";
14
- if (filePath === "") {
15
- program.error(`could not autodetect eslint config file`);
8
+ import { pathToFileURL } from "node:url";
9
+ program.name("oxlint-migrate").version(packageJson.version).argument("[eslint-config]", "The path to the eslint v9 config file").action(async (filePath) => {
10
+ let cwd = process.cwd();
11
+ if (filePath === void 0) {
12
+ filePath = getAutodetectedEslintConfigName(cwd);
13
+ if (filePath === void 0) {
14
+ program.error(`could not autodetect eslint config file`);
15
+ }
16
+ } else {
17
+ filePath = path.join(cwd, filePath);
16
18
  }
17
- } else {
18
- filePath = path.join(cwd, filePath);
19
- }
20
- if (!existsSync(filePath)) {
21
- program.error(`eslint config file not found: ${filePath}`);
22
- } else {
23
- const eslintConfigs = await import(filePath);
24
- const oxlintConfig = "default" in eslintConfigs ? await main(eslintConfigs.default, console.warn) : await main(eslintConfigs, console.warn);
25
- const oxlintFilePath = path.join(cwd, ".oxlintrc.json");
26
- if (existsSync(oxlintFilePath)) {
27
- renameSync(oxlintFilePath, `${oxlintFilePath}.bak`);
19
+ if (!existsSync(filePath)) {
20
+ program.error(`eslint config file not found: ${filePath}`);
21
+ } else {
22
+ const eslintConfigs = await import(pathToFileURL(filePath).toString());
23
+ const oxlintConfig = "default" in eslintConfigs ? await main(eslintConfigs.default, console.warn) : await main(eslintConfigs, console.warn);
24
+ const oxlintFilePath = path.join(cwd, ".oxlintrc.json");
25
+ if (existsSync(oxlintFilePath)) {
26
+ renameSync(oxlintFilePath, `${oxlintFilePath}.bak`);
27
+ }
28
+ writeFileSync(oxlintFilePath, JSON.stringify(oxlintConfig, null, 2));
28
29
  }
29
- writeFileSync(oxlintFilePath, JSON.stringify(oxlintConfig, null, 2));
30
- }
30
+ });
31
+ program.parse();
@@ -1,4 +1,4 @@
1
- const version = "0.0.3";
1
+ const version = "0.0.5";
2
2
  const packageJson = {
3
3
  version
4
4
  };
@@ -1,4 +1,5 @@
1
- import { removeGlobalsWithAreCoveredByEnv, transformBoolGlobalToString, ES_VERSIONS } from "./env_globals.mjs";
1
+ import { removeGlobalsWithAreCoveredByEnv, transformBoolGlobalToString, ES_VERSIONS, cleanUpUselessOverridesEnv } from "./env_globals.mjs";
2
+ import { cleanUpUselessOverridesRules, cleanUpUselessOverridesPlugins } from "./plugins_rules.mjs";
2
3
  const isEqualDeep = (a, b) => {
3
4
  if (a === b) {
4
5
  return true;
@@ -11,8 +12,6 @@ const isEqualDeep = (a, b) => {
11
12
  const TS_ESLINT_DEFAULT_OVERRIDE = {
12
13
  files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
13
14
  rules: {
14
- "constructor-super": "off",
15
- "getter-return": "off",
16
15
  "no-class-assign": "off",
17
16
  "no-const-assign": "off",
18
17
  "no-dupe-class-members": "off",
@@ -24,13 +23,12 @@ const TS_ESLINT_DEFAULT_OVERRIDE = {
24
23
  "no-redeclare": "off",
25
24
  "no-setter-return": "off",
26
25
  "no-this-before-super": "off",
27
- "no-undef": "off",
28
- "no-unreachable": "off",
29
26
  "no-unsafe-negation": "off",
30
27
  "no-var": "error",
31
28
  "prefer-rest-params": "error",
32
29
  "prefer-spread": "error"
33
- }
30
+ },
31
+ plugins: []
34
32
  };
35
33
  const cleanUpDefaultTypeScriptOverridesForEslint = (config) => {
36
34
  if (config.overrides === void 0) {
@@ -44,47 +42,28 @@ const cleanUpDefaultTypeScriptOverridesForEslint = (config) => {
44
42
  }
45
43
  }
46
44
  indexesToDelete.forEach((index) => delete config.overrides[index]);
45
+ config.overrides = config.overrides.filter(
46
+ (overrides) => Object.keys(overrides).length > 0
47
+ );
47
48
  if (Object.keys(config.overrides).length === 0) {
48
49
  delete config.overrides;
49
50
  }
50
51
  };
51
52
  const cleanUpUselessOverridesEntries = (config) => {
53
+ cleanUpUselessOverridesRules(config);
54
+ cleanUpUselessOverridesPlugins(config);
55
+ cleanUpUselessOverridesEnv(config);
52
56
  if (config.overrides === void 0) {
53
57
  return;
54
58
  }
59
+ for (const overrideIndex in config.overrides) {
60
+ if (Object.keys(config.overrides[overrideIndex]).length === 1) {
61
+ delete config.overrides[overrideIndex];
62
+ }
63
+ }
55
64
  config.overrides = config.overrides.filter(
56
65
  (overrides) => Object.keys(overrides).length > 0
57
66
  );
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
67
  if (config.overrides.length === 0) {
89
68
  delete config.overrides;
90
69
  }
@@ -108,17 +87,7 @@ const cleanUpOxlintConfig = (config) => {
108
87
  }
109
88
  }
110
89
  }
111
- if (config.rules !== void 0 && Object.keys(config.rules).length === 0) {
112
- delete config.rules;
113
- }
114
- if ("files" in config) {
115
- if (config.plugins !== void 0 && Object.keys(config.plugins).length === 0) {
116
- delete config.plugins;
117
- }
118
- if (Object.keys(config).length === 1) {
119
- delete config.files;
120
- }
121
- } else {
90
+ if (!("files" in config)) {
122
91
  cleanUpDefaultTypeScriptOverridesForEslint(config);
123
92
  cleanUpUselessOverridesEntries(config);
124
93
  }
@@ -1,7 +1,8 @@
1
- import { OxlintConfigOrOverride, Reporter } from './types.js';
1
+ import { OxlintConfig, OxlintConfigOrOverride, Reporter } from './types.js';
2
2
  import { Linter } from 'eslint';
3
3
  export declare const ES_VERSIONS: number[];
4
4
  export declare const removeGlobalsWithAreCoveredByEnv: (config: OxlintConfigOrOverride) => void;
5
5
  export declare const transformBoolGlobalToString: (config: OxlintConfigOrOverride) => void;
6
6
  export declare const detectEnvironmentByGlobals: (config: OxlintConfigOrOverride) => void;
7
7
  export declare const transformEnvAndGlobals: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, reporter?: Reporter) => void;
8
+ export declare const cleanUpUselessOverridesEnv: (config: OxlintConfig) => void;
@@ -67,10 +67,10 @@ const transformBoolGlobalToString = (config) => {
67
67
  return;
68
68
  }
69
69
  for (const [entry, value] of Object.entries(config.globals)) {
70
- if (value === false) {
70
+ if (value === false || value === "readable") {
71
71
  config.globals[entry] = "readonly";
72
- } else if (value === true) {
73
- config.globals[entry] = "writable";
72
+ } else if (value === true || value === "writable") {
73
+ config.globals[entry] = "writeable";
74
74
  }
75
75
  }
76
76
  };
@@ -129,8 +129,29 @@ const transformEnvAndGlobals = (eslintConfig, targetConfig, reporter) => {
129
129
  }
130
130
  }
131
131
  };
132
+ const cleanUpUselessOverridesEnv = (config) => {
133
+ if (config.env === void 0 || config.overrides === void 0) {
134
+ return;
135
+ }
136
+ for (const override of config.overrides) {
137
+ if (override.env === void 0) {
138
+ continue;
139
+ }
140
+ for (const [overrideEnv, overrideEnvConfig] of Object.entries(
141
+ override.env
142
+ )) {
143
+ if (overrideEnv in config.env && config.env[overrideEnv] === overrideEnvConfig) {
144
+ delete override.env[overrideEnv];
145
+ }
146
+ }
147
+ if (Object.keys(override.env).length === 0) {
148
+ delete override.env;
149
+ }
150
+ }
151
+ };
132
152
  export {
133
153
  ES_VERSIONS,
154
+ cleanUpUselessOverridesEnv,
134
155
  detectEnvironmentByGlobals,
135
156
  removeGlobalsWithAreCoveredByEnv,
136
157
  transformBoolGlobalToString,
@@ -1,2 +1,3 @@
1
1
  declare const rules: string[];
2
+ export declare const nurseryRules: string[];
2
3
  export default rules;
@@ -6,9 +6,11 @@ const rules = [
6
6
  "default-param-last",
7
7
  "eqeqeq",
8
8
  "for-direction",
9
+ "func-style",
9
10
  "func-names",
10
11
  "getter-return",
11
12
  "guard-for-in",
13
+ "init-declarations",
12
14
  "max-classes-per-file",
13
15
  "max-lines",
14
16
  "max-params",
@@ -479,6 +481,7 @@ const rules = [
479
481
  "vitest/prefer-to-be-truthy",
480
482
  "vitest/require-local-test-context-for-concurrent-snapshots",
481
483
  "@typescript-eslint/default-param-last",
484
+ "@typescript-eslint/init-declarations",
482
485
  "@typescript-eslint/max-params",
483
486
  "@typescript-eslint/no-restricted-imports",
484
487
  "@typescript-eslint/no-array-constructor",
@@ -507,6 +510,7 @@ const rules = [
507
510
  "vitest/no-interpolation-in-snapshots",
508
511
  "vitest/no-restricted-jest-methods",
509
512
  "vitest/no-restricted-matchers",
513
+ "vitest/no-standalone-expect",
510
514
  "vitest/no-test-prefixes",
511
515
  "vitest/no-test-return-statement",
512
516
  "vitest/prefer-each",
@@ -515,6 +519,7 @@ const rules = [
515
519
  "vitest/prefer-expect-resolves",
516
520
  "vitest/prefer-hooks-in-order",
517
521
  "vitest/prefer-hooks-on-top",
522
+ "vitest/prefer-lowercase-title",
518
523
  "vitest/prefer-mock-promise-shorthand",
519
524
  "vitest/prefer-strict-equal",
520
525
  "vitest/prefer-to-have-length",
@@ -524,6 +529,22 @@ const rules = [
524
529
  "vitest/valid-describe-callback",
525
530
  "vitest/valid-expect"
526
531
  ];
532
+ const nurseryRules = [
533
+ "constructor-super",
534
+ "getter-return",
535
+ "no-restricted-imports",
536
+ "no-undef",
537
+ "no-unreachable",
538
+ "import/export",
539
+ "import/named",
540
+ "oxc/no-map-spread",
541
+ "promise/no-return-in-finally",
542
+ "react-hooks/exhaustive-deps",
543
+ "react/require-render-return",
544
+ "@typescript-eslint/consistent-type-imports",
545
+ "@typescript-eslint/no-restricted-imports"
546
+ ];
527
547
  export {
528
- rules as default
548
+ rules as default,
549
+ nurseryRules
529
550
  };
@@ -1,3 +1,3 @@
1
1
  import { Linter } from 'eslint';
2
2
  import { OxlintConfigOrOverride, Reporter } from './types.js';
3
- export declare const transformIgnorePatterns: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, reporter: Reporter) => void;
3
+ export declare const transformIgnorePatterns: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, reporter?: Reporter) => void;
@@ -46,7 +46,7 @@ const buildConfig = (configs, reporter) => {
46
46
  cleanUpOxlintConfig(oxlintConfig);
47
47
  return oxlintConfig;
48
48
  };
49
- const main = async (configs, reporter = void 0) => {
49
+ const main = async (configs, reporter) => {
50
50
  const resolved = await Promise.resolve(configs);
51
51
  return Array.isArray(resolved) ? buildConfig(resolved, reporter) : buildConfig([resolved], reporter);
52
52
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,6 @@
1
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;
2
+ import { OxlintConfig, OxlintConfigOrOverride, Reporter } from './types.js';
3
+ export declare const transformRuleEntry: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, reporter?: Reporter) => void;
4
4
  export declare const detectNeededRulesPlugins: (targetConfig: OxlintConfigOrOverride, reporter?: Reporter) => void;
5
+ export declare const cleanUpUselessOverridesPlugins: (config: OxlintConfig) => void;
6
+ export declare const cleanUpUselessOverridesRules: (config: OxlintConfig) => void;
@@ -1,4 +1,4 @@
1
- import rules from "./generated/rules.mjs";
1
+ import rules, { nurseryRules } from "./generated/rules.mjs";
2
2
  import { rulesPrefixesForPlugins } from "./constants.mjs";
3
3
  const isValueInSet = (value, validSet) => validSet.includes(value) || Array.isArray(value) && validSet.includes(value[0]);
4
4
  const isActiveValue = (value) => isValueInSet(value, ["error", "warn", 1, 2]);
@@ -11,6 +11,10 @@ const transformRuleEntry = (eslintConfig, targetConfig, reporter) => {
11
11
  }
12
12
  for (const [rule, config] of Object.entries(eslintConfig.rules)) {
13
13
  if (rules.includes(rule)) {
14
+ if (nurseryRules.includes(rule)) {
15
+ reporter !== void 0 && reporter(`unsupported rule, but in development: ${rule}`);
16
+ continue;
17
+ }
14
18
  targetConfig.rules[rule] = config;
15
19
  } else {
16
20
  if (isActiveValue(config)) {
@@ -44,7 +48,45 @@ const detectNeededRulesPlugins = (targetConfig, reporter) => {
44
48
  }
45
49
  }
46
50
  };
51
+ const cleanUpUselessOverridesPlugins = (config) => {
52
+ if (config.overrides === void 0) {
53
+ return;
54
+ }
55
+ if (config.plugins !== void 0) {
56
+ for (const override of config.overrides) {
57
+ if (override.plugins === void 0) {
58
+ continue;
59
+ }
60
+ override.plugins = override.plugins.filter(
61
+ (overridePlugin) => !config.plugins.includes(overridePlugin)
62
+ );
63
+ if (override.plugins.length === 0) {
64
+ delete override.plugins;
65
+ }
66
+ }
67
+ }
68
+ };
69
+ const cleanUpUselessOverridesRules = (config) => {
70
+ if (config.rules === void 0 || config.overrides === void 0) {
71
+ return;
72
+ }
73
+ for (const override of config.overrides) {
74
+ if (override.rules === void 0) {
75
+ continue;
76
+ }
77
+ for (const [rule, settings] of Object.entries(override.rules)) {
78
+ if (config.rules[rule] === settings) {
79
+ delete override.rules[rule];
80
+ }
81
+ }
82
+ if (Object.keys(override.rules).length === 0) {
83
+ delete override.rules;
84
+ }
85
+ }
86
+ };
47
87
  export {
88
+ cleanUpUselessOverridesPlugins,
89
+ cleanUpUselessOverridesRules,
48
90
  detectNeededRulesPlugins,
49
91
  transformRuleEntry
50
92
  };
@@ -21,5 +21,5 @@ export type OxlintConfig = {
21
21
  ignorePatterns?: OxlintConfigIgnorePatterns;
22
22
  };
23
23
  export type OxlintConfigOrOverride = OxlintConfig | OxlintConfigOverride;
24
- export type Reporter = ((warning: string) => void) | undefined;
24
+ export type Reporter = (warning: string) => void;
25
25
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oxlint/migrate",
3
- "version": "0.0.3",
4
- "description": "Generates a `.oxlintrc.json` from a existing eslint v9 configuration",
3
+ "version": "0.0.5",
4
+ "description": "Generates a `.oxlintrc.json` from a existing eslint flat config",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "oxlint-migrate": "./dist/bin/oxlint-migrate.mjs"
@@ -17,7 +17,7 @@
17
17
  "type-check": "tsc --noEmit",
18
18
  "test": "vitest",
19
19
  "build": "vite build",
20
- "manual-test": "pnpm build; chmod +x dist/bin/oxlint-migrate.mjs; npx . integration_test/projects/autoprefixer.eslint.config.mjs"
20
+ "manual-test": "pnpm build; chmod +x dist/bin/oxlint-migrate.mjs; npx ."
21
21
  },
22
22
  "files": [
23
23
  "dist/*",
@@ -33,21 +33,24 @@
33
33
  "license": "MIT",
34
34
  "devDependencies": {
35
35
  "@antfu/eslint-config": "^4.2.0",
36
- "@logux/eslint-config": "^53.5.1",
36
+ "@eslint/js": "^9.20.0",
37
+ "@logux/eslint-config": "^54.0.0",
37
38
  "@oxc-node/core": "^0.0.19",
38
- "@stylistic/eslint-plugin-ts": "^3.1.0",
39
+ "@stylistic/eslint-plugin-ts": "^4.0.0",
39
40
  "@types/eslint-config-prettier": "^6.11.3",
40
41
  "@types/node": "^22.13.4",
41
42
  "@vitest/coverage-v8": "^3.0.5",
42
43
  "eslint": "^9.20.1",
43
44
  "eslint-config-prettier": "^10.0.1",
44
45
  "eslint-plugin-header": "^3.1.1",
46
+ "eslint-plugin-jsdoc": "^50.6.3",
45
47
  "eslint-plugin-local": "^6.0.0",
46
48
  "eslint-plugin-oxlint": "^0.15.10",
47
49
  "eslint-plugin-regexp": "^2.7.0",
50
+ "eslint-plugin-unicorn": "^57.0.0",
48
51
  "husky": "^9.1.7",
49
52
  "lint-staged": "^15.4.3",
50
- "oxlint": "^0.15.10",
53
+ "oxlint": "^0.15.11",
51
54
  "prettier": "^3.5.1",
52
55
  "typescript": "^5.7.3",
53
56
  "typescript-eslint": "^8.24.0",
@@ -62,8 +65,5 @@
62
65
  "commander": "^13.1.0",
63
66
  "globals": "^15.15.0"
64
67
  },
65
- "peerDependencies": {
66
- "eslint": "^9"
67
- },
68
- "packageManager": "pnpm@9.15.0"
68
+ "packageManager": "pnpm@10.4.1"
69
69
  }