@oxlint/migrate 1.56.0 → 1.58.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
@@ -114,8 +114,4 @@ Depending on how this is implemented by the given config, these behaviors may no
114
114
 
115
115
  The JS Plugins API supports almost all ESLint v9+ plugins for linting JS/TS/JSX/TSX files, but there are still some minor holes in support. See the [JS Plugins documentation](https://oxc.rs/docs/guide/usage/linter/js-plugins.html) for specifics.
116
116
 
117
- For example, if you currently use `eslint-plugin-prettier`, it will not work as a JS Plugin, as we do not support custom parsers for JS Plugins. To replace the functionality of `eslint-plugin-prettier`, you can use `prettier --check` in CI and/or your git pre-commit hooks to ensure code formatting is enforced.
118
-
119
- You could also consider [replacing Prettier with Oxfmt](https://oxc.rs/docs/guide/usage/formatter/migrate-from-prettier.html).
120
-
121
- Note that `eslint-config-prettier` is different from the prettier plugin, and _will_ be migrated fine, as it's just a config to disable formatting-related ESLint rules, not an actual plugin.
117
+ For example, if you currently use `eslint-plugin-svelte`, only some of its rules will work via JS Plugin, as Oxlint does not yet fully support custom file formats like `.svelte`. This means that Oxlint will only be able to lint the script blocks in your `.svelte` files, and not the template blocks where many of the `eslint-plugin-svelte` rules apply.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as nurseryRules, i as buildUnsupportedRuleExplanations, n as preFixForJsPlugins, o as rules_exports, r as isOffValue, t as main } from "../src-DIfNUkJH.mjs";
2
+ import { a as nurseryRules, i as buildUnsupportedRuleExplanations, n as preFixForJsPlugins, o as rules_exports, r as isOffValue, s as normalizeRuleToCanonical, t as main } from "../src-BLIW50Ng.mjs";
3
3
  import { program } from "commander";
4
4
  import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
5
  import path from "node:path";
@@ -30,10 +30,11 @@ const loadESLintConfig = async (filePath) => {
30
30
  };
31
31
  //#endregion
32
32
  //#region package.json
33
- var version = "1.56.0";
33
+ var version = "1.58.0";
34
34
  //#endregion
35
35
  //#region src/walker/comments/replaceRuleDirectiveComment.ts
36
- const allRules = Object.values(rules_exports).flat();
36
+ const allRulesSet = new Set(Object.values(rules_exports).flat());
37
+ const nurseryRulesSet = new Set(nurseryRules);
37
38
  function replaceRuleDirectiveComment(comment, type, options) {
38
39
  const originalComment = comment;
39
40
  comment = comment.split(" -- ")[0].trimStart();
@@ -51,14 +52,13 @@ function replaceRuleDirectiveComment(comment, type, options) {
51
52
  comment = comment.trimStart();
52
53
  if (comment.length === 0) return originalComment;
53
54
  while (comment.length) {
54
- let foundRule = false;
55
- for (const rule of allRules) if (comment.startsWith(rule)) {
56
- if (!options.withNursery && nurseryRules.includes(rule)) continue;
57
- foundRule = true;
58
- comment = comment.substring(rule.length).trimStart();
59
- break;
60
- }
61
- if (!foundRule) return originalComment;
55
+ const commaIdx = comment.indexOf(",");
56
+ const candidateEnd = commaIdx === -1 ? comment.length : commaIdx;
57
+ const candidate = comment.substring(0, candidateEnd).trimEnd();
58
+ const canonical = normalizeRuleToCanonical(candidate);
59
+ if (!allRulesSet.has(canonical)) return originalComment;
60
+ if (!options.withNursery && nurseryRulesSet.has(canonical)) return originalComment;
61
+ comment = comment.substring(candidate.length).trimStart();
62
62
  if (!comment.length) break;
63
63
  if (!comment.startsWith(", ")) return originalComment;
64
64
  comment = comment.substring(1).trimStart();
@@ -1,4 +1,4 @@
1
- //#region node_modules/.pnpm/oxlint@1.56.0_oxlint-tsgolint@0.16.0/node_modules/oxlint/dist/index.d.ts
1
+ //#region node_modules/.pnpm/oxlint@1.58.0_oxlint-tsgolint@0.18.1/node_modules/oxlint/dist/index.d.ts
2
2
  //#region src-js/package/config.generated.d.ts
3
3
  type AllowWarnDeny = ("allow" | "off" | "warn" | "error" | "deny") | number;
4
4
  type GlobalValue = "readonly" | "writable" | "off";
@@ -37,7 +37,7 @@ type ExternalPluginEntry = string | {
37
37
  type GlobSet = string[];
38
38
  type LintPluginOptionsSchema = "eslint" | "react" | "unicorn" | "typescript" | "oxc" | "import" | "jsdoc" | "jest" | "vitest" | "jsx-a11y" | "nextjs" | "react-perf" | "promise" | "node" | "vue";
39
39
  type LintPlugins = LintPluginOptionsSchema[];
40
- type DummyRule = AllowWarnDeny | unknown[];
40
+ type DummyRule = AllowWarnDeny | [AllowWarnDeny, ...unknown[]];
41
41
  type OxlintOverrides = OxlintOverride[];
42
42
  type TagNamePreference = string | {
43
43
  message: string;
@@ -1,2 +1,2 @@
1
- import { t as main } from "../src-DIfNUkJH.mjs";
1
+ import { t as main } from "../src-BLIW50Ng.mjs";
2
2
  export { main as default };
@@ -165,6 +165,223 @@ const cleanUpSupersetEnvs = (config) => {
165
165
  }
166
166
  };
167
167
  //#endregion
168
+ //#region src/constants.ts
169
+ const rulesPrefixesForPlugins = {
170
+ import: "import",
171
+ "import-x": "import",
172
+ jest: "jest",
173
+ jsdoc: "jsdoc",
174
+ "jsx-a11y": "jsx-a11y",
175
+ "@next/next": "nextjs",
176
+ node: "node",
177
+ n: "node",
178
+ promise: "promise",
179
+ react: "react",
180
+ "react-perf": "react-perf",
181
+ "react-hooks": "react",
182
+ "react-refresh": "react",
183
+ "@typescript-eslint": "typescript",
184
+ unicorn: "unicorn",
185
+ vitest: "vitest",
186
+ vue: "vue"
187
+ };
188
+ /**
189
+ * Normalizes an ESLint-style rule name to its canonical Oxlint form.
190
+ * e.g. "@typescript-eslint/no-floating-promises" → "typescript/no-floating-promises"
191
+ * "react-hooks/exhaustive-deps" → "react/exhaustive-deps"
192
+ * "@next/next/inline-script-id" → "nextjs/inline-script-id"
193
+ * "no-unused-vars" → "no-unused-vars" (unchanged for unprefixed rules)
194
+ */
195
+ function normalizeRuleToCanonical(rule) {
196
+ for (const [prefix, plugin] of Object.entries(rulesPrefixesForPlugins)) if (prefix !== plugin && rule.startsWith(`${prefix}/`)) return `${plugin}/${rule.slice(prefix.length + 1)}`;
197
+ return rule;
198
+ }
199
+ const eslintRulesToTypescriptEquivalents = {
200
+ "dot-notation": "@typescript-eslint/dot-notation",
201
+ "consistent-return": "@typescript-eslint/consistent-return"
202
+ };
203
+ const typescriptRulesExtendEslintRules = [
204
+ "class-methods-use-this",
205
+ "default-param-last",
206
+ "init-declarations",
207
+ "max-params",
208
+ "no-array-constructor",
209
+ "no-dupe-class-members",
210
+ "no-empty-function",
211
+ "no-invalid-this",
212
+ "no-loop-func",
213
+ "no-loss-of-precision",
214
+ "no-magic-numbers",
215
+ "no-redeclare",
216
+ "no-restricted-imports",
217
+ "no-shadow",
218
+ "no-unused-expressions",
219
+ "no-unused-vars",
220
+ "no-use-before-define",
221
+ "no-useless-constructor"
222
+ ];
223
+ //#endregion
224
+ //#region src/jsPlugins.ts
225
+ const ignorePlugins = new Set([
226
+ ...Object.keys(rulesPrefixesForPlugins),
227
+ ...Object.values(rulesPrefixesForPlugins),
228
+ "local"
229
+ ]);
230
+ const tryResolvePackage = (packageName) => {
231
+ try {
232
+ import.meta.resolve(packageName);
233
+ return true;
234
+ } catch {
235
+ return false;
236
+ }
237
+ };
238
+ const pluginNameCache = /* @__PURE__ */ new Map();
239
+ /**
240
+ * Resolves the npm package name for an ESLint plugin given its scope name.
241
+ *
242
+ * For scoped plugin names (starting with `@`), the mapping is unambiguous:
243
+ * - `@scope` -> `@scope/eslint-plugin`
244
+ * - `@scope/sub` -> `@scope/eslint-plugin-sub`
245
+ *
246
+ * For non-scoped names, the npm package could follow either convention:
247
+ * - `eslint-plugin-{name}` (e.g. `eslint-plugin-mocha`)
248
+ * - `@{name}/eslint-plugin` (e.g. `@e18e/eslint-plugin`)
249
+ *
250
+ * We try to resolve both candidates against the installed packages and
251
+ * use the one that is actually present, falling back to the standard
252
+ * `eslint-plugin-{name}` convention when neither can be resolved.
253
+ */
254
+ const resolveEslintPluginName = (pluginName) => {
255
+ const cached = pluginNameCache.get(pluginName);
256
+ if (cached !== void 0) return cached;
257
+ let result;
258
+ if (pluginName.startsWith("@")) {
259
+ const [scope, maybeSub] = pluginName.split("/");
260
+ if (maybeSub) result = `${scope}/eslint-plugin-${maybeSub}`;
261
+ else result = `${scope}/eslint-plugin`;
262
+ } else {
263
+ const standardName = `eslint-plugin-${pluginName}`;
264
+ const scopedName = `@${pluginName}/eslint-plugin`;
265
+ if (tryResolvePackage(standardName)) result = standardName;
266
+ else if (tryResolvePackage(scopedName)) result = scopedName;
267
+ else result = standardName;
268
+ }
269
+ pluginNameCache.set(pluginName, result);
270
+ return result;
271
+ };
272
+ const extractPluginId = (ruleId) => {
273
+ const firstSlash = ruleId.indexOf("/");
274
+ if (firstSlash === -1) return;
275
+ if (ruleId.startsWith("@")) {
276
+ const secondSlash = ruleId.indexOf("/", firstSlash + 1);
277
+ if (secondSlash !== -1) return ruleId.substring(0, secondSlash);
278
+ }
279
+ return ruleId.substring(0, firstSlash);
280
+ };
281
+ const isIgnoredPluginRule = (ruleId) => {
282
+ const pluginName = extractPluginId(ruleId);
283
+ if (pluginName === void 0) return true;
284
+ return ignorePlugins.has(pluginName);
285
+ };
286
+ /**
287
+ * Derives the npm package name for a plugin from its `meta.name` field.
288
+ *
289
+ * If `meta.name` already looks like a full npm package name (contains
290
+ * "eslint-plugin"), it is returned as-is. Otherwise it is fed through
291
+ * {@link resolveEslintPluginName} for the usual heuristic resolution.
292
+ */
293
+ const resolveFromMetaName = (metaName) => {
294
+ if (metaName.includes("eslint-plugin")) return metaName;
295
+ return resolveEslintPluginName(metaName);
296
+ };
297
+ /**
298
+ * Derives the rule-ID prefix that an npm package exposes.
299
+ *
300
+ * Examples:
301
+ * `eslint-plugin-react-dom` -> `react-dom`
302
+ * `eslint-plugin-mocha` -> `mocha`
303
+ * `@stylistic/eslint-plugin` -> `@stylistic`
304
+ * `@stylistic/eslint-plugin-ts` -> `@stylistic/ts`
305
+ */
306
+ const deriveRulePrefix = (packageName) => {
307
+ if (packageName.startsWith("@")) {
308
+ const slashIdx = packageName.indexOf("/");
309
+ const scope = packageName.substring(0, slashIdx);
310
+ const rest = packageName.substring(slashIdx + 1);
311
+ if (rest === "eslint-plugin") return scope;
312
+ if (rest.startsWith("eslint-plugin-")) return `${scope}/${rest.substring(14)}`;
313
+ return packageName;
314
+ }
315
+ if (packageName.startsWith("eslint-plugin-")) return packageName.substring(14);
316
+ return packageName;
317
+ };
318
+ /**
319
+ * Resolves the canonical rule name for a jsPlugin rule.
320
+ *
321
+ * When a plugin is registered under an alias (e.g. `@eslint-react/dom`) but
322
+ * its `meta.name` reveals a different canonical package (`eslint-plugin-react-dom`),
323
+ * the rule must be rewritten so that oxlint can match it to the loaded plugin.
324
+ *
325
+ * For example:
326
+ * `@eslint-react/dom/no-find-dom-node` -> `react-dom/no-find-dom-node`
327
+ */
328
+ const resolveJsPluginRuleName = (rule, plugins) => {
329
+ const pluginName = extractPluginId(rule);
330
+ if (pluginName === void 0) return rule;
331
+ const metaName = plugins?.[pluginName]?.meta?.name;
332
+ if (!metaName || !metaName.includes("eslint-plugin")) return rule;
333
+ const canonicalPrefix = deriveRulePrefix(metaName);
334
+ if (canonicalPrefix === pluginName) return rule;
335
+ return `${canonicalPrefix}/${rule.substring(pluginName.length + 1)}`;
336
+ };
337
+ const enableJsPluginRule = (targetConfig, rule, ruleEntry, plugins) => {
338
+ const pluginName = extractPluginId(rule);
339
+ if (pluginName === void 0) return false;
340
+ if (ignorePlugins.has(pluginName)) return false;
341
+ if (targetConfig.jsPlugins === void 0 || targetConfig.jsPlugins === null) targetConfig.jsPlugins = [];
342
+ const metaName = plugins?.[pluginName]?.meta?.name;
343
+ const eslintPluginName = metaName ? resolveFromMetaName(metaName) : resolveEslintPluginName(pluginName);
344
+ if (!targetConfig.jsPlugins.includes(eslintPluginName)) targetConfig.jsPlugins.push(eslintPluginName);
345
+ const resolvedRule = resolveJsPluginRuleName(rule, plugins);
346
+ targetConfig.rules = targetConfig.rules ?? {};
347
+ targetConfig.rules[resolvedRule] = ruleEntry;
348
+ return true;
349
+ };
350
+ /**
351
+ * Returns true if any rule name matches the given jsPlugin package.
352
+ *
353
+ * Handles aliased plugins where the ESLint registration name differs from the
354
+ * canonical prefix derived from the npm package name:
355
+ * - `@e18e/eslint-plugin` → prefix `@e18e`, but rules may use `e18e/`
356
+ * - `@eslint/eslint-plugin-markdown` → prefix `@eslint/markdown`, but rules
357
+ * may use `markdown/`
358
+ */
359
+ const hasRulesForPlugin = (ruleNames, pluginPackage) => {
360
+ const prefix = deriveRulePrefix(pluginPackage);
361
+ if (ruleNames.some((rule) => rule.startsWith(`${prefix}/`))) return true;
362
+ if (prefix.startsWith("@")) {
363
+ const slashIdx = prefix.indexOf("/");
364
+ const unscoped = slashIdx === -1 ? prefix.substring(1) : prefix.substring(slashIdx + 1);
365
+ return ruleNames.some((rule) => rule.startsWith(`${unscoped}/`));
366
+ }
367
+ return false;
368
+ };
369
+ /**
370
+ * Removes jsPlugin entries that have no corresponding rules left in the config.
371
+ *
372
+ * This can happen when an earlier ESLint config enables a plugin rule (adding the
373
+ * jsPlugin) but a later config (e.g. eslint-config-prettier) turns all of that
374
+ * plugin's rules off (deleting them from the rules object).
375
+ */
376
+ const cleanUpUnusedJsPlugins = (config) => {
377
+ if (config.jsPlugins === void 0 || config.jsPlugins === null || config.jsPlugins.length === 0) return;
378
+ const ruleNames = Object.keys(config.rules ?? {});
379
+ config.jsPlugins = config.jsPlugins.filter((entry) => {
380
+ return hasRulesForPlugin(ruleNames, typeof entry === "string" ? entry : entry.specifier);
381
+ });
382
+ if (config.jsPlugins.length === 0) delete config.jsPlugins;
383
+ };
384
+ //#endregion
168
385
  //#region src/generated/rules.ts
169
386
  var rules_exports = /* @__PURE__ */ __exportAll({
170
387
  correctnessRules: () => correctnessRules,
@@ -222,31 +439,31 @@ const pedanticRules = [
222
439
  "react/jsx-no-target-blank",
223
440
  "react/jsx-no-useless-fragment",
224
441
  "react/no-unescaped-entities",
225
- "react-hooks/rules-of-hooks",
226
- "@typescript-eslint/ban-ts-comment",
227
- "@typescript-eslint/ban-types",
228
- "@typescript-eslint/no-confusing-void-expression",
229
- "@typescript-eslint/no-deprecated",
230
- "@typescript-eslint/no-misused-promises",
231
- "@typescript-eslint/no-mixed-enums",
232
- "@typescript-eslint/no-unsafe-argument",
233
- "@typescript-eslint/no-unsafe-assignment",
234
- "@typescript-eslint/no-unsafe-call",
235
- "@typescript-eslint/no-unsafe-function-type",
236
- "@typescript-eslint/no-unsafe-member-access",
237
- "@typescript-eslint/no-unsafe-return",
238
- "@typescript-eslint/only-throw-error",
239
- "@typescript-eslint/prefer-enum-initializers",
240
- "@typescript-eslint/prefer-includes",
241
- "@typescript-eslint/prefer-nullish-coalescing",
242
- "@typescript-eslint/prefer-promise-reject-errors",
243
- "@typescript-eslint/prefer-ts-expect-error",
244
- "@typescript-eslint/related-getter-setter-pairs",
245
- "@typescript-eslint/require-await",
246
- "@typescript-eslint/restrict-plus-operands",
247
- "@typescript-eslint/return-await",
248
- "@typescript-eslint/strict-boolean-expressions",
249
- "@typescript-eslint/switch-exhaustiveness-check",
442
+ "react/rules-of-hooks",
443
+ "typescript/ban-ts-comment",
444
+ "typescript/ban-types",
445
+ "typescript/no-confusing-void-expression",
446
+ "typescript/no-deprecated",
447
+ "typescript/no-misused-promises",
448
+ "typescript/no-mixed-enums",
449
+ "typescript/no-unsafe-argument",
450
+ "typescript/no-unsafe-assignment",
451
+ "typescript/no-unsafe-call",
452
+ "typescript/no-unsafe-function-type",
453
+ "typescript/no-unsafe-member-access",
454
+ "typescript/no-unsafe-return",
455
+ "typescript/only-throw-error",
456
+ "typescript/prefer-enum-initializers",
457
+ "typescript/prefer-includes",
458
+ "typescript/prefer-nullish-coalescing",
459
+ "typescript/prefer-promise-reject-errors",
460
+ "typescript/prefer-ts-expect-error",
461
+ "typescript/related-getter-setter-pairs",
462
+ "typescript/require-await",
463
+ "typescript/restrict-plus-operands",
464
+ "typescript/return-await",
465
+ "typescript/strict-boolean-expressions",
466
+ "typescript/switch-exhaustiveness-check",
250
467
  "unicorn/consistent-assert",
251
468
  "unicorn/consistent-empty-array-spread",
252
469
  "unicorn/escape-case",
@@ -291,11 +508,10 @@ const pedanticRules = [
291
508
  "unicorn/prefer-top-level-await",
292
509
  "unicorn/prefer-type-error",
293
510
  "unicorn/require-number-to-fixed-digits-argument",
294
- "@typescript-eslint/no-array-constructor",
295
- "@typescript-eslint/no-loop-func",
511
+ "typescript/no-array-constructor",
512
+ "typescript/no-loop-func",
296
513
  "unicorn/no-negated-condition",
297
- "@typescript-eslint/no-redeclare",
298
- "import-x/max-dependencies",
514
+ "typescript/no-redeclare",
299
515
  "vitest/no-conditional-in-test"
300
516
  ];
301
517
  const styleRules = [
@@ -420,26 +636,31 @@ const styleRules = [
420
636
  "react/prefer-es6-class",
421
637
  "react/self-closing-comp",
422
638
  "react/state-in-constructor",
423
- "@typescript-eslint/adjacent-overload-signatures",
424
- "@typescript-eslint/array-type",
425
- "@typescript-eslint/ban-tslint-comment",
426
- "@typescript-eslint/class-literal-property-style",
427
- "@typescript-eslint/consistent-generic-constructors",
428
- "@typescript-eslint/consistent-indexed-object-style",
429
- "@typescript-eslint/consistent-type-assertions",
430
- "@typescript-eslint/consistent-type-definitions",
431
- "@typescript-eslint/consistent-type-imports",
432
- "@typescript-eslint/no-empty-interface",
433
- "@typescript-eslint/no-inferrable-types",
434
- "@typescript-eslint/parameter-properties",
435
- "@typescript-eslint/prefer-for-of",
436
- "@typescript-eslint/prefer-function-type",
437
- "@typescript-eslint/prefer-reduce-type-parameter",
438
- "@typescript-eslint/prefer-return-this-type",
439
- "@typescript-eslint/unified-signatures",
639
+ "typescript/adjacent-overload-signatures",
640
+ "typescript/array-type",
641
+ "typescript/ban-tslint-comment",
642
+ "typescript/class-literal-property-style",
643
+ "typescript/consistent-generic-constructors",
644
+ "typescript/consistent-indexed-object-style",
645
+ "typescript/consistent-type-assertions",
646
+ "typescript/consistent-type-definitions",
647
+ "typescript/consistent-type-imports",
648
+ "typescript/no-empty-interface",
649
+ "typescript/no-inferrable-types",
650
+ "typescript/parameter-properties",
651
+ "typescript/prefer-find",
652
+ "typescript/prefer-for-of",
653
+ "typescript/prefer-function-type",
654
+ "typescript/prefer-readonly",
655
+ "typescript/prefer-reduce-type-parameter",
656
+ "typescript/prefer-regexp-exec",
657
+ "typescript/prefer-return-this-type",
658
+ "typescript/prefer-string-starts-ends-with",
659
+ "typescript/unified-signatures",
440
660
  "unicorn/catch-error-name",
441
661
  "unicorn/consistent-date-clone",
442
662
  "unicorn/consistent-existence-index-check",
663
+ "unicorn/custom-error-definition",
443
664
  "unicorn/empty-brace-spaces",
444
665
  "unicorn/error-message",
445
666
  "unicorn/filename-case",
@@ -484,11 +705,13 @@ const styleRules = [
484
705
  "vitest/consistent-vitest-vi",
485
706
  "vitest/no-import-node-test",
486
707
  "vitest/no-importing-vitest-globals",
708
+ "vitest/prefer-called-exactly-once-with",
487
709
  "vitest/prefer-called-once",
488
710
  "vitest/prefer-called-times",
489
711
  "vitest/prefer-describe-function-title",
490
712
  "vitest/prefer-expect-type-of",
491
713
  "vitest/prefer-import-in-mock",
714
+ "vitest/prefer-strict-boolean-matchers",
492
715
  "vitest/prefer-to-be-falsy",
493
716
  "vitest/prefer-to-be-object",
494
717
  "vitest/prefer-to-be-truthy",
@@ -496,22 +719,10 @@ const styleRules = [
496
719
  "vue/define-props-declaration",
497
720
  "vue/define-props-destructuring",
498
721
  "vue/require-typed-ref",
499
- "@typescript-eslint/default-param-last",
500
- "@typescript-eslint/init-declarations",
501
- "@typescript-eslint/max-params",
502
- "@typescript-eslint/no-magic-numbers",
503
- "import-x/consistent-type-specifier-style",
504
- "import-x/exports-last",
505
- "import-x/first",
506
- "import-x/group-exports",
507
- "import-x/no-anonymous-default-export",
508
- "import-x/no-duplicates",
509
- "import-x/no-mutable-exports",
510
- "import-x/no-named-default",
511
- "import-x/no-named-export",
512
- "import-x/no-namespace",
513
- "import-x/no-nodejs-modules",
514
- "import-x/prefer-default-export",
722
+ "typescript/default-param-last",
723
+ "typescript/init-declarations",
724
+ "typescript/max-params",
725
+ "typescript/no-magic-numbers",
515
726
  "vitest/consistent-test-it",
516
727
  "vitest/max-expects",
517
728
  "vitest/max-nested-describe",
@@ -541,12 +752,11 @@ const styleRules = [
541
752
  "vitest/prefer-strict-equal",
542
753
  "vitest/prefer-to-be",
543
754
  "vitest/prefer-to-contain",
755
+ "vitest/prefer-to-have-been-called-times",
544
756
  "vitest/prefer-to-have-length",
545
757
  "vitest/prefer-todo",
546
758
  "vitest/require-hook",
547
- "vitest/require-top-level-describe",
548
- "n/global-require",
549
- "n/no-exports-assign"
759
+ "vitest/require-top-level-describe"
550
760
  ];
551
761
  const suspiciousRules = [
552
762
  "block-scoped-var",
@@ -576,15 +786,15 @@ const suspiciousRules = [
576
786
  "react/no-namespace",
577
787
  "react/react-in-jsx-scope",
578
788
  "react/style-prop-object",
579
- "@typescript-eslint/no-confusing-non-null-assertion",
580
- "@typescript-eslint/no-extraneous-class",
581
- "@typescript-eslint/no-unnecessary-boolean-literal-compare",
582
- "@typescript-eslint/no-unnecessary-template-expression",
583
- "@typescript-eslint/no-unnecessary-type-arguments",
584
- "@typescript-eslint/no-unnecessary-type-assertion",
585
- "@typescript-eslint/no-unnecessary-type-constraint",
586
- "@typescript-eslint/no-unsafe-enum-comparison",
587
- "@typescript-eslint/no-unsafe-type-assertion",
789
+ "typescript/no-confusing-non-null-assertion",
790
+ "typescript/no-extraneous-class",
791
+ "typescript/no-unnecessary-boolean-literal-compare",
792
+ "typescript/no-unnecessary-template-expression",
793
+ "typescript/no-unnecessary-type-arguments",
794
+ "typescript/no-unnecessary-type-assertion",
795
+ "typescript/no-unnecessary-type-constraint",
796
+ "typescript/no-unsafe-enum-comparison",
797
+ "typescript/no-unsafe-type-assertion",
588
798
  "unicorn/consistent-function-scoping",
589
799
  "unicorn/no-accessor-recursion",
590
800
  "unicorn/no-array-reverse",
@@ -595,14 +805,8 @@ const suspiciousRules = [
595
805
  "unicorn/require-post-message-target-origin",
596
806
  "vue/no-required-prop-with-default",
597
807
  "vue/require-default-export",
598
- "@typescript-eslint/no-shadow",
599
- "@typescript-eslint/no-useless-constructor",
600
- "import-x/no-absolute-path",
601
- "import-x/no-empty-named-blocks",
602
- "import-x/no-named-as-default",
603
- "import-x/no-named-as-default-member",
604
- "import-x/no-self-import",
605
- "import-x/no-unassigned-import",
808
+ "typescript/no-shadow",
809
+ "typescript/no-useless-constructor",
606
810
  "vitest/no-commented-out-tests"
607
811
  ];
608
812
  const restrictionRules = [
@@ -656,23 +860,23 @@ const restrictionRules = [
656
860
  "react/no-react-children",
657
861
  "react/no-unknown-property",
658
862
  "react/only-export-components",
659
- "@typescript-eslint/explicit-function-return-type",
660
- "@typescript-eslint/explicit-module-boundary-types",
661
- "@typescript-eslint/no-dynamic-delete",
662
- "@typescript-eslint/no-empty-object-type",
663
- "@typescript-eslint/no-explicit-any",
664
- "@typescript-eslint/no-import-type-side-effects",
665
- "@typescript-eslint/no-invalid-void-type",
666
- "@typescript-eslint/no-namespace",
667
- "@typescript-eslint/no-non-null-asserted-nullish-coalescing",
668
- "@typescript-eslint/no-non-null-assertion",
669
- "@typescript-eslint/no-require-imports",
670
- "@typescript-eslint/no-restricted-types",
671
- "@typescript-eslint/no-var-requires",
672
- "@typescript-eslint/non-nullable-type-assertion-style",
673
- "@typescript-eslint/prefer-literal-enum-member",
674
- "@typescript-eslint/promise-function-async",
675
- "@typescript-eslint/use-unknown-in-catch-callback-variable",
863
+ "typescript/explicit-function-return-type",
864
+ "typescript/explicit-module-boundary-types",
865
+ "typescript/no-dynamic-delete",
866
+ "typescript/no-empty-object-type",
867
+ "typescript/no-explicit-any",
868
+ "typescript/no-import-type-side-effects",
869
+ "typescript/no-invalid-void-type",
870
+ "typescript/no-namespace",
871
+ "typescript/no-non-null-asserted-nullish-coalescing",
872
+ "typescript/no-non-null-assertion",
873
+ "typescript/no-require-imports",
874
+ "typescript/no-restricted-types",
875
+ "typescript/no-var-requires",
876
+ "typescript/non-nullable-type-assertion-style",
877
+ "typescript/prefer-literal-enum-member",
878
+ "typescript/promise-function-async",
879
+ "typescript/use-unknown-in-catch-callback-variable",
676
880
  "unicorn/no-abusive-eslint-disable",
677
881
  "unicorn/no-anonymous-default-export",
678
882
  "unicorn/no-array-for-each",
@@ -686,27 +890,14 @@ const restrictionRules = [
686
890
  "unicorn/prefer-module",
687
891
  "unicorn/prefer-node-protocol",
688
892
  "unicorn/prefer-number-properties",
893
+ "vitest/require-test-timeout",
689
894
  "vue/max-props",
690
895
  "vue/no-import-compiler-macros",
691
896
  "vue/no-multiple-slot-args",
692
- "@typescript-eslint/class-methods-use-this",
693
- "@typescript-eslint/no-empty-function",
694
- "@typescript-eslint/no-restricted-imports",
695
- "@typescript-eslint/no-use-before-define",
696
- "import-x/extensions",
697
- "import-x/no-amd",
698
- "import-x/no-commonjs",
699
- "import-x/no-cycle",
700
- "import-x/no-default-export",
701
- "import-x/no-dynamic-require",
702
- "import-x/no-relative-parent-imports",
703
- "import-x/no-webpack-loader-syntax",
704
- "import-x/unambiguous",
705
- "n/handle-callback-err",
706
- "n/no-new-require",
707
- "n/no-path-concat",
708
- "n/no-process-env",
709
- "react-refresh/only-export-components"
897
+ "typescript/class-methods-use-this",
898
+ "typescript/no-empty-function",
899
+ "typescript/no-restricted-imports",
900
+ "typescript/no-use-before-define"
710
901
  ];
711
902
  const correctnessRules = [
712
903
  "constructor-super",
@@ -815,31 +1006,31 @@ const correctnessRules = [
815
1006
  "jsx-a11y/role-supports-aria-props",
816
1007
  "jsx-a11y/scope",
817
1008
  "jsx-a11y/tabindex-no-positive",
818
- "@next/next/google-font-display",
819
- "@next/next/google-font-preconnect",
820
- "@next/next/inline-script-id",
821
- "@next/next/next-script-for-ga",
822
- "@next/next/no-assign-module-variable",
823
- "@next/next/no-async-client-component",
824
- "@next/next/no-before-interactive-script-outside-document",
825
- "@next/next/no-css-tags",
826
- "@next/next/no-document-import-in-page",
827
- "@next/next/no-duplicate-head",
828
- "@next/next/no-head-element",
829
- "@next/next/no-head-import-in-document",
830
- "@next/next/no-html-link-for-pages",
831
- "@next/next/no-img-element",
832
- "@next/next/no-page-custom-font",
833
- "@next/next/no-script-component-in-head",
834
- "@next/next/no-styled-jsx-in-document",
835
- "@next/next/no-sync-scripts",
836
- "@next/next/no-title-in-document-head",
837
- "@next/next/no-typos",
838
- "@next/next/no-unwanted-polyfillio",
1009
+ "nextjs/google-font-display",
1010
+ "nextjs/google-font-preconnect",
1011
+ "nextjs/inline-script-id",
1012
+ "nextjs/next-script-for-ga",
1013
+ "nextjs/no-assign-module-variable",
1014
+ "nextjs/no-async-client-component",
1015
+ "nextjs/no-before-interactive-script-outside-document",
1016
+ "nextjs/no-css-tags",
1017
+ "nextjs/no-document-import-in-page",
1018
+ "nextjs/no-duplicate-head",
1019
+ "nextjs/no-head-element",
1020
+ "nextjs/no-head-import-in-document",
1021
+ "nextjs/no-html-link-for-pages",
1022
+ "nextjs/no-img-element",
1023
+ "nextjs/no-page-custom-font",
1024
+ "nextjs/no-script-component-in-head",
1025
+ "nextjs/no-styled-jsx-in-document",
1026
+ "nextjs/no-sync-scripts",
1027
+ "nextjs/no-title-in-document-head",
1028
+ "nextjs/no-typos",
1029
+ "nextjs/no-unwanted-polyfillio",
839
1030
  "promise/no-callback-in-promise",
840
1031
  "promise/no-new-statics",
841
1032
  "promise/valid-params",
842
- "react-hooks/exhaustive-deps",
1033
+ "react/exhaustive-deps",
843
1034
  "react/forward-ref-uses-ref",
844
1035
  "react/jsx-key",
845
1036
  "react/jsx-no-duplicate-props",
@@ -857,32 +1048,32 @@ const correctnessRules = [
857
1048
  "react/no-unsafe",
858
1049
  "react/no-will-update-set-state",
859
1050
  "react/void-dom-elements-no-children",
860
- "@typescript-eslint/await-thenable",
861
- "@typescript-eslint/no-array-delete",
862
- "@typescript-eslint/no-base-to-string",
863
- "@typescript-eslint/no-duplicate-enum-values",
864
- "@typescript-eslint/no-duplicate-type-constituents",
865
- "@typescript-eslint/no-extra-non-null-assertion",
866
- "@typescript-eslint/no-floating-promises",
867
- "@typescript-eslint/no-for-in-array",
868
- "@typescript-eslint/no-implied-eval",
869
- "@typescript-eslint/no-meaningless-void-operator",
870
- "@typescript-eslint/no-misused-new",
871
- "@typescript-eslint/no-misused-spread",
872
- "@typescript-eslint/no-non-null-asserted-optional-chain",
873
- "@typescript-eslint/no-redundant-type-constituents",
874
- "@typescript-eslint/no-this-alias",
875
- "@typescript-eslint/no-unnecessary-parameter-property-assignment",
876
- "@typescript-eslint/no-unsafe-declaration-merging",
877
- "@typescript-eslint/no-unsafe-unary-minus",
878
- "@typescript-eslint/no-useless-empty-export",
879
- "@typescript-eslint/no-wrapper-object-types",
880
- "@typescript-eslint/prefer-as-const",
881
- "@typescript-eslint/prefer-namespace-keyword",
882
- "@typescript-eslint/require-array-sort-compare",
883
- "@typescript-eslint/restrict-template-expressions",
884
- "@typescript-eslint/triple-slash-reference",
885
- "@typescript-eslint/unbound-method",
1051
+ "typescript/await-thenable",
1052
+ "typescript/no-array-delete",
1053
+ "typescript/no-base-to-string",
1054
+ "typescript/no-duplicate-enum-values",
1055
+ "typescript/no-duplicate-type-constituents",
1056
+ "typescript/no-extra-non-null-assertion",
1057
+ "typescript/no-floating-promises",
1058
+ "typescript/no-for-in-array",
1059
+ "typescript/no-implied-eval",
1060
+ "typescript/no-meaningless-void-operator",
1061
+ "typescript/no-misused-new",
1062
+ "typescript/no-misused-spread",
1063
+ "typescript/no-non-null-asserted-optional-chain",
1064
+ "typescript/no-redundant-type-constituents",
1065
+ "typescript/no-this-alias",
1066
+ "typescript/no-unnecessary-parameter-property-assignment",
1067
+ "typescript/no-unsafe-declaration-merging",
1068
+ "typescript/no-unsafe-unary-minus",
1069
+ "typescript/no-useless-empty-export",
1070
+ "typescript/no-wrapper-object-types",
1071
+ "typescript/prefer-as-const",
1072
+ "typescript/prefer-namespace-keyword",
1073
+ "typescript/require-array-sort-compare",
1074
+ "typescript/restrict-template-expressions",
1075
+ "typescript/triple-slash-reference",
1076
+ "typescript/unbound-method",
886
1077
  "unicorn/no-await-in-promise-methods",
887
1078
  "unicorn/no-empty-file",
888
1079
  "unicorn/no-invalid-fetch-options",
@@ -899,7 +1090,9 @@ const correctnessRules = [
899
1090
  "vitest/consistent-each-for",
900
1091
  "vitest/hoisted-apis-on-top",
901
1092
  "vitest/no-conditional-tests",
1093
+ "vitest/require-awaited-expect-poll",
902
1094
  "vitest/require-local-test-context-for-concurrent-snapshots",
1095
+ "vitest/require-mock-type-parameters",
903
1096
  "vitest/warn-todo",
904
1097
  "vue/no-arrow-functions-in-watch",
905
1098
  "vue/no-deprecated-destroyed-lifecycle",
@@ -909,12 +1102,10 @@ const correctnessRules = [
909
1102
  "vue/prefer-import-from-vue",
910
1103
  "vue/valid-define-emits",
911
1104
  "vue/valid-define-props",
912
- "@typescript-eslint/no-dupe-class-members",
913
- "@typescript-eslint/no-loss-of-precision",
914
- "@typescript-eslint/no-unused-expressions",
915
- "@typescript-eslint/no-unused-vars",
916
- "import-x/default",
917
- "import-x/namespace",
1105
+ "typescript/no-dupe-class-members",
1106
+ "typescript/no-loss-of-precision",
1107
+ "typescript/no-unused-expressions",
1108
+ "typescript/no-unused-vars",
918
1109
  "vitest/expect-expect",
919
1110
  "vitest/no-conditional-expect",
920
1111
  "vitest/no-disabled-tests",
@@ -922,7 +1113,8 @@ const correctnessRules = [
922
1113
  "vitest/no-standalone-expect",
923
1114
  "vitest/require-to-throw-message",
924
1115
  "vitest/valid-describe-callback",
925
- "vitest/valid-expect"
1116
+ "vitest/valid-expect",
1117
+ "vitest/valid-title"
926
1118
  ];
927
1119
  const nurseryRules = [
928
1120
  "getter-return",
@@ -932,23 +1124,17 @@ const nurseryRules = [
932
1124
  "import/named",
933
1125
  "promise/no-return-in-finally",
934
1126
  "react/require-render-return",
935
- "@typescript-eslint/consistent-return",
936
- "@typescript-eslint/consistent-type-exports",
937
- "@typescript-eslint/dot-notation",
938
- "@typescript-eslint/no-unnecessary-condition",
939
- "@typescript-eslint/no-unnecessary-qualifier",
940
- "@typescript-eslint/no-unnecessary-type-conversion",
941
- "@typescript-eslint/no-unnecessary-type-parameters",
942
- "@typescript-eslint/no-useless-default-assignment",
943
- "@typescript-eslint/prefer-find",
944
- "@typescript-eslint/prefer-optional-chain",
945
- "@typescript-eslint/prefer-readonly",
946
- "@typescript-eslint/prefer-readonly-parameter-types",
947
- "@typescript-eslint/prefer-regexp-exec",
948
- "@typescript-eslint/prefer-string-starts-ends-with",
949
- "@typescript-eslint/strict-void-return",
950
- "import-x/export",
951
- "import-x/named"
1127
+ "typescript/consistent-return",
1128
+ "typescript/consistent-type-exports",
1129
+ "typescript/dot-notation",
1130
+ "typescript/no-unnecessary-condition",
1131
+ "typescript/no-unnecessary-qualifier",
1132
+ "typescript/no-unnecessary-type-conversion",
1133
+ "typescript/no-unnecessary-type-parameters",
1134
+ "typescript/no-useless-default-assignment",
1135
+ "typescript/prefer-optional-chain",
1136
+ "typescript/prefer-readonly-parameter-types",
1137
+ "typescript/strict-void-return"
952
1138
  ];
953
1139
  const perfRules = [
954
1140
  "no-await-in-loop",
@@ -964,239 +1150,67 @@ const perfRules = [
964
1150
  "unicorn/prefer-set-has"
965
1151
  ];
966
1152
  const typeAwareRules = [
967
- "@typescript-eslint/await-thenable",
968
- "@typescript-eslint/consistent-return",
969
- "@typescript-eslint/consistent-type-exports",
970
- "@typescript-eslint/dot-notation",
971
- "@typescript-eslint/no-array-delete",
972
- "@typescript-eslint/no-base-to-string",
973
- "@typescript-eslint/no-confusing-void-expression",
974
- "@typescript-eslint/no-deprecated",
975
- "@typescript-eslint/no-duplicate-type-constituents",
976
- "@typescript-eslint/no-floating-promises",
977
- "@typescript-eslint/no-for-in-array",
978
- "@typescript-eslint/no-implied-eval",
979
- "@typescript-eslint/no-meaningless-void-operator",
980
- "@typescript-eslint/no-misused-promises",
981
- "@typescript-eslint/no-misused-spread",
982
- "@typescript-eslint/no-mixed-enums",
983
- "@typescript-eslint/no-redundant-type-constituents",
984
- "@typescript-eslint/no-unnecessary-boolean-literal-compare",
985
- "@typescript-eslint/no-unnecessary-condition",
986
- "@typescript-eslint/no-unnecessary-qualifier",
987
- "@typescript-eslint/no-unnecessary-template-expression",
988
- "@typescript-eslint/no-unnecessary-type-arguments",
989
- "@typescript-eslint/no-unnecessary-type-assertion",
990
- "@typescript-eslint/no-unnecessary-type-conversion",
991
- "@typescript-eslint/no-unnecessary-type-parameters",
992
- "@typescript-eslint/no-unsafe-argument",
993
- "@typescript-eslint/no-unsafe-assignment",
994
- "@typescript-eslint/no-unsafe-call",
995
- "@typescript-eslint/no-unsafe-enum-comparison",
996
- "@typescript-eslint/no-unsafe-member-access",
997
- "@typescript-eslint/no-unsafe-return",
998
- "@typescript-eslint/no-unsafe-type-assertion",
999
- "@typescript-eslint/no-unsafe-unary-minus",
1000
- "@typescript-eslint/no-useless-default-assignment",
1001
- "@typescript-eslint/non-nullable-type-assertion-style",
1002
- "@typescript-eslint/only-throw-error",
1003
- "@typescript-eslint/prefer-find",
1004
- "@typescript-eslint/prefer-includes",
1005
- "@typescript-eslint/prefer-nullish-coalescing",
1006
- "@typescript-eslint/prefer-optional-chain",
1007
- "@typescript-eslint/prefer-promise-reject-errors",
1008
- "@typescript-eslint/prefer-readonly",
1009
- "@typescript-eslint/prefer-readonly-parameter-types",
1010
- "@typescript-eslint/prefer-reduce-type-parameter",
1011
- "@typescript-eslint/prefer-regexp-exec",
1012
- "@typescript-eslint/prefer-return-this-type",
1013
- "@typescript-eslint/prefer-string-starts-ends-with",
1014
- "@typescript-eslint/promise-function-async",
1015
- "@typescript-eslint/related-getter-setter-pairs",
1016
- "@typescript-eslint/require-array-sort-compare",
1017
- "@typescript-eslint/require-await",
1018
- "@typescript-eslint/restrict-plus-operands",
1019
- "@typescript-eslint/restrict-template-expressions",
1020
- "@typescript-eslint/return-await",
1021
- "@typescript-eslint/strict-boolean-expressions",
1022
- "@typescript-eslint/strict-void-return",
1023
- "@typescript-eslint/switch-exhaustiveness-check",
1024
- "@typescript-eslint/unbound-method",
1025
- "@typescript-eslint/use-unknown-in-catch-callback-variable"
1153
+ "typescript/await-thenable",
1154
+ "typescript/consistent-return",
1155
+ "typescript/consistent-type-exports",
1156
+ "typescript/dot-notation",
1157
+ "typescript/no-array-delete",
1158
+ "typescript/no-base-to-string",
1159
+ "typescript/no-confusing-void-expression",
1160
+ "typescript/no-deprecated",
1161
+ "typescript/no-duplicate-type-constituents",
1162
+ "typescript/no-floating-promises",
1163
+ "typescript/no-for-in-array",
1164
+ "typescript/no-implied-eval",
1165
+ "typescript/no-meaningless-void-operator",
1166
+ "typescript/no-misused-promises",
1167
+ "typescript/no-misused-spread",
1168
+ "typescript/no-mixed-enums",
1169
+ "typescript/no-redundant-type-constituents",
1170
+ "typescript/no-unnecessary-boolean-literal-compare",
1171
+ "typescript/no-unnecessary-condition",
1172
+ "typescript/no-unnecessary-qualifier",
1173
+ "typescript/no-unnecessary-template-expression",
1174
+ "typescript/no-unnecessary-type-arguments",
1175
+ "typescript/no-unnecessary-type-assertion",
1176
+ "typescript/no-unnecessary-type-conversion",
1177
+ "typescript/no-unnecessary-type-parameters",
1178
+ "typescript/no-unsafe-argument",
1179
+ "typescript/no-unsafe-assignment",
1180
+ "typescript/no-unsafe-call",
1181
+ "typescript/no-unsafe-enum-comparison",
1182
+ "typescript/no-unsafe-member-access",
1183
+ "typescript/no-unsafe-return",
1184
+ "typescript/no-unsafe-type-assertion",
1185
+ "typescript/no-unsafe-unary-minus",
1186
+ "typescript/no-useless-default-assignment",
1187
+ "typescript/non-nullable-type-assertion-style",
1188
+ "typescript/only-throw-error",
1189
+ "typescript/prefer-find",
1190
+ "typescript/prefer-includes",
1191
+ "typescript/prefer-nullish-coalescing",
1192
+ "typescript/prefer-optional-chain",
1193
+ "typescript/prefer-promise-reject-errors",
1194
+ "typescript/prefer-readonly",
1195
+ "typescript/prefer-readonly-parameter-types",
1196
+ "typescript/prefer-reduce-type-parameter",
1197
+ "typescript/prefer-regexp-exec",
1198
+ "typescript/prefer-return-this-type",
1199
+ "typescript/prefer-string-starts-ends-with",
1200
+ "typescript/promise-function-async",
1201
+ "typescript/related-getter-setter-pairs",
1202
+ "typescript/require-array-sort-compare",
1203
+ "typescript/require-await",
1204
+ "typescript/restrict-plus-operands",
1205
+ "typescript/restrict-template-expressions",
1206
+ "typescript/return-await",
1207
+ "typescript/strict-boolean-expressions",
1208
+ "typescript/strict-void-return",
1209
+ "typescript/switch-exhaustiveness-check",
1210
+ "typescript/unbound-method",
1211
+ "typescript/use-unknown-in-catch-callback-variable"
1026
1212
  ];
1027
1213
  //#endregion
1028
- //#region src/constants.ts
1029
- const rulesPrefixesForPlugins = {
1030
- import: "import",
1031
- "import-x": "import",
1032
- jest: "jest",
1033
- jsdoc: "jsdoc",
1034
- "jsx-a11y": "jsx-a11y",
1035
- "@next/next": "nextjs",
1036
- node: "node",
1037
- n: "node",
1038
- promise: "promise",
1039
- react: "react",
1040
- "react-perf": "react-perf",
1041
- "react-hooks": "react",
1042
- "react-refresh": "react",
1043
- "@typescript-eslint": "typescript",
1044
- unicorn: "unicorn",
1045
- vitest: "vitest",
1046
- vue: "vue"
1047
- };
1048
- const eslintRulesToTypescriptEquivalents = {
1049
- "dot-notation": "@typescript-eslint/dot-notation",
1050
- "consistent-return": "@typescript-eslint/consistent-return"
1051
- };
1052
- const typescriptRulesExtendEslintRules = [
1053
- "class-methods-use-this",
1054
- "default-param-last",
1055
- "init-declarations",
1056
- "max-params",
1057
- "no-array-constructor",
1058
- "no-dupe-class-members",
1059
- "no-empty-function",
1060
- "no-invalid-this",
1061
- "no-loop-func",
1062
- "no-loss-of-precision",
1063
- "no-magic-numbers",
1064
- "no-redeclare",
1065
- "no-restricted-imports",
1066
- "no-shadow",
1067
- "no-unused-expressions",
1068
- "no-unused-vars",
1069
- "no-use-before-define",
1070
- "no-useless-constructor"
1071
- ];
1072
- //#endregion
1073
- //#region src/jsPlugins.ts
1074
- const ignorePlugins = new Set([
1075
- ...Object.keys(rulesPrefixesForPlugins),
1076
- ...Object.values(rulesPrefixesForPlugins),
1077
- "local"
1078
- ]);
1079
- const tryResolvePackage = (packageName) => {
1080
- try {
1081
- import.meta.resolve(packageName);
1082
- return true;
1083
- } catch {
1084
- return false;
1085
- }
1086
- };
1087
- const pluginNameCache = /* @__PURE__ */ new Map();
1088
- /**
1089
- * Resolves the npm package name for an ESLint plugin given its scope name.
1090
- *
1091
- * For scoped plugin names (starting with `@`), the mapping is unambiguous:
1092
- * - `@scope` -> `@scope/eslint-plugin`
1093
- * - `@scope/sub` -> `@scope/eslint-plugin-sub`
1094
- *
1095
- * For non-scoped names, the npm package could follow either convention:
1096
- * - `eslint-plugin-{name}` (e.g. `eslint-plugin-mocha`)
1097
- * - `@{name}/eslint-plugin` (e.g. `@e18e/eslint-plugin`)
1098
- *
1099
- * We try to resolve both candidates against the installed packages and
1100
- * use the one that is actually present, falling back to the standard
1101
- * `eslint-plugin-{name}` convention when neither can be resolved.
1102
- */
1103
- const resolveEslintPluginName = (pluginName) => {
1104
- const cached = pluginNameCache.get(pluginName);
1105
- if (cached !== void 0) return cached;
1106
- let result;
1107
- if (pluginName.startsWith("@")) {
1108
- const [scope, maybeSub] = pluginName.split("/");
1109
- if (maybeSub) result = `${scope}/eslint-plugin-${maybeSub}`;
1110
- else result = `${scope}/eslint-plugin`;
1111
- } else {
1112
- const standardName = `eslint-plugin-${pluginName}`;
1113
- const scopedName = `@${pluginName}/eslint-plugin`;
1114
- if (tryResolvePackage(standardName)) result = standardName;
1115
- else if (tryResolvePackage(scopedName)) result = scopedName;
1116
- else result = standardName;
1117
- }
1118
- pluginNameCache.set(pluginName, result);
1119
- return result;
1120
- };
1121
- const extractPluginId = (ruleId) => {
1122
- const firstSlash = ruleId.indexOf("/");
1123
- if (firstSlash === -1) return;
1124
- if (ruleId.startsWith("@")) {
1125
- const secondSlash = ruleId.indexOf("/", firstSlash + 1);
1126
- if (secondSlash !== -1) return ruleId.substring(0, secondSlash);
1127
- }
1128
- return ruleId.substring(0, firstSlash);
1129
- };
1130
- const isIgnoredPluginRule = (ruleId) => {
1131
- const pluginName = extractPluginId(ruleId);
1132
- if (pluginName === void 0) return true;
1133
- return ignorePlugins.has(pluginName);
1134
- };
1135
- /**
1136
- * Derives the npm package name for a plugin from its `meta.name` field.
1137
- *
1138
- * If `meta.name` already looks like a full npm package name (contains
1139
- * "eslint-plugin"), it is returned as-is. Otherwise it is fed through
1140
- * {@link resolveEslintPluginName} for the usual heuristic resolution.
1141
- */
1142
- const resolveFromMetaName = (metaName) => {
1143
- if (metaName.includes("eslint-plugin")) return metaName;
1144
- return resolveEslintPluginName(metaName);
1145
- };
1146
- /**
1147
- * Derives the rule-ID prefix that an npm package exposes.
1148
- *
1149
- * Examples:
1150
- * `eslint-plugin-react-dom` -> `react-dom`
1151
- * `eslint-plugin-mocha` -> `mocha`
1152
- * `@stylistic/eslint-plugin` -> `@stylistic`
1153
- * `@stylistic/eslint-plugin-ts` -> `@stylistic/ts`
1154
- */
1155
- const deriveRulePrefix = (packageName) => {
1156
- if (packageName.startsWith("@")) {
1157
- const slashIdx = packageName.indexOf("/");
1158
- const scope = packageName.substring(0, slashIdx);
1159
- const rest = packageName.substring(slashIdx + 1);
1160
- if (rest === "eslint-plugin") return scope;
1161
- if (rest.startsWith("eslint-plugin-")) return `${scope}/${rest.substring(14)}`;
1162
- return packageName;
1163
- }
1164
- if (packageName.startsWith("eslint-plugin-")) return packageName.substring(14);
1165
- return packageName;
1166
- };
1167
- /**
1168
- * Resolves the canonical rule name for a jsPlugin rule.
1169
- *
1170
- * When a plugin is registered under an alias (e.g. `@eslint-react/dom`) but
1171
- * its `meta.name` reveals a different canonical package (`eslint-plugin-react-dom`),
1172
- * the rule must be rewritten so that oxlint can match it to the loaded plugin.
1173
- *
1174
- * For example:
1175
- * `@eslint-react/dom/no-find-dom-node` -> `react-dom/no-find-dom-node`
1176
- */
1177
- const resolveJsPluginRuleName = (rule, plugins) => {
1178
- const pluginName = extractPluginId(rule);
1179
- if (pluginName === void 0) return rule;
1180
- const metaName = plugins?.[pluginName]?.meta?.name;
1181
- if (!metaName || !metaName.includes("eslint-plugin")) return rule;
1182
- const canonicalPrefix = deriveRulePrefix(metaName);
1183
- if (canonicalPrefix === pluginName) return rule;
1184
- return `${canonicalPrefix}/${rule.substring(pluginName.length + 1)}`;
1185
- };
1186
- const enableJsPluginRule = (targetConfig, rule, ruleEntry, plugins) => {
1187
- const pluginName = extractPluginId(rule);
1188
- if (pluginName === void 0) return false;
1189
- if (ignorePlugins.has(pluginName)) return false;
1190
- if (targetConfig.jsPlugins === void 0 || targetConfig.jsPlugins === null) targetConfig.jsPlugins = [];
1191
- const metaName = plugins?.[pluginName]?.meta?.name;
1192
- const eslintPluginName = metaName ? resolveFromMetaName(metaName) : resolveEslintPluginName(pluginName);
1193
- if (!targetConfig.jsPlugins.includes(eslintPluginName)) targetConfig.jsPlugins.push(eslintPluginName);
1194
- const resolvedRule = resolveJsPluginRuleName(rule, plugins);
1195
- targetConfig.rules = targetConfig.rules ?? {};
1196
- targetConfig.rules[resolvedRule] = ruleEntry;
1197
- return true;
1198
- };
1199
- //#endregion
1200
1214
  //#region src/generated/unsupported-rules.json
1201
1215
  var unsupportedRules = {
1202
1216
  "eslint/no-dupe-args": "Superseded by strict mode.",
@@ -1569,8 +1583,7 @@ var unsupportedRules = {
1569
1583
  //#region src/utilities.ts
1570
1584
  const isEqualDeep = (a, b) => {
1571
1585
  if (a === b) return true;
1572
- const bothAreObjects = a && b && typeof a === "object" && typeof b === "object";
1573
- return Boolean(bothAreObjects && Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => isEqualDeep(v, b[k])));
1586
+ return Boolean(a && b && typeof a === "object" && typeof b === "object" && Object.keys(a).length === Object.keys(b).length && Object.entries(a).every(([k, v]) => isEqualDeep(v, b[k])));
1574
1587
  };
1575
1588
  /**
1576
1589
  * Builds a lookup map of unsupported rule explanations.
@@ -1692,12 +1705,13 @@ const transformRuleEntry = (eslintConfig, targetConfig, baseConfig, options, ove
1692
1705
  if (resolved !== rule) removePreviousOverrideRule(resolved, eslintConfig, overrides);
1693
1706
  }
1694
1707
  }
1695
- if (allRules.includes(rule)) {
1696
- if (!options?.withNursery && nurseryRules.includes(rule)) {
1708
+ const canonicalRule = normalizeRuleToCanonical(rule);
1709
+ if (allRules.includes(canonicalRule)) {
1710
+ if (!options?.withNursery && nurseryRules.includes(canonicalRule)) {
1697
1711
  options?.reporter?.markSkipped(rule, "nursery");
1698
1712
  continue;
1699
1713
  }
1700
- if (!options?.typeAware && typeAwareRules.includes(rule)) {
1714
+ if (!options?.typeAware && typeAwareRules.includes(canonicalRule)) {
1701
1715
  options?.reporter?.markSkipped(rule, "type-aware");
1702
1716
  continue;
1703
1717
  }
@@ -1844,29 +1858,26 @@ const replaceTypescriptAliasRules = (config) => {
1844
1858
  if (Object.keys(config.rules).length === 0) delete config.rules;
1845
1859
  };
1846
1860
  /**
1847
- * Oxlint supports eslint-plugin-n rules only under the `node` plugin name
1861
+ * Renames rules from an ESLint plugin prefix to the canonical Oxlint plugin prefix.
1848
1862
  */
1849
- const replaceNodePluginName = (config) => {
1863
+ const replaceRulePrefix = (config, oldPrefix, newPrefix) => {
1850
1864
  if (config.rules === void 0) return;
1851
1865
  for (const rule of Object.keys(config.rules)) {
1852
- if (!rule.startsWith("n/")) continue;
1853
- const nodeRule = `node/${rule.slice(2)}`;
1854
- config.rules[nodeRule] = config.rules[rule];
1866
+ if (!rule.startsWith(`${oldPrefix}/`)) continue;
1867
+ const canonicalRule = `${newPrefix}/${rule.slice(oldPrefix.length + 1)}`;
1868
+ config.rules[canonicalRule] = config.rules[rule];
1855
1869
  delete config.rules[rule];
1856
1870
  }
1857
1871
  };
1858
1872
  /**
1859
- * Oxlint supports the eslint-plugin-react-refresh/only-export-components rule
1860
- * under the `react` plugin name.
1873
+ * Renames all ESLint plugin prefixes to their canonical Oxlint equivalents,
1874
+ * driven by the `rulesPrefixesForPlugins` mapping in constants.ts.
1875
+ *
1876
+ * This should run AFTER `replaceTypescriptAliasRules` so that rules which
1877
+ * extend core ESLint rules have already been stripped of their prefix.
1861
1878
  */
1862
- const replaceReactRefreshPluginName = (config) => {
1863
- if (config.rules === void 0) return;
1864
- for (const rule of Object.keys(config.rules)) {
1865
- if (!rule.startsWith("react-refresh/")) continue;
1866
- const reactRefreshRule = `react/${rule.slice(14)}`;
1867
- config.rules[reactRefreshRule] = config.rules[rule];
1868
- delete config.rules[rule];
1869
- }
1879
+ const replaceCanonicalPluginPrefixes = (config) => {
1880
+ for (const [prefix, plugin] of Object.entries(rulesPrefixesForPlugins)) if (prefix !== plugin) replaceRulePrefix(config, prefix, plugin);
1870
1881
  };
1871
1882
  //#endregion
1872
1883
  //#region src/cleanup.ts
@@ -1917,9 +1928,9 @@ const cleanUpOxlintConfig = (config) => {
1917
1928
  removeGlobalsWithAreCoveredByEnv(config);
1918
1929
  transformBoolGlobalToString(config);
1919
1930
  replaceTypescriptAliasRules(config);
1920
- replaceNodePluginName(config);
1921
- replaceReactRefreshPluginName(config);
1931
+ replaceCanonicalPluginPrefixes(config);
1922
1932
  cleanUpRulesWhichAreCoveredByCategory(config);
1933
+ if ("files" in config) cleanUpUnusedJsPlugins(config);
1923
1934
  if (config.globals !== void 0 && config.globals !== null && Object.keys(config.globals).length === 0) delete config.globals;
1924
1935
  if (config.env !== void 0 && config.env !== null) {
1925
1936
  delete config.env.es3;
@@ -1932,6 +1943,7 @@ const cleanUpOxlintConfig = (config) => {
1932
1943
  if (!("files" in config)) {
1933
1944
  cleanUpUselessOverridesEntries(config);
1934
1945
  cleanUpDisabledRootRules(config);
1946
+ cleanUpUnusedJsPlugins(config);
1935
1947
  }
1936
1948
  };
1937
1949
  /**
@@ -2255,4 +2267,4 @@ const main = async (configs, oxlintConfig, options) => {
2255
2267
  return buildConfig(Array.isArray(resolved) ? resolved : [resolved], oxlintConfig, options);
2256
2268
  };
2257
2269
  //#endregion
2258
- export { nurseryRules as a, buildUnsupportedRuleExplanations as i, preFixForJsPlugins as n, rules_exports as o, isOffValue as r, main as t };
2270
+ export { nurseryRules as a, buildUnsupportedRuleExplanations as i, preFixForJsPlugins as n, rules_exports as o, isOffValue as r, normalizeRuleToCanonical as s, main as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxlint/migrate",
3
- "version": "1.56.0",
3
+ "version": "1.58.0",
4
4
  "description": "Generates a `.oxlintrc.json` from a existing eslint flat config",
5
5
  "keywords": [
6
6
  "eslint",
@@ -41,13 +41,14 @@
41
41
  "dependencies": {
42
42
  "commander": "^14.0.0",
43
43
  "globals": "^17.0.0",
44
- "oxc-parser": "^0.116.0",
44
+ "oxc-parser": "^0.121.0",
45
45
  "tinyglobby": "^0.2.14"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@antfu/eslint-config": "^7.0.0",
49
- "@e18e/eslint-plugin": "^0.2.0",
50
- "@eslint-react/eslint-plugin": "^2.13.0",
49
+ "@babel/eslint-plugin": "^7.27.1",
50
+ "@e18e/eslint-plugin": "^0.3.0",
51
+ "@eslint-react/eslint-plugin": "^3.0.0",
51
52
  "@eslint/js": "^10.0.0",
52
53
  "@logux/eslint-config": "^57.0.0",
53
54
  "@oxc-node/core": "^0.0.35",
@@ -76,22 +77,23 @@
76
77
  "eslint-plugin-react-hooks": "^7.0.1",
77
78
  "eslint-plugin-react-perf": "^3.3.3",
78
79
  "eslint-plugin-react-refresh": "^0.5.0",
79
- "eslint-plugin-react-web-api": "^2.13.0",
80
+ "eslint-plugin-react-web-api": "^3.0.0",
80
81
  "eslint-plugin-regexp": "^3.0.0",
81
82
  "eslint-plugin-tsdoc": "^0.5.0",
82
83
  "eslint-plugin-unicorn": "^63.0.0",
83
84
  "husky": "^9.1.7",
84
85
  "lint-staged": "^16.1.2",
85
86
  "next": "^16.0.0",
86
- "oxfmt": "^0.36.0",
87
- "oxlint": "^1.56.0",
88
- "oxlint-tsgolint": "^0.16.0",
87
+ "oxfmt": "^0.42.0",
88
+ "oxlint": "^1.58.0",
89
+ "oxlint-tsgolint": "^0.18.0",
89
90
  "tsdown": "^0.21.0",
91
+ "typescript": "^6.0.0",
90
92
  "typescript-eslint": "^8.35.0",
91
93
  "vitest": "^4.0.0"
92
94
  },
93
95
  "lint-staged": {
94
96
  "*": "oxfmt --no-error-on-unmatched-pattern"
95
97
  },
96
- "packageManager": "pnpm@10.30.3"
98
+ "packageManager": "pnpm@10.33.0"
97
99
  }