@oxlint/migrate 1.57.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.
@@ -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-DEzNNXJD.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.57.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.57.0_oxlint-tsgolint@0.17.1/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-DEzNNXJD.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,23 +636,27 @@ 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",
@@ -485,6 +705,7 @@ const styleRules = [
485
705
  "vitest/consistent-vitest-vi",
486
706
  "vitest/no-import-node-test",
487
707
  "vitest/no-importing-vitest-globals",
708
+ "vitest/prefer-called-exactly-once-with",
488
709
  "vitest/prefer-called-once",
489
710
  "vitest/prefer-called-times",
490
711
  "vitest/prefer-describe-function-title",
@@ -498,22 +719,10 @@ const styleRules = [
498
719
  "vue/define-props-declaration",
499
720
  "vue/define-props-destructuring",
500
721
  "vue/require-typed-ref",
501
- "@typescript-eslint/default-param-last",
502
- "@typescript-eslint/init-declarations",
503
- "@typescript-eslint/max-params",
504
- "@typescript-eslint/no-magic-numbers",
505
- "import-x/consistent-type-specifier-style",
506
- "import-x/exports-last",
507
- "import-x/first",
508
- "import-x/group-exports",
509
- "import-x/no-anonymous-default-export",
510
- "import-x/no-duplicates",
511
- "import-x/no-mutable-exports",
512
- "import-x/no-named-default",
513
- "import-x/no-named-export",
514
- "import-x/no-namespace",
515
- "import-x/no-nodejs-modules",
516
- "import-x/prefer-default-export",
722
+ "typescript/default-param-last",
723
+ "typescript/init-declarations",
724
+ "typescript/max-params",
725
+ "typescript/no-magic-numbers",
517
726
  "vitest/consistent-test-it",
518
727
  "vitest/max-expects",
519
728
  "vitest/max-nested-describe",
@@ -543,12 +752,11 @@ const styleRules = [
543
752
  "vitest/prefer-strict-equal",
544
753
  "vitest/prefer-to-be",
545
754
  "vitest/prefer-to-contain",
755
+ "vitest/prefer-to-have-been-called-times",
546
756
  "vitest/prefer-to-have-length",
547
757
  "vitest/prefer-todo",
548
758
  "vitest/require-hook",
549
- "vitest/require-top-level-describe",
550
- "n/global-require",
551
- "n/no-exports-assign"
759
+ "vitest/require-top-level-describe"
552
760
  ];
553
761
  const suspiciousRules = [
554
762
  "block-scoped-var",
@@ -578,15 +786,15 @@ const suspiciousRules = [
578
786
  "react/no-namespace",
579
787
  "react/react-in-jsx-scope",
580
788
  "react/style-prop-object",
581
- "@typescript-eslint/no-confusing-non-null-assertion",
582
- "@typescript-eslint/no-extraneous-class",
583
- "@typescript-eslint/no-unnecessary-boolean-literal-compare",
584
- "@typescript-eslint/no-unnecessary-template-expression",
585
- "@typescript-eslint/no-unnecessary-type-arguments",
586
- "@typescript-eslint/no-unnecessary-type-assertion",
587
- "@typescript-eslint/no-unnecessary-type-constraint",
588
- "@typescript-eslint/no-unsafe-enum-comparison",
589
- "@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",
590
798
  "unicorn/consistent-function-scoping",
591
799
  "unicorn/no-accessor-recursion",
592
800
  "unicorn/no-array-reverse",
@@ -597,14 +805,8 @@ const suspiciousRules = [
597
805
  "unicorn/require-post-message-target-origin",
598
806
  "vue/no-required-prop-with-default",
599
807
  "vue/require-default-export",
600
- "@typescript-eslint/no-shadow",
601
- "@typescript-eslint/no-useless-constructor",
602
- "import-x/no-absolute-path",
603
- "import-x/no-empty-named-blocks",
604
- "import-x/no-named-as-default",
605
- "import-x/no-named-as-default-member",
606
- "import-x/no-self-import",
607
- "import-x/no-unassigned-import",
808
+ "typescript/no-shadow",
809
+ "typescript/no-useless-constructor",
608
810
  "vitest/no-commented-out-tests"
609
811
  ];
610
812
  const restrictionRules = [
@@ -658,23 +860,23 @@ const restrictionRules = [
658
860
  "react/no-react-children",
659
861
  "react/no-unknown-property",
660
862
  "react/only-export-components",
661
- "@typescript-eslint/explicit-function-return-type",
662
- "@typescript-eslint/explicit-module-boundary-types",
663
- "@typescript-eslint/no-dynamic-delete",
664
- "@typescript-eslint/no-empty-object-type",
665
- "@typescript-eslint/no-explicit-any",
666
- "@typescript-eslint/no-import-type-side-effects",
667
- "@typescript-eslint/no-invalid-void-type",
668
- "@typescript-eslint/no-namespace",
669
- "@typescript-eslint/no-non-null-asserted-nullish-coalescing",
670
- "@typescript-eslint/no-non-null-assertion",
671
- "@typescript-eslint/no-require-imports",
672
- "@typescript-eslint/no-restricted-types",
673
- "@typescript-eslint/no-var-requires",
674
- "@typescript-eslint/non-nullable-type-assertion-style",
675
- "@typescript-eslint/prefer-literal-enum-member",
676
- "@typescript-eslint/promise-function-async",
677
- "@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",
678
880
  "unicorn/no-abusive-eslint-disable",
679
881
  "unicorn/no-anonymous-default-export",
680
882
  "unicorn/no-array-for-each",
@@ -688,27 +890,14 @@ const restrictionRules = [
688
890
  "unicorn/prefer-module",
689
891
  "unicorn/prefer-node-protocol",
690
892
  "unicorn/prefer-number-properties",
893
+ "vitest/require-test-timeout",
691
894
  "vue/max-props",
692
895
  "vue/no-import-compiler-macros",
693
896
  "vue/no-multiple-slot-args",
694
- "@typescript-eslint/class-methods-use-this",
695
- "@typescript-eslint/no-empty-function",
696
- "@typescript-eslint/no-restricted-imports",
697
- "@typescript-eslint/no-use-before-define",
698
- "import-x/extensions",
699
- "import-x/no-amd",
700
- "import-x/no-commonjs",
701
- "import-x/no-cycle",
702
- "import-x/no-default-export",
703
- "import-x/no-dynamic-require",
704
- "import-x/no-relative-parent-imports",
705
- "import-x/no-webpack-loader-syntax",
706
- "import-x/unambiguous",
707
- "n/handle-callback-err",
708
- "n/no-new-require",
709
- "n/no-path-concat",
710
- "n/no-process-env",
711
- "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"
712
901
  ];
713
902
  const correctnessRules = [
714
903
  "constructor-super",
@@ -817,31 +1006,31 @@ const correctnessRules = [
817
1006
  "jsx-a11y/role-supports-aria-props",
818
1007
  "jsx-a11y/scope",
819
1008
  "jsx-a11y/tabindex-no-positive",
820
- "@next/next/google-font-display",
821
- "@next/next/google-font-preconnect",
822
- "@next/next/inline-script-id",
823
- "@next/next/next-script-for-ga",
824
- "@next/next/no-assign-module-variable",
825
- "@next/next/no-async-client-component",
826
- "@next/next/no-before-interactive-script-outside-document",
827
- "@next/next/no-css-tags",
828
- "@next/next/no-document-import-in-page",
829
- "@next/next/no-duplicate-head",
830
- "@next/next/no-head-element",
831
- "@next/next/no-head-import-in-document",
832
- "@next/next/no-html-link-for-pages",
833
- "@next/next/no-img-element",
834
- "@next/next/no-page-custom-font",
835
- "@next/next/no-script-component-in-head",
836
- "@next/next/no-styled-jsx-in-document",
837
- "@next/next/no-sync-scripts",
838
- "@next/next/no-title-in-document-head",
839
- "@next/next/no-typos",
840
- "@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",
841
1030
  "promise/no-callback-in-promise",
842
1031
  "promise/no-new-statics",
843
1032
  "promise/valid-params",
844
- "react-hooks/exhaustive-deps",
1033
+ "react/exhaustive-deps",
845
1034
  "react/forward-ref-uses-ref",
846
1035
  "react/jsx-key",
847
1036
  "react/jsx-no-duplicate-props",
@@ -859,32 +1048,32 @@ const correctnessRules = [
859
1048
  "react/no-unsafe",
860
1049
  "react/no-will-update-set-state",
861
1050
  "react/void-dom-elements-no-children",
862
- "@typescript-eslint/await-thenable",
863
- "@typescript-eslint/no-array-delete",
864
- "@typescript-eslint/no-base-to-string",
865
- "@typescript-eslint/no-duplicate-enum-values",
866
- "@typescript-eslint/no-duplicate-type-constituents",
867
- "@typescript-eslint/no-extra-non-null-assertion",
868
- "@typescript-eslint/no-floating-promises",
869
- "@typescript-eslint/no-for-in-array",
870
- "@typescript-eslint/no-implied-eval",
871
- "@typescript-eslint/no-meaningless-void-operator",
872
- "@typescript-eslint/no-misused-new",
873
- "@typescript-eslint/no-misused-spread",
874
- "@typescript-eslint/no-non-null-asserted-optional-chain",
875
- "@typescript-eslint/no-redundant-type-constituents",
876
- "@typescript-eslint/no-this-alias",
877
- "@typescript-eslint/no-unnecessary-parameter-property-assignment",
878
- "@typescript-eslint/no-unsafe-declaration-merging",
879
- "@typescript-eslint/no-unsafe-unary-minus",
880
- "@typescript-eslint/no-useless-empty-export",
881
- "@typescript-eslint/no-wrapper-object-types",
882
- "@typescript-eslint/prefer-as-const",
883
- "@typescript-eslint/prefer-namespace-keyword",
884
- "@typescript-eslint/require-array-sort-compare",
885
- "@typescript-eslint/restrict-template-expressions",
886
- "@typescript-eslint/triple-slash-reference",
887
- "@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",
888
1077
  "unicorn/no-await-in-promise-methods",
889
1078
  "unicorn/no-empty-file",
890
1079
  "unicorn/no-invalid-fetch-options",
@@ -901,7 +1090,9 @@ const correctnessRules = [
901
1090
  "vitest/consistent-each-for",
902
1091
  "vitest/hoisted-apis-on-top",
903
1092
  "vitest/no-conditional-tests",
1093
+ "vitest/require-awaited-expect-poll",
904
1094
  "vitest/require-local-test-context-for-concurrent-snapshots",
1095
+ "vitest/require-mock-type-parameters",
905
1096
  "vitest/warn-todo",
906
1097
  "vue/no-arrow-functions-in-watch",
907
1098
  "vue/no-deprecated-destroyed-lifecycle",
@@ -911,12 +1102,10 @@ const correctnessRules = [
911
1102
  "vue/prefer-import-from-vue",
912
1103
  "vue/valid-define-emits",
913
1104
  "vue/valid-define-props",
914
- "@typescript-eslint/no-dupe-class-members",
915
- "@typescript-eslint/no-loss-of-precision",
916
- "@typescript-eslint/no-unused-expressions",
917
- "@typescript-eslint/no-unused-vars",
918
- "import-x/default",
919
- "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",
920
1109
  "vitest/expect-expect",
921
1110
  "vitest/no-conditional-expect",
922
1111
  "vitest/no-disabled-tests",
@@ -924,7 +1113,8 @@ const correctnessRules = [
924
1113
  "vitest/no-standalone-expect",
925
1114
  "vitest/require-to-throw-message",
926
1115
  "vitest/valid-describe-callback",
927
- "vitest/valid-expect"
1116
+ "vitest/valid-expect",
1117
+ "vitest/valid-title"
928
1118
  ];
929
1119
  const nurseryRules = [
930
1120
  "getter-return",
@@ -934,23 +1124,17 @@ const nurseryRules = [
934
1124
  "import/named",
935
1125
  "promise/no-return-in-finally",
936
1126
  "react/require-render-return",
937
- "@typescript-eslint/consistent-return",
938
- "@typescript-eslint/consistent-type-exports",
939
- "@typescript-eslint/dot-notation",
940
- "@typescript-eslint/no-unnecessary-condition",
941
- "@typescript-eslint/no-unnecessary-qualifier",
942
- "@typescript-eslint/no-unnecessary-type-conversion",
943
- "@typescript-eslint/no-unnecessary-type-parameters",
944
- "@typescript-eslint/no-useless-default-assignment",
945
- "@typescript-eslint/prefer-find",
946
- "@typescript-eslint/prefer-optional-chain",
947
- "@typescript-eslint/prefer-readonly",
948
- "@typescript-eslint/prefer-readonly-parameter-types",
949
- "@typescript-eslint/prefer-regexp-exec",
950
- "@typescript-eslint/prefer-string-starts-ends-with",
951
- "@typescript-eslint/strict-void-return",
952
- "import-x/export",
953
- "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"
954
1138
  ];
955
1139
  const perfRules = [
956
1140
  "no-await-in-loop",
@@ -966,239 +1150,67 @@ const perfRules = [
966
1150
  "unicorn/prefer-set-has"
967
1151
  ];
968
1152
  const typeAwareRules = [
969
- "@typescript-eslint/await-thenable",
970
- "@typescript-eslint/consistent-return",
971
- "@typescript-eslint/consistent-type-exports",
972
- "@typescript-eslint/dot-notation",
973
- "@typescript-eslint/no-array-delete",
974
- "@typescript-eslint/no-base-to-string",
975
- "@typescript-eslint/no-confusing-void-expression",
976
- "@typescript-eslint/no-deprecated",
977
- "@typescript-eslint/no-duplicate-type-constituents",
978
- "@typescript-eslint/no-floating-promises",
979
- "@typescript-eslint/no-for-in-array",
980
- "@typescript-eslint/no-implied-eval",
981
- "@typescript-eslint/no-meaningless-void-operator",
982
- "@typescript-eslint/no-misused-promises",
983
- "@typescript-eslint/no-misused-spread",
984
- "@typescript-eslint/no-mixed-enums",
985
- "@typescript-eslint/no-redundant-type-constituents",
986
- "@typescript-eslint/no-unnecessary-boolean-literal-compare",
987
- "@typescript-eslint/no-unnecessary-condition",
988
- "@typescript-eslint/no-unnecessary-qualifier",
989
- "@typescript-eslint/no-unnecessary-template-expression",
990
- "@typescript-eslint/no-unnecessary-type-arguments",
991
- "@typescript-eslint/no-unnecessary-type-assertion",
992
- "@typescript-eslint/no-unnecessary-type-conversion",
993
- "@typescript-eslint/no-unnecessary-type-parameters",
994
- "@typescript-eslint/no-unsafe-argument",
995
- "@typescript-eslint/no-unsafe-assignment",
996
- "@typescript-eslint/no-unsafe-call",
997
- "@typescript-eslint/no-unsafe-enum-comparison",
998
- "@typescript-eslint/no-unsafe-member-access",
999
- "@typescript-eslint/no-unsafe-return",
1000
- "@typescript-eslint/no-unsafe-type-assertion",
1001
- "@typescript-eslint/no-unsafe-unary-minus",
1002
- "@typescript-eslint/no-useless-default-assignment",
1003
- "@typescript-eslint/non-nullable-type-assertion-style",
1004
- "@typescript-eslint/only-throw-error",
1005
- "@typescript-eslint/prefer-find",
1006
- "@typescript-eslint/prefer-includes",
1007
- "@typescript-eslint/prefer-nullish-coalescing",
1008
- "@typescript-eslint/prefer-optional-chain",
1009
- "@typescript-eslint/prefer-promise-reject-errors",
1010
- "@typescript-eslint/prefer-readonly",
1011
- "@typescript-eslint/prefer-readonly-parameter-types",
1012
- "@typescript-eslint/prefer-reduce-type-parameter",
1013
- "@typescript-eslint/prefer-regexp-exec",
1014
- "@typescript-eslint/prefer-return-this-type",
1015
- "@typescript-eslint/prefer-string-starts-ends-with",
1016
- "@typescript-eslint/promise-function-async",
1017
- "@typescript-eslint/related-getter-setter-pairs",
1018
- "@typescript-eslint/require-array-sort-compare",
1019
- "@typescript-eslint/require-await",
1020
- "@typescript-eslint/restrict-plus-operands",
1021
- "@typescript-eslint/restrict-template-expressions",
1022
- "@typescript-eslint/return-await",
1023
- "@typescript-eslint/strict-boolean-expressions",
1024
- "@typescript-eslint/strict-void-return",
1025
- "@typescript-eslint/switch-exhaustiveness-check",
1026
- "@typescript-eslint/unbound-method",
1027
- "@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"
1028
1212
  ];
1029
1213
  //#endregion
1030
- //#region src/constants.ts
1031
- const rulesPrefixesForPlugins = {
1032
- import: "import",
1033
- "import-x": "import",
1034
- jest: "jest",
1035
- jsdoc: "jsdoc",
1036
- "jsx-a11y": "jsx-a11y",
1037
- "@next/next": "nextjs",
1038
- node: "node",
1039
- n: "node",
1040
- promise: "promise",
1041
- react: "react",
1042
- "react-perf": "react-perf",
1043
- "react-hooks": "react",
1044
- "react-refresh": "react",
1045
- "@typescript-eslint": "typescript",
1046
- unicorn: "unicorn",
1047
- vitest: "vitest",
1048
- vue: "vue"
1049
- };
1050
- const eslintRulesToTypescriptEquivalents = {
1051
- "dot-notation": "@typescript-eslint/dot-notation",
1052
- "consistent-return": "@typescript-eslint/consistent-return"
1053
- };
1054
- const typescriptRulesExtendEslintRules = [
1055
- "class-methods-use-this",
1056
- "default-param-last",
1057
- "init-declarations",
1058
- "max-params",
1059
- "no-array-constructor",
1060
- "no-dupe-class-members",
1061
- "no-empty-function",
1062
- "no-invalid-this",
1063
- "no-loop-func",
1064
- "no-loss-of-precision",
1065
- "no-magic-numbers",
1066
- "no-redeclare",
1067
- "no-restricted-imports",
1068
- "no-shadow",
1069
- "no-unused-expressions",
1070
- "no-unused-vars",
1071
- "no-use-before-define",
1072
- "no-useless-constructor"
1073
- ];
1074
- //#endregion
1075
- //#region src/jsPlugins.ts
1076
- const ignorePlugins = new Set([
1077
- ...Object.keys(rulesPrefixesForPlugins),
1078
- ...Object.values(rulesPrefixesForPlugins),
1079
- "local"
1080
- ]);
1081
- const tryResolvePackage = (packageName) => {
1082
- try {
1083
- import.meta.resolve(packageName);
1084
- return true;
1085
- } catch {
1086
- return false;
1087
- }
1088
- };
1089
- const pluginNameCache = /* @__PURE__ */ new Map();
1090
- /**
1091
- * Resolves the npm package name for an ESLint plugin given its scope name.
1092
- *
1093
- * For scoped plugin names (starting with `@`), the mapping is unambiguous:
1094
- * - `@scope` -> `@scope/eslint-plugin`
1095
- * - `@scope/sub` -> `@scope/eslint-plugin-sub`
1096
- *
1097
- * For non-scoped names, the npm package could follow either convention:
1098
- * - `eslint-plugin-{name}` (e.g. `eslint-plugin-mocha`)
1099
- * - `@{name}/eslint-plugin` (e.g. `@e18e/eslint-plugin`)
1100
- *
1101
- * We try to resolve both candidates against the installed packages and
1102
- * use the one that is actually present, falling back to the standard
1103
- * `eslint-plugin-{name}` convention when neither can be resolved.
1104
- */
1105
- const resolveEslintPluginName = (pluginName) => {
1106
- const cached = pluginNameCache.get(pluginName);
1107
- if (cached !== void 0) return cached;
1108
- let result;
1109
- if (pluginName.startsWith("@")) {
1110
- const [scope, maybeSub] = pluginName.split("/");
1111
- if (maybeSub) result = `${scope}/eslint-plugin-${maybeSub}`;
1112
- else result = `${scope}/eslint-plugin`;
1113
- } else {
1114
- const standardName = `eslint-plugin-${pluginName}`;
1115
- const scopedName = `@${pluginName}/eslint-plugin`;
1116
- if (tryResolvePackage(standardName)) result = standardName;
1117
- else if (tryResolvePackage(scopedName)) result = scopedName;
1118
- else result = standardName;
1119
- }
1120
- pluginNameCache.set(pluginName, result);
1121
- return result;
1122
- };
1123
- const extractPluginId = (ruleId) => {
1124
- const firstSlash = ruleId.indexOf("/");
1125
- if (firstSlash === -1) return;
1126
- if (ruleId.startsWith("@")) {
1127
- const secondSlash = ruleId.indexOf("/", firstSlash + 1);
1128
- if (secondSlash !== -1) return ruleId.substring(0, secondSlash);
1129
- }
1130
- return ruleId.substring(0, firstSlash);
1131
- };
1132
- const isIgnoredPluginRule = (ruleId) => {
1133
- const pluginName = extractPluginId(ruleId);
1134
- if (pluginName === void 0) return true;
1135
- return ignorePlugins.has(pluginName);
1136
- };
1137
- /**
1138
- * Derives the npm package name for a plugin from its `meta.name` field.
1139
- *
1140
- * If `meta.name` already looks like a full npm package name (contains
1141
- * "eslint-plugin"), it is returned as-is. Otherwise it is fed through
1142
- * {@link resolveEslintPluginName} for the usual heuristic resolution.
1143
- */
1144
- const resolveFromMetaName = (metaName) => {
1145
- if (metaName.includes("eslint-plugin")) return metaName;
1146
- return resolveEslintPluginName(metaName);
1147
- };
1148
- /**
1149
- * Derives the rule-ID prefix that an npm package exposes.
1150
- *
1151
- * Examples:
1152
- * `eslint-plugin-react-dom` -> `react-dom`
1153
- * `eslint-plugin-mocha` -> `mocha`
1154
- * `@stylistic/eslint-plugin` -> `@stylistic`
1155
- * `@stylistic/eslint-plugin-ts` -> `@stylistic/ts`
1156
- */
1157
- const deriveRulePrefix = (packageName) => {
1158
- if (packageName.startsWith("@")) {
1159
- const slashIdx = packageName.indexOf("/");
1160
- const scope = packageName.substring(0, slashIdx);
1161
- const rest = packageName.substring(slashIdx + 1);
1162
- if (rest === "eslint-plugin") return scope;
1163
- if (rest.startsWith("eslint-plugin-")) return `${scope}/${rest.substring(14)}`;
1164
- return packageName;
1165
- }
1166
- if (packageName.startsWith("eslint-plugin-")) return packageName.substring(14);
1167
- return packageName;
1168
- };
1169
- /**
1170
- * Resolves the canonical rule name for a jsPlugin rule.
1171
- *
1172
- * When a plugin is registered under an alias (e.g. `@eslint-react/dom`) but
1173
- * its `meta.name` reveals a different canonical package (`eslint-plugin-react-dom`),
1174
- * the rule must be rewritten so that oxlint can match it to the loaded plugin.
1175
- *
1176
- * For example:
1177
- * `@eslint-react/dom/no-find-dom-node` -> `react-dom/no-find-dom-node`
1178
- */
1179
- const resolveJsPluginRuleName = (rule, plugins) => {
1180
- const pluginName = extractPluginId(rule);
1181
- if (pluginName === void 0) return rule;
1182
- const metaName = plugins?.[pluginName]?.meta?.name;
1183
- if (!metaName || !metaName.includes("eslint-plugin")) return rule;
1184
- const canonicalPrefix = deriveRulePrefix(metaName);
1185
- if (canonicalPrefix === pluginName) return rule;
1186
- return `${canonicalPrefix}/${rule.substring(pluginName.length + 1)}`;
1187
- };
1188
- const enableJsPluginRule = (targetConfig, rule, ruleEntry, plugins) => {
1189
- const pluginName = extractPluginId(rule);
1190
- if (pluginName === void 0) return false;
1191
- if (ignorePlugins.has(pluginName)) return false;
1192
- if (targetConfig.jsPlugins === void 0 || targetConfig.jsPlugins === null) targetConfig.jsPlugins = [];
1193
- const metaName = plugins?.[pluginName]?.meta?.name;
1194
- const eslintPluginName = metaName ? resolveFromMetaName(metaName) : resolveEslintPluginName(pluginName);
1195
- if (!targetConfig.jsPlugins.includes(eslintPluginName)) targetConfig.jsPlugins.push(eslintPluginName);
1196
- const resolvedRule = resolveJsPluginRuleName(rule, plugins);
1197
- targetConfig.rules = targetConfig.rules ?? {};
1198
- targetConfig.rules[resolvedRule] = ruleEntry;
1199
- return true;
1200
- };
1201
- //#endregion
1202
1214
  //#region src/generated/unsupported-rules.json
1203
1215
  var unsupportedRules = {
1204
1216
  "eslint/no-dupe-args": "Superseded by strict mode.",
@@ -1571,8 +1583,7 @@ var unsupportedRules = {
1571
1583
  //#region src/utilities.ts
1572
1584
  const isEqualDeep = (a, b) => {
1573
1585
  if (a === b) return true;
1574
- const bothAreObjects = a && b && typeof a === "object" && typeof b === "object";
1575
- 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])));
1576
1587
  };
1577
1588
  /**
1578
1589
  * Builds a lookup map of unsupported rule explanations.
@@ -1694,12 +1705,13 @@ const transformRuleEntry = (eslintConfig, targetConfig, baseConfig, options, ove
1694
1705
  if (resolved !== rule) removePreviousOverrideRule(resolved, eslintConfig, overrides);
1695
1706
  }
1696
1707
  }
1697
- if (allRules.includes(rule)) {
1698
- if (!options?.withNursery && nurseryRules.includes(rule)) {
1708
+ const canonicalRule = normalizeRuleToCanonical(rule);
1709
+ if (allRules.includes(canonicalRule)) {
1710
+ if (!options?.withNursery && nurseryRules.includes(canonicalRule)) {
1699
1711
  options?.reporter?.markSkipped(rule, "nursery");
1700
1712
  continue;
1701
1713
  }
1702
- if (!options?.typeAware && typeAwareRules.includes(rule)) {
1714
+ if (!options?.typeAware && typeAwareRules.includes(canonicalRule)) {
1703
1715
  options?.reporter?.markSkipped(rule, "type-aware");
1704
1716
  continue;
1705
1717
  }
@@ -1846,29 +1858,26 @@ const replaceTypescriptAliasRules = (config) => {
1846
1858
  if (Object.keys(config.rules).length === 0) delete config.rules;
1847
1859
  };
1848
1860
  /**
1849
- * 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.
1850
1862
  */
1851
- const replaceNodePluginName = (config) => {
1863
+ const replaceRulePrefix = (config, oldPrefix, newPrefix) => {
1852
1864
  if (config.rules === void 0) return;
1853
1865
  for (const rule of Object.keys(config.rules)) {
1854
- if (!rule.startsWith("n/")) continue;
1855
- const nodeRule = `node/${rule.slice(2)}`;
1856
- 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];
1857
1869
  delete config.rules[rule];
1858
1870
  }
1859
1871
  };
1860
1872
  /**
1861
- * Oxlint supports the eslint-plugin-react-refresh/only-export-components rule
1862
- * 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.
1863
1878
  */
1864
- const replaceReactRefreshPluginName = (config) => {
1865
- if (config.rules === void 0) return;
1866
- for (const rule of Object.keys(config.rules)) {
1867
- if (!rule.startsWith("react-refresh/")) continue;
1868
- const reactRefreshRule = `react/${rule.slice(14)}`;
1869
- config.rules[reactRefreshRule] = config.rules[rule];
1870
- delete config.rules[rule];
1871
- }
1879
+ const replaceCanonicalPluginPrefixes = (config) => {
1880
+ for (const [prefix, plugin] of Object.entries(rulesPrefixesForPlugins)) if (prefix !== plugin) replaceRulePrefix(config, prefix, plugin);
1872
1881
  };
1873
1882
  //#endregion
1874
1883
  //#region src/cleanup.ts
@@ -1919,9 +1928,9 @@ const cleanUpOxlintConfig = (config) => {
1919
1928
  removeGlobalsWithAreCoveredByEnv(config);
1920
1929
  transformBoolGlobalToString(config);
1921
1930
  replaceTypescriptAliasRules(config);
1922
- replaceNodePluginName(config);
1923
- replaceReactRefreshPluginName(config);
1931
+ replaceCanonicalPluginPrefixes(config);
1924
1932
  cleanUpRulesWhichAreCoveredByCategory(config);
1933
+ if ("files" in config) cleanUpUnusedJsPlugins(config);
1925
1934
  if (config.globals !== void 0 && config.globals !== null && Object.keys(config.globals).length === 0) delete config.globals;
1926
1935
  if (config.env !== void 0 && config.env !== null) {
1927
1936
  delete config.env.es3;
@@ -1934,6 +1943,7 @@ const cleanUpOxlintConfig = (config) => {
1934
1943
  if (!("files" in config)) {
1935
1944
  cleanUpUselessOverridesEntries(config);
1936
1945
  cleanUpDisabledRootRules(config);
1946
+ cleanUpUnusedJsPlugins(config);
1937
1947
  }
1938
1948
  };
1939
1949
  /**
@@ -2257,4 +2267,4 @@ const main = async (configs, oxlintConfig, options) => {
2257
2267
  return buildConfig(Array.isArray(resolved) ? resolved : [resolved], oxlintConfig, options);
2258
2268
  };
2259
2269
  //#endregion
2260
- 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.57.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",
@@ -46,7 +46,8 @@
46
46
  },
47
47
  "devDependencies": {
48
48
  "@antfu/eslint-config": "^7.0.0",
49
- "@e18e/eslint-plugin": "^0.2.0",
49
+ "@babel/eslint-plugin": "^7.27.1",
50
+ "@e18e/eslint-plugin": "^0.3.0",
50
51
  "@eslint-react/eslint-plugin": "^3.0.0",
51
52
  "@eslint/js": "^10.0.0",
52
53
  "@logux/eslint-config": "^57.0.0",
@@ -83,15 +84,16 @@
83
84
  "husky": "^9.1.7",
84
85
  "lint-staged": "^16.1.2",
85
86
  "next": "^16.0.0",
86
- "oxfmt": "^0.41.0",
87
- "oxlint": "^1.57.0",
88
- "oxlint-tsgolint": "^0.17.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.32.1"
98
+ "packageManager": "pnpm@10.33.0"
97
99
  }