@oxlint/migrate 1.28.0 → 1.30.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
@@ -4,7 +4,7 @@
4
4
  [![NPM Version](https://img.shields.io/npm/v/%40oxlint%2Fmigrate)](https://www.npmjs.com/package/@oxlint/migrate)
5
5
  [![NPM Downloads](https://img.shields.io/npm/dm/%40oxlint%2Fmigrate)](https://www.npmjs.com/package/@oxlint/migrate)
6
6
 
7
- Generates a `.oxlintrc.json` from a existing eslint flat config.
7
+ Generates a `.oxlintrc.json` from an existing eslint flat config.
8
8
 
9
9
  ## Usage
10
10
 
@@ -2,7 +2,7 @@ import { glob } from "tinyglobby";
2
2
  const getAllProjectFiles = () => {
3
3
  return glob(
4
4
  [
5
- "**/*.{js,cjs,mjs,ts,cts,mts,vue,astro,svelte}",
5
+ "**/*.{js,cjs,mjs,ts,cts,mts,jsx,tsx,vue,astro,svelte}",
6
6
  "!**/node_modules/**",
7
7
  "!**/dist/**"
8
8
  ],
@@ -1,4 +1,4 @@
1
- const version = "1.28.0";
1
+ const version = "1.30.0";
2
2
  const packageJson = {
3
3
  version
4
4
  };
@@ -1,4 +1,4 @@
1
- import { removeGlobalsWithAreCoveredByEnv, transformBoolGlobalToString, ES_VERSIONS, cleanUpUselessOverridesEnv } from "./env_globals.mjs";
1
+ import { removeGlobalsWithAreCoveredByEnv, transformBoolGlobalToString, ES_VERSIONS, cleanUpUselessOverridesEnv, cleanUpSupersetEnvs } from "./env_globals.mjs";
2
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 = {
@@ -42,6 +42,7 @@ const cleanUpUselessOverridesEntries = (config) => {
42
42
  cleanUpUselessOverridesRules(config);
43
43
  cleanUpUselessOverridesPlugins(config);
44
44
  cleanUpUselessOverridesEnv(config);
45
+ cleanUpSupersetEnvs(config);
45
46
  if (config.overrides === void 0) {
46
47
  return;
47
48
  }
@@ -53,6 +54,8 @@ const cleanUpUselessOverridesEntries = (config) => {
53
54
  config.overrides = config.overrides.filter(
54
55
  (overrides) => Object.keys(overrides).length > 0
55
56
  );
57
+ mergeConsecutiveIdenticalOverrides(config);
58
+ mergeConsecutiveOverridesWithDifferingFiles(config);
56
59
  if (config.overrides.length === 0) {
57
60
  delete config.overrides;
58
61
  }
@@ -84,6 +87,68 @@ const cleanUpOxlintConfig = (config) => {
84
87
  cleanUpDisabledRootRules(config);
85
88
  }
86
89
  };
90
+ function mergeConsecutiveIdenticalOverrides(config) {
91
+ if (config.overrides === void 0) {
92
+ return;
93
+ }
94
+ if (config.overrides.length <= 1) {
95
+ return;
96
+ }
97
+ const mergedOverrides = [];
98
+ let i = 0;
99
+ while (i < config.overrides.length) {
100
+ const current = config.overrides[i];
101
+ if (i + 1 < config.overrides.length && isEqualDeep(current, config.overrides[i + 1])) {
102
+ mergedOverrides.push(current);
103
+ while (i + 1 < config.overrides.length && isEqualDeep(current, config.overrides[i + 1])) {
104
+ i++;
105
+ }
106
+ } else {
107
+ mergedOverrides.push(current);
108
+ }
109
+ i++;
110
+ }
111
+ config.overrides = mergedOverrides;
112
+ }
113
+ function mergeConsecutiveOverridesWithDifferingFiles(config) {
114
+ if (config.overrides === void 0) {
115
+ return;
116
+ }
117
+ if (config.overrides.length <= 1) {
118
+ return;
119
+ }
120
+ const mergedOverrides = [];
121
+ let i = 0;
122
+ while (i < config.overrides.length) {
123
+ const current = config.overrides[i];
124
+ const currentFiles = current.files;
125
+ const { files: _, ...currentWithoutFiles } = current;
126
+ let j = i + 1;
127
+ const filesToMerge = [...currentFiles];
128
+ while (j < config.overrides.length) {
129
+ const next = config.overrides[j];
130
+ const { files: __, ...nextWithoutFiles } = next;
131
+ if (isEqualDeep(currentWithoutFiles, nextWithoutFiles)) {
132
+ filesToMerge.push(...next.files);
133
+ j++;
134
+ } else {
135
+ break;
136
+ }
137
+ }
138
+ if (j > i + 1) {
139
+ const uniqueFiles = [...new Set(filesToMerge)];
140
+ mergedOverrides.push({
141
+ ...current,
142
+ files: uniqueFiles
143
+ });
144
+ i = j;
145
+ } else {
146
+ mergedOverrides.push(current);
147
+ i++;
148
+ }
149
+ }
150
+ config.overrides = mergedOverrides;
151
+ }
87
152
  export {
88
153
  cleanUpOxlintConfig
89
154
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -6,3 +6,11 @@ export declare const transformBoolGlobalToString: (config: OxlintConfigOrOverrid
6
6
  export declare const detectEnvironmentByGlobals: (config: OxlintConfigOrOverride) => void;
7
7
  export declare const transformEnvAndGlobals: (eslintConfig: Linter.Config, targetConfig: OxlintConfigOrOverride, options?: Options) => void;
8
8
  export declare const cleanUpUselessOverridesEnv: (config: OxlintConfig) => void;
9
+ /**
10
+ * Cleans up superset environments in the config and its overrides.
11
+ * If a superset environment is present, its subset environments are removed, e.g. all globals from `shared-node-browser` are also in `browser` and `node`.
12
+ *
13
+ * This also applies for overrides, where if a superset env is defined in the override or main config,
14
+ * the subset envs can be removed from the override if the override has the same value as the superset.
15
+ */
16
+ export declare const cleanUpSupersetEnvs: (config: OxlintConfig) => void;
@@ -21,6 +21,7 @@ const OTHER_SUPPORTED_ENVS = [
21
21
  "serviceworker",
22
22
  "amd",
23
23
  "applescript",
24
+ "astro",
24
25
  "atomtest",
25
26
  "commonjs",
26
27
  "embertest",
@@ -36,9 +37,11 @@ const OTHER_SUPPORTED_ENVS = [
36
37
  "prototypejs",
37
38
  "phantomjs",
38
39
  "shelljs",
40
+ "svelte",
39
41
  "webextensions",
40
42
  "qunit",
41
- "vitest"
43
+ "vitest",
44
+ "vue"
42
45
  ];
43
46
  const SUPPORTED_ESLINT_PARSERS = ["typescript-eslint/parser"];
44
47
  const normalizeGlobValue = (value) => {
@@ -79,6 +82,7 @@ const transformBoolGlobalToString = (config) => {
79
82
  }
80
83
  }
81
84
  };
85
+ const THRESHOLD_ENVS = ["browser", "node", "serviceworker", "worker"];
82
86
  const detectEnvironmentByGlobals = (config) => {
83
87
  if (config.globals === void 0) {
84
88
  return;
@@ -93,12 +97,14 @@ const detectEnvironmentByGlobals = (config) => {
93
97
  let search = Object.keys(entries);
94
98
  let matches = search.filter(
95
99
  (entry) => (
96
- // @ts-ignore -- we already checked for undefined
97
- entry in config.globals && // @ts-ignore -- filtering makes the key to any
100
+ // @ts-expect-error -- we already checked for undefined
101
+ entry in config.globals && // @ts-expect-error -- filtering makes the key to any
98
102
  normalizeGlobValue(config.globals[entry]) === entries[entry]
99
103
  )
100
104
  );
101
- if (search.length === matches.length) {
105
+ const useThreshold = THRESHOLD_ENVS.includes(env);
106
+ const withinThreshold = useThreshold && matches.length / search.length >= 0.97;
107
+ if (withinThreshold || !useThreshold && matches.length === search.length) {
102
108
  if (config.env === void 0) {
103
109
  config.env = {};
104
110
  }
@@ -108,11 +114,11 @@ const detectEnvironmentByGlobals = (config) => {
108
114
  };
109
115
  const transformEnvAndGlobals = (eslintConfig, targetConfig, options) => {
110
116
  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
117
+ // @ts-expect-error
112
118
  eslintConfig.languageOptions.parser.meta?.name
113
119
  )) {
114
120
  options?.reporter?.report(
115
- "special parser detected: " + // @ts-ignore
121
+ "special parser detected: " + // @ts-expect-error
116
122
  eslintConfig.languageOptions.parser.meta?.name
117
123
  );
118
124
  }
@@ -172,8 +178,53 @@ const cleanUpUselessOverridesEnv = (config) => {
172
178
  }
173
179
  }
174
180
  };
181
+ const SUPERSET_ENVS = {
182
+ node: ["nodeBuiltin", "shared-node-browser", "commonjs"],
183
+ browser: ["shared-node-browser"]
184
+ };
185
+ const cleanUpSupersetEnvs = (config) => {
186
+ if (config.env !== void 0) {
187
+ for (const [supersetEnv, subsetEnvs] of Object.entries(SUPERSET_ENVS)) {
188
+ if (!(supersetEnv in config.env)) {
189
+ continue;
190
+ }
191
+ for (const subsetEnv of subsetEnvs) {
192
+ if (config.env[subsetEnv] === config.env[supersetEnv]) {
193
+ delete config.env[subsetEnv];
194
+ }
195
+ }
196
+ }
197
+ }
198
+ if (config.overrides !== void 0) {
199
+ for (const override of config.overrides) {
200
+ if (override.env === void 0) {
201
+ continue;
202
+ }
203
+ for (const [supersetEnv, subsetEnvs] of Object.entries(SUPERSET_ENVS)) {
204
+ const supersetInOverride = supersetEnv in override.env;
205
+ const supersetInMain = config.env !== void 0 && supersetEnv in config.env;
206
+ for (const subsetEnv of subsetEnvs) {
207
+ if (!(subsetEnv in override.env)) {
208
+ continue;
209
+ }
210
+ if (supersetInOverride && override.env[subsetEnv] === override.env[supersetEnv]) {
211
+ delete override.env[subsetEnv];
212
+ continue;
213
+ }
214
+ if (supersetInMain && !supersetInOverride && config.env[supersetEnv] === override.env[subsetEnv]) {
215
+ delete override.env[subsetEnv];
216
+ }
217
+ }
218
+ }
219
+ if (Object.keys(override.env).length === 0) {
220
+ delete override.env;
221
+ }
222
+ }
223
+ }
224
+ };
175
225
  export {
176
226
  ES_VERSIONS,
227
+ cleanUpSupersetEnvs,
177
228
  cleanUpUselessOverridesEnv,
178
229
  detectEnvironmentByGlobals,
179
230
  removeGlobalsWithAreCoveredByEnv,
@@ -53,6 +53,7 @@ const pedanticRules = [
53
53
  "@typescript-eslint/no-unsafe-return",
54
54
  "@typescript-eslint/only-throw-error",
55
55
  "@typescript-eslint/prefer-enum-initializers",
56
+ "@typescript-eslint/prefer-includes",
56
57
  "@typescript-eslint/prefer-promise-reject-errors",
57
58
  "@typescript-eslint/prefer-ts-expect-error",
58
59
  "@typescript-eslint/related-getter-setter-pairs",
@@ -251,6 +252,8 @@ const styleRules = [
251
252
  "unicorn/numeric-separators-style",
252
253
  "unicorn/prefer-classlist-toggle",
253
254
  "unicorn/prefer-class-fields",
255
+ "unicorn/prefer-bigint-literals",
256
+ "unicorn/prefer-response-static-json",
254
257
  "unicorn/prefer-global-this",
255
258
  "unicorn/prefer-object-from-entries",
256
259
  "unicorn/prefer-array-index-of",
@@ -6,8 +6,8 @@ const allRules = Object.values(rules).flat();
6
6
  const isValueInSet = (value, validSet) => validSet.includes(value) || Array.isArray(value) && validSet.includes(value[0]);
7
7
  const isActiveValue = (value) => isValueInSet(value, ["error", "warn", 1, 2]);
8
8
  const isOffValue = (value) => isValueInSet(value, ["off", 0]);
9
- const isErrorValue = (value) => isValueInSet(value, ["error", 1]);
10
- const isWarnValue = (value) => isValueInSet(value, ["warn", 2]);
9
+ const isWarnValue = (value) => isValueInSet(value, ["warn", 1]);
10
+ const isErrorValue = (value) => isValueInSet(value, ["error", 2]);
11
11
  const normalizeSeverityValue = (value) => {
12
12
  if (value === void 0) {
13
13
  return value;
@@ -120,17 +120,42 @@ const cleanUpUselessOverridesRules = (config) => {
120
120
  if (config.rules === void 0 || config.overrides === void 0) {
121
121
  return;
122
122
  }
123
- for (const override of config.overrides) {
124
- if (override.rules === void 0) {
123
+ const filesPatternMap = /* @__PURE__ */ new Map();
124
+ for (const [i, override] of config.overrides.entries()) {
125
+ if (override.files === void 0) {
125
126
  continue;
126
127
  }
127
- for (const [rule, settings] of Object.entries(override.rules)) {
128
- if (config.rules[rule] === settings) {
129
- delete override.rules[rule];
128
+ const filesKey = JSON.stringify(override.files);
129
+ let entry = filesPatternMap.get(filesKey);
130
+ if (!entry) {
131
+ entry = {
132
+ firstIndex: i,
133
+ finalRules: {},
134
+ indicesToRemove: []
135
+ };
136
+ filesPatternMap.set(filesKey, entry);
137
+ } else {
138
+ entry.indicesToRemove.push(i);
139
+ }
140
+ if (override.rules) {
141
+ Object.assign(entry.finalRules, override.rules);
142
+ }
143
+ }
144
+ for (const entry of filesPatternMap.values()) {
145
+ const firstOverride = config.overrides[entry.firstIndex];
146
+ firstOverride.rules = entry.finalRules;
147
+ if (firstOverride.rules) {
148
+ for (const [rule, settings] of Object.entries(firstOverride.rules)) {
149
+ if (config.rules[rule] === settings) {
150
+ delete firstOverride.rules[rule];
151
+ }
152
+ }
153
+ if (Object.keys(firstOverride.rules).length === 0) {
154
+ delete firstOverride.rules;
130
155
  }
131
156
  }
132
- if (Object.keys(override.rules).length === 0) {
133
- delete override.rules;
157
+ for (const indexToRemove of entry.indicesToRemove) {
158
+ delete config.overrides[indexToRemove].rules;
134
159
  }
135
160
  }
136
161
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxlint/migrate",
3
- "version": "1.28.0",
3
+ "version": "1.30.0",
4
4
  "description": "Generates a `.oxlintrc.json` from a existing eslint flat config",
5
5
  "type": "module",
6
6
  "bin": {
@@ -63,14 +63,14 @@
63
63
  "eslint-plugin-react-hooks": "^7.0.1",
64
64
  "eslint-plugin-react-perf": "^3.3.3",
65
65
  "eslint-plugin-regexp": "^2.9.0",
66
- "eslint-plugin-tsdoc": "^0.4.0",
66
+ "eslint-plugin-tsdoc": "^0.5.0",
67
67
  "eslint-plugin-unicorn": "^62.0.0",
68
68
  "husky": "^9.1.7",
69
69
  "jiti": "^2.4.2",
70
70
  "lint-staged": "^16.1.2",
71
71
  "next": "^16.0.0",
72
- "oxlint": "^1.28.0",
73
- "oxlint-tsgolint": "^0.2.0",
72
+ "oxlint": "^1.30.0",
73
+ "oxlint-tsgolint": "^0.8.0",
74
74
  "prettier": "^3.6.1",
75
75
  "typescript": "^5.8.3",
76
76
  "typescript-eslint": "^8.35.0",
@@ -84,11 +84,11 @@
84
84
  "dependencies": {
85
85
  "commander": "^14.0.0",
86
86
  "globals": "^16.3.0",
87
- "oxc-parser": "^0.96.0",
87
+ "oxc-parser": "^0.98.0",
88
88
  "tinyglobby": "^0.2.14"
89
89
  },
90
90
  "peerDependencies": {
91
91
  "jiti": "*"
92
92
  },
93
- "packageManager": "pnpm@10.21.0"
93
+ "packageManager": "pnpm@10.23.0"
94
94
  }