biome-to-oxc 3.0.0 → 3.5.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
@@ -22,6 +22,8 @@ Current capabilities:
22
22
 
23
23
  - Converts `biome.json`/`biome.jsonc` to `.oxlintrc.json` and `.oxfmtrc.jsonc`
24
24
  - Maps 80+ Biome linter rules to Oxlint equivalents (native `typescript/` rules)
25
+ - Substitutes a non-type-aware Oxlint rule for the three Biome rules that need no types but whose
26
+ only Oxlint counterpart is type-aware, so a migration without tsgolint keeps their coverage
25
27
  - Transforms Biome formatter options to Oxfmt (Prettier-compatible)
26
28
  - Normalizes `include`/`includes` field variations automatically
27
29
 
@@ -37,7 +39,10 @@ Current capabilities:
37
39
  - Rule severities (`error`/`warn`/`off`; `info` and `on` are accepted with explicit lossy-mapping warnings)
38
40
  - Explicit `printWidth` handling (no silent changes)
39
41
  - The set of formatted files: Oxfmt-only formats (YAML, TOML, Markdown) are excluded, and
40
- `sortPackageJson` is pinned off, so migrating never reformats files Biome left alone
42
+ `sortPackageJson` is pinned off unless the Biome config turns the matching assist action on, so
43
+ migrating never reformats files Biome left alone
44
+ - Assist actions: `organizeImports` and `useSortedPackageJson` become the Oxfmt options that
45
+ implement them, and every other `assist.actions.source` entry is reported as a loss
41
46
 
42
47
  ✅ **Refuses to Lose Behaviour Silently**
43
48
 
@@ -301,6 +306,52 @@ Oxlint's broader `restriction` category.
301
306
  | bracketSpacing | bracketSpacing | Direct mapping |
302
307
  | bracketSameLine | bracketSameLine | Direct mapping |
303
308
 
309
+ ### Type-Aware Rule Fallbacks
310
+
311
+ Three Biome rules need no type information, but their only Oxlint counterpart is a type-aware
312
+ (tsgolint) rule. Type-aware linting is off unless the migration enables it, so mapping straight to
313
+ the tsgolint rule would drop diagnostics the Biome config did produce. When type-aware linting is
314
+ off, a non-type-aware Oxlint rule takes its place instead:
315
+
316
+ | Biome Rule | Type-aware mapping | Fallback when type-aware is off |
317
+ | ------------------------- | ------------------------------------------- | ---------------------------------------- |
318
+ | `useArrayFind` | `typescript/prefer-find` | `unicorn/prefer-array-find` |
319
+ | `useIncludes` | `typescript/prefer-includes` | `unicorn/prefer-includes` |
320
+ | `useStringStartsEndsWith` | `typescript/prefer-string-starts-ends-with` | `unicorn/prefer-string-starts-ends-with` |
321
+
322
+ The fallback replaces the type-aware rule rather than joining it, so turning type-aware linting on
323
+ later can never report the same line twice. The first two pairs report exactly what the Biome rule
324
+ reports; `unicorn/prefer-string-starts-ends-with` covers only the anchored-regex form of the four
325
+ Biome flags, so that substitution is reported as a semantic loss.
326
+
327
+ Every other Biome rule that maps only to a type-aware Oxlint rule — `noFloatingPromises`,
328
+ `noMisusedPromises`, `useOptionalChain` and the rest — needs types on both sides and has no
329
+ fallback.
330
+
331
+ ### Assist Actions
332
+
333
+ Biome's assist actions are code actions rather than lint rules. Oxfmt implements two of them as
334
+ formatter options; the rest have no Oxc equivalent and are reported as semantic losses.
335
+
336
+ | Biome Assist Action | Oxfmt Option | Notes |
337
+ | ---------------------- | ----------------- | ---------------------------------------------------------------- |
338
+ | `organizeImports` | `sortImports` | `options.sortBareImports` → `sortImports.sortSideEffects` |
339
+ | `useSortedPackageJson` | `sortPackageJson` | Lifts the default pin that keeps Oxfmt from sorting package.json |
340
+
341
+ Only actions the Biome config names explicitly are migrated. Biome enables `organizeImports`
342
+ through its recommended set even when the config never mentions it, but both Oxfmt options default
343
+ to off here, so deriving them from a preset would start rewriting imports in projects whose Biome
344
+ config never asked for it. When a preset is what turned the actions on, the migration reports it.
345
+
346
+ Biome's `organizeImports` `groups` are matcher predicates (`:NODE:`, source globs) while Oxfmt's
347
+ are a fixed set of group names, so custom group ordering is reported as a loss rather than guessed
348
+ at. Per-override `assist` is not migrated either, and is likewise reported.
349
+
350
+ Biome and Oxfmt sort imports and `package.json` keys into different orders, so the first Oxfmt run
351
+ after migrating either action reorders once; the migration warns about it. And because Biome sorts
352
+ imports by default through its recommended assist set, a config that never settles
353
+ `organizeImports` also gets a warning: Oxfmt leaves imports alone unless `sortImports` is set.
354
+
304
355
  ## After Migration
305
356
 
306
357
  1. **Review generated configs**
@@ -380,6 +431,9 @@ npx oxlint --type-aware --type-check
380
431
  targeted typescript-eslint rules are currently implemented
381
432
  - CSS and JSON formatter overrides are mapped but may need manual review
382
433
  - Prettier plugin support is not available in Oxfmt
434
+ - Assist actions are migrated only when the Biome config names them explicitly; actions enabled
435
+ through `recommended` or a preset are reported rather than derived
436
+ - `organizeImports` custom `groups` and `identifierOrder` have no Oxfmt counterpart and are reported
383
437
  - Some Biome rules still require JS plugin fallback until native rule parity is available
384
438
 
385
439
  ## Migration Report
@@ -7,7 +7,6 @@ interface CliRuntimeOptions {
7
7
  stderr?: CliWriteStream;
8
8
  stdout?: CliWriteStream;
9
9
  }
10
- declare function runCli(argv: string[], runtimeOptions?: CliRuntimeOptions): Promise<number>;
11
- declare function createTerminationHandler(signalName: NodeJS.Signals, controller: AbortController, stderr: CliWriteStream): () => void;
12
- //#endregion
13
- export { createTerminationHandler, runCli };
10
+ export declare function runCli(argv: string[], runtimeOptions?: CliRuntimeOptions): Promise<number>;
11
+ export declare function createTerminationHandler(signalName: NodeJS.Signals, controller: AbortController, stderr: CliWriteStream): () => void;
12
+ //#endregion
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as readJsonFile, n as DefaultReporter, r as findClosestPackageJson, t as migrate } from "../src-CUWW9YZ_.mjs";
2
+ import { i as readJsonFile, n as DefaultReporter, r as findClosestPackageJson, t as migrate } from "../src-Dz7Nl3tJ.mjs";
3
3
  import { realpath } from "node:fs/promises";
4
4
  import { dirname } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
@@ -1,5 +1,5 @@
1
1
  //#region src/types.d.ts
2
- interface BiomeConfig {
2
+ export interface BiomeConfig {
3
3
  $schema?: string;
4
4
  extends?: string | string[];
5
5
  root?: boolean;
@@ -7,13 +7,14 @@ interface BiomeConfig {
7
7
  vcs?: BiomeVcsConfig;
8
8
  linter?: BiomeLinterConfig;
9
9
  formatter?: BiomeFormatterConfig;
10
+ assist?: BiomeAssistConfig;
10
11
  javascript?: BiomeJavaScriptConfig;
11
12
  json?: BiomeJsonConfig;
12
13
  css?: BiomeCssConfig;
13
14
  html?: Record<string, unknown>;
14
15
  overrides?: BiomeOverride[];
15
16
  }
16
- interface BiomeFilesConfig {
17
+ export interface BiomeFilesConfig {
17
18
  include?: string[];
18
19
  includes?: string[];
19
20
  /** Negated `includes` entries (`!pattern`), split out during normalization. */
@@ -22,14 +23,14 @@ interface BiomeFilesConfig {
22
23
  ignoreUnknown?: boolean;
23
24
  maxSize?: number;
24
25
  }
25
- interface BiomeVcsConfig {
26
+ export interface BiomeVcsConfig {
26
27
  enabled?: boolean;
27
28
  clientKind?: 'git';
28
29
  useIgnoreFile?: boolean;
29
30
  root?: string;
30
31
  defaultBranch?: string;
31
32
  }
32
- interface BiomeLinterConfig {
33
+ export interface BiomeLinterConfig {
33
34
  enabled?: boolean;
34
35
  include?: string[];
35
36
  includes?: string[];
@@ -38,24 +39,47 @@ interface BiomeLinterConfig {
38
39
  ignore?: string[];
39
40
  rules?: BiomeLinterRules;
40
41
  }
41
- interface BiomeLinterRules {
42
+ export interface BiomeLinterRules {
42
43
  recommended?: boolean;
43
44
  all?: boolean;
44
45
  preset?: 'recommended' | 'all' | 'none';
45
46
  [category: string]: boolean | BiomeRuleGroup | BiomeRuleSeverityValue | 'recommended' | 'all' | 'none' | undefined;
46
47
  }
47
- interface BiomeRuleGroup {
48
+ export interface BiomeRuleGroup {
48
49
  recommended?: boolean;
49
50
  all?: boolean;
50
51
  preset?: 'recommended' | 'all' | 'none';
51
52
  [rule: string]: BiomeRuleSeverity | boolean | 'recommended' | 'all' | 'none' | undefined;
52
53
  }
53
- type BiomeRuleSeverityValue = 'off' | 'on' | 'info' | 'warn' | 'error';
54
- type BiomeRuleSeverity = BiomeRuleSeverityValue | {
54
+ export type BiomeRuleSeverityValue = 'off' | 'on' | 'info' | 'warn' | 'error';
55
+ export type BiomeRuleSeverity = BiomeRuleSeverityValue | {
55
56
  level: BiomeRuleSeverityValue;
56
57
  options?: unknown;
57
58
  };
58
- interface BiomeFormatterConfig {
59
+ /**
60
+ * Biome's assist actions. They are code actions rather than lint rules, and the two Oxc
61
+ * surfaces split them: the sorting actions belong to Oxfmt, everything else has no home.
62
+ */
63
+ export interface BiomeAssistConfig {
64
+ enabled?: boolean;
65
+ includes?: string[];
66
+ actions?: BiomeAssistActions;
67
+ }
68
+ export interface BiomeAssistActions {
69
+ recommended?: boolean;
70
+ source?: BiomeAssistSource;
71
+ }
72
+ export interface BiomeAssistSource {
73
+ recommended?: boolean;
74
+ preset?: 'recommended' | 'all' | 'none';
75
+ [action: string]: BiomeAssistAction | boolean | 'recommended' | 'all' | 'none' | undefined;
76
+ }
77
+ export type BiomeAssistActionLevel = 'off' | 'on';
78
+ export type BiomeAssistAction = BiomeAssistActionLevel | {
79
+ level: BiomeAssistActionLevel;
80
+ options?: unknown;
81
+ };
82
+ export interface BiomeFormatterConfig {
59
83
  enabled?: boolean;
60
84
  include?: string[];
61
85
  includes?: string[];
@@ -74,7 +98,7 @@ interface BiomeFormatterConfig {
74
98
  trailingNewline?: boolean;
75
99
  [key: string]: unknown;
76
100
  }
77
- interface BiomeJavaScriptConfig {
101
+ export interface BiomeJavaScriptConfig {
78
102
  parser?: {
79
103
  unsafeParameterDecoratorsEnabled?: boolean;
80
104
  jsxEverywhere?: boolean;
@@ -104,7 +128,7 @@ interface BiomeJavaScriptConfig {
104
128
  globals?: string[];
105
129
  [key: string]: unknown;
106
130
  }
107
- interface BiomeJsonConfig {
131
+ export interface BiomeJsonConfig {
108
132
  parser?: {
109
133
  allowComments?: boolean;
110
134
  allowTrailingCommas?: boolean;
@@ -123,7 +147,7 @@ interface BiomeJsonConfig {
123
147
  enabled?: boolean;
124
148
  };
125
149
  }
126
- interface BiomeCssConfig {
150
+ export interface BiomeCssConfig {
127
151
  parser?: {
128
152
  cssModules?: boolean;
129
153
  };
@@ -140,7 +164,7 @@ interface BiomeCssConfig {
140
164
  enabled?: boolean;
141
165
  };
142
166
  }
143
- interface BiomeOverride {
167
+ export interface BiomeOverride {
144
168
  include?: string[];
145
169
  includes?: string[];
146
170
  /** Negated `includes` entries (`!pattern`), split out during normalization. */
@@ -148,18 +172,19 @@ interface BiomeOverride {
148
172
  ignore?: string[];
149
173
  linter?: BiomeLinterConfig;
150
174
  formatter?: BiomeFormatterConfig;
175
+ assist?: BiomeAssistConfig;
151
176
  javascript?: BiomeJavaScriptConfig;
152
177
  json?: BiomeJsonConfig;
153
178
  css?: BiomeCssConfig;
154
179
  }
155
- type FixStrategy = 'safe' | 'suggestions' | 'dangerous';
156
- type TypeAwareProfile = 'standard' | 'strict';
157
- type OxlintBuiltinPlugin = 'eslint' | 'react' | 'unicorn' | 'typescript' | 'oxc' | 'import' | 'jsdoc' | 'jest' | 'vitest' | 'jsx-a11y' | 'nextjs' | 'react-perf' | 'promise' | 'node' | 'vue';
158
- type OxlintJsPlugin = string | {
180
+ export type FixStrategy = 'safe' | 'suggestions' | 'dangerous';
181
+ export type TypeAwareProfile = 'standard' | 'strict';
182
+ export type OxlintBuiltinPlugin = 'eslint' | 'react' | 'unicorn' | 'typescript' | 'oxc' | 'import' | 'jsdoc' | 'jest' | 'vitest' | 'jsx-a11y' | 'nextjs' | 'react-perf' | 'promise' | 'node' | 'vue';
183
+ export type OxlintJsPlugin = string | {
159
184
  name: string;
160
185
  specifier: string;
161
186
  };
162
- interface OxlintSettings {
187
+ export interface OxlintSettings {
163
188
  jsdoc?: {
164
189
  augmentsExtendsReplacesDocs?: boolean;
165
190
  exemptDestructuredRootsFromChecks?: boolean;
@@ -195,7 +220,7 @@ interface OxlintSettings {
195
220
  };
196
221
  [key: string]: unknown;
197
222
  }
198
- interface OxlintConfig {
223
+ export interface OxlintConfig {
199
224
  $schema?: string;
200
225
  options?: {
201
226
  typeAware?: boolean;
@@ -211,7 +236,7 @@ interface OxlintConfig {
211
236
  ignorePatterns?: string[];
212
237
  settings?: OxlintSettings;
213
238
  }
214
- interface OxlintOverride {
239
+ export interface OxlintOverride {
215
240
  files: string[];
216
241
  excludeFiles?: string[];
217
242
  env?: Record<string, boolean>;
@@ -220,13 +245,13 @@ interface OxlintOverride {
220
245
  jsPlugins?: OxlintJsPlugin[];
221
246
  rules?: Record<string, OxlintRuleSeverity>;
222
247
  }
223
- type OxlintRuleSeverity = 'off' | 'warn' | 'error' | ['off' | 'warn' | 'error', ...unknown[]];
224
- interface OxfmtOverride {
248
+ export type OxlintRuleSeverity = 'off' | 'warn' | 'error' | ['off' | 'warn' | 'error', ...unknown[]];
249
+ export interface OxfmtOverride {
225
250
  files: string[];
226
251
  excludeFiles?: string[];
227
252
  options?: Partial<Omit<OxfmtConfig, '$schema' | 'ignorePatterns' | 'overrides'>>;
228
253
  }
229
- interface OxfmtConfig {
254
+ export interface OxfmtConfig {
230
255
  $schema?: string;
231
256
  printWidth?: number;
232
257
  tabWidth?: number;
@@ -309,7 +334,7 @@ interface OxfmtConfig {
309
334
  ignorePatterns?: string[];
310
335
  overrides?: OxfmtOverride[];
311
336
  }
312
- interface MigrationOptions {
337
+ export interface MigrationOptions {
313
338
  configPath?: string;
314
339
  outputDir?: string;
315
340
  dryRun?: boolean;
@@ -332,23 +357,23 @@ interface MigrationOptions {
332
357
  report?: string;
333
358
  signal?: AbortSignal;
334
359
  }
335
- interface PackageScriptUpdate {
360
+ export interface PackageScriptUpdate {
336
361
  name: string;
337
362
  before: string;
338
363
  after: string;
339
364
  }
340
- interface PackageDependencyRemoval {
365
+ export interface PackageDependencyRemoval {
341
366
  name: string;
342
367
  dependencyType: 'dependencies' | 'devDependencies';
343
368
  version?: string;
344
369
  }
345
- interface PackageDevDependencyChange {
370
+ export interface PackageDevDependencyChange {
346
371
  name: string;
347
372
  action: 'added' | 'already-present' | 'updated';
348
373
  from?: string;
349
374
  to: string;
350
375
  }
351
- interface PackageUpdateSummary {
376
+ export interface PackageUpdateSummary {
352
377
  packageJsonPath: string;
353
378
  found: boolean;
354
379
  dryRun: boolean;
@@ -359,14 +384,14 @@ interface PackageUpdateSummary {
359
384
  /** Lockfile that dependency changes invalidated, when one was detected. */
360
385
  lockfile?: LockfileStatus;
361
386
  }
362
- interface LockfileStatus {
387
+ export interface LockfileStatus {
363
388
  path: string;
364
389
  /** Command that regenerates the lockfile from the updated manifest. */
365
390
  installCommand: string;
366
391
  /** True when this run changed dependencies, so the lockfile no longer matches. */
367
392
  stale: boolean;
368
393
  }
369
- interface MigrationReport {
394
+ export interface MigrationReport {
370
395
  /**
371
396
  * True when the migration wrote every requested change without errors AND the
372
397
  * generated configuration is a complete replacement for the Biome setup.
@@ -404,7 +429,7 @@ interface MigrationReport {
404
429
  };
405
430
  cleanup?: CleanupOutcome;
406
431
  }
407
- interface CleanupOutcome {
432
+ export interface CleanupOutcome {
408
433
  /** Whether `--delete` was requested. */
409
434
  requested: boolean;
410
435
  /** Whether legacy Biome files were (or in dry-run, would be) removed. */
@@ -414,7 +439,7 @@ interface CleanupOutcome {
414
439
  /** Legacy Biome files removed, or that would be removed in dry-run. */
415
440
  files: string[];
416
441
  }
417
- interface Reporter {
442
+ export interface Reporter {
418
443
  warn(message: string): void;
419
444
  error(message: string): void;
420
445
  info(message: string): void;
@@ -434,6 +459,5 @@ interface Reporter {
434
459
  }
435
460
  //#endregion
436
461
  //#region src/index.d.ts
437
- declare function migrate(options?: MigrationOptions, reporter?: Reporter): Promise<MigrationReport>;
438
- //#endregion
439
- export { BiomeConfig, BiomeCssConfig, BiomeFilesConfig, BiomeFormatterConfig, BiomeJavaScriptConfig, BiomeJsonConfig, BiomeLinterConfig, BiomeLinterRules, BiomeOverride, BiomeRuleGroup, BiomeRuleSeverity, BiomeRuleSeverityValue, BiomeVcsConfig, CleanupOutcome, FixStrategy, LockfileStatus, MigrationOptions, MigrationReport, OxfmtConfig, OxfmtOverride, OxlintBuiltinPlugin, OxlintConfig, OxlintJsPlugin, OxlintOverride, OxlintRuleSeverity, OxlintSettings, PackageDependencyRemoval, PackageDevDependencyChange, PackageScriptUpdate, PackageUpdateSummary, Reporter, TypeAwareProfile, migrate };
462
+ export declare function migrate(options?: MigrationOptions, reporter?: Reporter): Promise<MigrationReport>;
463
+ //#endregion
@@ -1,2 +1,2 @@
1
- import { t as migrate } from "../src-CUWW9YZ_.mjs";
1
+ import { t as migrate } from "../src-Dz7Nl3tJ.mjs";
2
2
  export { migrate };
@@ -306,6 +306,7 @@ const SUPPORTED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
306
306
  "vcs",
307
307
  "linter",
308
308
  "formatter",
309
+ "assist",
309
310
  "javascript",
310
311
  "json",
311
312
  "css",
@@ -471,12 +472,32 @@ const BiomeLinterConfigSchema = IncludeFieldsSchema.extend({
471
472
  ignore: z.array(z.string()).optional(),
472
473
  rules: BiomeLinterRulesSchema.optional()
473
474
  }).passthrough();
475
+ const BiomeAssistActionSchema = z.union([z.enum(["off", "on"]), z.object({
476
+ level: z.enum(["off", "on"]),
477
+ options: z.unknown().optional()
478
+ }).passthrough()]);
479
+ const BiomeAssistConfigSchema = z.object({
480
+ enabled: z.boolean().optional(),
481
+ includes: z.array(z.string()).optional(),
482
+ actions: z.object({
483
+ recommended: z.boolean().optional(),
484
+ source: z.object({
485
+ recommended: z.boolean().optional(),
486
+ preset: z.enum([
487
+ "recommended",
488
+ "all",
489
+ "none"
490
+ ]).optional()
491
+ }).catchall(z.union([BiomeAssistActionSchema, z.boolean()])).optional()
492
+ }).passthrough().optional()
493
+ }).passthrough();
474
494
  const BiomeOverrideSchema = z.object({
475
495
  include: z.array(z.string()).optional(),
476
496
  includes: z.array(z.string()).optional(),
477
497
  ignore: z.array(z.string()).optional(),
478
498
  linter: BiomeLinterConfigSchema.optional(),
479
499
  formatter: BiomeFormatterConfigSchema.optional(),
500
+ assist: BiomeAssistConfigSchema.optional(),
480
501
  javascript: BiomeJavaScriptConfigSchema.optional(),
481
502
  json: BiomeJsonConfigSchema.optional(),
482
503
  css: BiomeCssConfigSchema.optional()
@@ -501,6 +522,7 @@ const BiomeConfigSchema = z.object({
501
522
  }).passthrough().optional(),
502
523
  linter: BiomeLinterConfigSchema.optional(),
503
524
  formatter: BiomeFormatterConfigSchema.optional(),
525
+ assist: BiomeAssistConfigSchema.optional(),
504
526
  javascript: BiomeJavaScriptConfigSchema.optional(),
505
527
  json: BiomeJsonConfigSchema.optional(),
506
528
  css: BiomeCssConfigSchema.optional(),
@@ -797,6 +819,7 @@ function generateOxfmtOverrides(biomeOverrides, reporter) {
797
819
  if (!files || files.length === 0) continue;
798
820
  const excludePatterns = [.../* @__PURE__ */ new Set([...override.ignore ?? [], ...override.exclude ?? []])];
799
821
  const excludeFiles = excludePatterns.length > 0 ? excludePatterns : void 0;
822
+ if (override.assist) reporter.loss(`Biome override for ${files.join(", ")} configures assist actions; per-override assist is not migrated, so only the top-level assist configuration reached the Oxfmt config.`);
800
823
  pushOverride(oxfmtOverrides, files, excludeFiles, mapBaseFormatterOptions(override.formatter, reporter));
801
824
  pushScopedOverride(oxfmtOverrides, files, excludeFiles, mapJavaScriptFormatterOptions(override.javascript?.formatter, reporter), reporter, "javascript.formatter", JAVASCRIPT_EXTENSIONS);
802
825
  pushScopedOverride(oxfmtOverrides, files, excludeFiles, mapJsonFormatterOptions(override.json?.formatter, reporter), reporter, "json.formatter", JSON_EXTENSIONS);
@@ -996,6 +1019,13 @@ const OXFMT_ONLY_IGNORE_PATTERNS = [
996
1019
  "**/*.toml",
997
1020
  "**/*.{md,mdx}"
998
1021
  ];
1022
+ /**
1023
+ * The two Biome assist actions Oxfmt implements. Every other `assist.actions.source` entry
1024
+ * is a code action with no formatter equivalent, so enabling one is a migration loss.
1025
+ */
1026
+ const OXFMT_BACKED_ASSIST_ACTIONS = /* @__PURE__ */ new Set(["organizeImports", "useSortedPackageJson"]);
1027
+ /** Group-level switches that sit alongside the actions and are not actions themselves. */
1028
+ const ASSIST_GROUP_LEVEL_KEYS = /* @__PURE__ */ new Set(["recommended", "preset"]);
999
1029
  function generateOxfmtConfig(biomeConfig, reporter, options = {}) {
1000
1030
  const oxfmtConfig = { $schema: "./node_modules/oxfmt/configuration_schema.json" };
1001
1031
  const { formatter } = biomeConfig;
@@ -1011,6 +1041,7 @@ function generateOxfmtConfig(biomeConfig, reporter, options = {}) {
1011
1041
  mapFormatterOptions(formatter, oxfmtConfig, reporter);
1012
1042
  mapIgnorePatterns$1(biomeConfig, oxfmtConfig, options.biomeIgnorePatterns ?? []);
1013
1043
  mapDisabledLanguageFormatters(biomeConfig, oxfmtConfig);
1044
+ mapAssistActions(biomeConfig.assist, oxfmtConfig, reporter);
1014
1045
  applyExplicitFormatterOptionPassThrough([formatter], oxfmtConfig, reporter);
1015
1046
  oxfmtConfig.sortPackageJson ??= false;
1016
1047
  const languageOverrides = generateOxfmtOverrides([
@@ -1080,6 +1111,67 @@ function mapFormatterOptions(formatter, oxfmtConfig, reporter) {
1080
1111
  if (formatter?.trailingNewline !== void 0) oxfmtConfig.insertFinalNewline = formatter.trailingNewline;
1081
1112
  if (formatter?.formatWithErrors) reporter.warn("Biome's formatWithErrors option is not supported in Oxfmt");
1082
1113
  }
1114
+ /**
1115
+ * Maps Biome's assist actions onto the Oxfmt options that implement them.
1116
+ *
1117
+ * Only actions the config turns on explicitly are migrated. Biome enables `organizeImports`
1118
+ * through its recommended set even when the config never mentions it, but both Oxfmt options
1119
+ * default to off here, so deriving them from a preset would start rewriting imports in
1120
+ * projects whose Biome config never asked for it.
1121
+ */
1122
+ function mapAssistActions(assist, oxfmtConfig, reporter) {
1123
+ if (assist?.includes && assist.includes.length > 0) reporter.loss(`Biome assist.includes (${assist.includes.join(", ")}) cannot be represented in an Oxfmt config; Oxfmt applies its sorting options to every file it formats.`);
1124
+ if (assist?.enabled === false) return;
1125
+ const source = assist?.actions?.source;
1126
+ if (assist?.actions?.recommended || source?.recommended || source?.preset) reporter.loss("Biome assist actions were enabled through a preset rather than named individually; only the actions the config names explicitly were migrated to Oxfmt.");
1127
+ for (const [action, value] of Object.entries(source ?? {})) {
1128
+ if (ASSIST_GROUP_LEVEL_KEYS.has(action) || value === void 0) continue;
1129
+ if (readAssistActionLevel(value) !== "on") continue;
1130
+ if (!OXFMT_BACKED_ASSIST_ACTIONS.has(action)) {
1131
+ reporter.loss(`Biome assist action "${action}" has no Oxfmt equivalent and was not migrated; its code action is lost.`);
1132
+ continue;
1133
+ }
1134
+ if (action === "useSortedPackageJson") {
1135
+ oxfmtConfig.sortPackageJson = true;
1136
+ reporter.warn("Biome assist action useSortedPackageJson became Oxfmt's sortPackageJson; the two use different key orders, so the first Oxfmt run will reorder package.json once.");
1137
+ continue;
1138
+ }
1139
+ oxfmtConfig.sortImports = mapOrganizeImportsOptions(value, reporter);
1140
+ reporter.warn("Biome assist action organizeImports became Oxfmt's sortImports; the two group and order imports differently, so the first Oxfmt run will reorder imports once.");
1141
+ }
1142
+ warnAboutDefaultOrganizeImports(source, oxfmtConfig, reporter);
1143
+ }
1144
+ /**
1145
+ * Biome runs `organizeImports` through its recommended assist set even when the config never
1146
+ * mentions it, so `biome check` sorts imports in essentially every project. Oxfmt's
1147
+ * `sortImports` defaults to off and deriving it from that default would start rewriting
1148
+ * imports in projects that never asked for it, so the difference is reported instead.
1149
+ *
1150
+ * Reported as a warning rather than a loss because it applies to nearly every migration, the
1151
+ * way the linter's category-preset approximation does.
1152
+ */
1153
+ function warnAboutDefaultOrganizeImports(source, oxfmtConfig, reporter) {
1154
+ const organizeImports = source?.organizeImports;
1155
+ if (oxfmtConfig.sortImports !== void 0 || organizeImports !== void 0) return;
1156
+ reporter.warn("Biome sorts imports by default through its recommended assist set. Oxfmt does not sort imports unless asked, so the generated config leaves them alone; set \"sortImports\" in the Oxfmt config to keep sorting them.");
1157
+ }
1158
+ function readAssistActionLevel(value) {
1159
+ if (typeof value === "boolean") return value ? "on" : "off";
1160
+ if (typeof value === "string") return value === "on" ? "on" : "off";
1161
+ return value.level === "on" ? "on" : "off";
1162
+ }
1163
+ /**
1164
+ * Translates the one `organizeImports` option Oxfmt has a counterpart for. Biome's `groups`
1165
+ * are matcher predicates (`:NODE:`, source globs) while Oxfmt's are a fixed list of group
1166
+ * names, so a faithful translation is not available and the ordering is reported as lost.
1167
+ */
1168
+ function mapOrganizeImportsOptions(value, reporter) {
1169
+ const options = typeof value === "object" && value.options && typeof value.options === "object" ? value.options : void 0;
1170
+ if (!options) return {};
1171
+ if (options.groups) reporter.loss("Biome assist action organizeImports option \"groups\" was not migrated; Biome's groups are matcher predicates while Oxfmt's are a fixed set of group names, so Oxfmt will sort imports into its default groups.");
1172
+ if (options.identifierOrder !== void 0 && options.identifierOrder !== "natural") reporter.loss(`Biome assist action organizeImports option "identifierOrder": ${JSON.stringify(options.identifierOrder)} has no Oxfmt equivalent; Oxfmt sorts identifiers with its own order.`);
1173
+ return typeof options.sortBareImports === "boolean" ? { sortSideEffects: options.sortBareImports } : {};
1174
+ }
1083
1175
  function mapIgnorePatterns$1(biomeConfig, oxfmtConfig, additionalIgnorePatterns) {
1084
1176
  const ignorePatterns = [
1085
1177
  ...oxfmtConfig.ignorePatterns ?? [],
@@ -1356,28 +1448,40 @@ const OXLINT_CATEGORIES = [
1356
1448
  "suspicious"
1357
1449
  ];
1358
1450
  /**
1359
- * The React Compiler rules Oxlint activates for ESLint's `react-hooks/recommended` preset.
1451
+ * Every React Compiler rule Oxlint implements.
1360
1452
  *
1361
- * Oxlint 1.79 replaced the single `react/react-compiler` rule with 22 per-diagnostic rules;
1362
- * Biome's `useReactCompiler` runs the compiler and reports every bailout it finds, so the
1363
- * `recommended` slice is the closest equivalent. The remaining rules default to off upstream
1364
- * and would fire on code Biome never flagged.
1453
+ * Oxlint 1.79 replaced the single `react/react-compiler` rule with 22 per-diagnostic rules,
1454
+ * spread across the `correctness`, `perf`, `restriction`, and `suspicious` categories. Biome's
1455
+ * `useReactCompiler` runs the compiler and reports every bailout it finds, so the whole set is
1456
+ * the equivalent: mapping only the rules Oxlint enables by default would drop diagnostics the
1457
+ * Biome rule did produce. Oxlint does not implement `gating` or `memoized-effect-dependencies`,
1458
+ * so there is nothing to enable for those two.
1365
1459
  *
1366
1460
  * @see https://oxc.rs/blog/2026-08-18-react-compiler-support
1367
1461
  */
1368
- const REACT_COMPILER_RECOMMENDED_RULES = [
1462
+ const REACT_COMPILER_RULES = [
1463
+ "react/capitalized-calls",
1369
1464
  "react/error-boundaries",
1465
+ "react/exhaustive-effect-dependencies",
1370
1466
  "react/globals",
1467
+ "react/hooks",
1371
1468
  "react/immutability",
1372
1469
  "react/incompatible-library",
1470
+ "react/invariant",
1471
+ "react/memo-dependencies",
1472
+ "react/no-deriving-state-in-effects",
1373
1473
  "react/preserve-manual-memoization",
1374
1474
  "react/purity",
1375
1475
  "react/refs",
1476
+ "react/rule-suppression",
1376
1477
  "react/set-state-in-effect",
1377
1478
  "react/set-state-in-render",
1378
1479
  "react/static-components",
1480
+ "react/syntax",
1481
+ "react/todo",
1379
1482
  "react/unsupported-syntax",
1380
- "react/use-memo"
1483
+ "react/use-memo",
1484
+ "react/void-use-memo"
1381
1485
  ];
1382
1486
  /**
1383
1487
  * Mappings where the Oxlint rule covers only part of what the Biome rule checked. The note
@@ -1387,8 +1491,26 @@ const PARTIAL_RULE_MAPPING_NOTES = {
1387
1491
  noComponentHookFactories: "Biome rule noComponentHookFactories was mapped to react/no-unstable-nested-components, which reports nested component definitions but not nested custom hook definitions.",
1388
1492
  noReactPropAssignments: "Biome rule noReactPropAssignments was mapped to the React Compiler rule react/immutability, which reports prop mutation alongside other mutations of values React treats as immutable.",
1389
1493
  useExplicitType: "Biome rule useExplicitType was mapped to typescript/explicit-function-return-type, which requires return types on functions and methods but not types on variables or parameters.",
1390
- useReactCompiler: `Biome rule useReactCompiler was mapped to Oxlint's React Compiler rules for ESLint's recommended preset (${REACT_COMPILER_RECOMMENDED_RULES.join(", ")}); the compiler rules that are off by default upstream were not enabled. See https://oxc.rs/blog/2026-08-18-react-compiler-support`
1494
+ useStaticResponseMethods: "Biome rule useStaticResponseMethods was mapped to unicorn/prefer-response-static-json, which reports `new Response(JSON.stringify(...))` but not the `new Response(null, { status, headers: { Location } })` form Biome rewrites to Response.redirect()."
1495
+ };
1496
+ /**
1497
+ * Biome rules whose only Oxlint counterpart is a type-aware rule, even though the Biome rule
1498
+ * itself needs no type information. Without type-aware linting the type-aware rule never runs,
1499
+ * so the migration would silently drop diagnostics the source config did produce. These
1500
+ * non-type-aware Oxlint rules take its place whenever the migration is not enabling type-aware
1501
+ * linting; they replace rather than accompany it, so switching the profile on later can never
1502
+ * report the same line twice.
1503
+ *
1504
+ * Every pair was checked by running both binaries over the same fixture.
1505
+ */
1506
+ const TYPE_AWARE_RULE_FALLBACKS = {
1507
+ useArrayFind: "unicorn/prefer-array-find",
1508
+ useFind: "unicorn/prefer-array-find",
1509
+ useIncludes: "unicorn/prefer-includes",
1510
+ useStringStartsEndsWith: "unicorn/prefer-string-starts-ends-with"
1391
1511
  };
1512
+ /** Fallbacks that cover less than the type-aware rule they stand in for. */
1513
+ const TYPE_AWARE_FALLBACK_NOTES = { useStringStartsEndsWith: "Biome rule useStringStartsEndsWith was mapped to unicorn/prefer-string-starts-ends-with because type-aware linting is off; it reports anchored RegExp#test() prefix checks but not the indexOf(), slice() and charAt() comparisons Biome also reports. Enabling type-aware linting maps it to typescript/prefer-string-starts-ends-with instead, which covers all four." };
1392
1514
  const BIOME_TO_OXLINT_RULE_MAP = {
1393
1515
  noAccessKey: "jsx-a11y/no-access-key",
1394
1516
  noAdjacentSpacesInRegex: "no-regex-spaces",
@@ -1467,6 +1589,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
1467
1589
  noExtraBooleanCast: "no-extra-boolean-cast",
1468
1590
  noExtraNonNullAssertion: "typescript/no-extra-non-null-assertion",
1469
1591
  noFallthroughSwitchClause: "no-fallthrough",
1592
+ noFlatMapIdentity: "unicorn/prefer-array-flat",
1470
1593
  noFloatingPromises: "typescript/no-floating-promises",
1471
1594
  noFocusedTests: ["jest/no-focused-tests", "vitest/no-focused-tests"],
1472
1595
  noForEach: "unicorn/no-array-for-each",
@@ -1498,6 +1621,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
1498
1621
  noJsRestrictedProperties: "no-restricted-properties",
1499
1622
  noJsxLiterals: "react/jsx-no-literals",
1500
1623
  noJsxNamespace: "react/no-namespace",
1624
+ noJsxPropsBind: "react-perf/jsx-no-new-function-as-prop",
1501
1625
  noLabelWithoutControl: "jsx-a11y/label-has-associated-control",
1502
1626
  noLabelVar: "no-label-var",
1503
1627
  noLoopFunc: "no-loop-func",
@@ -1654,6 +1778,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
1654
1778
  useConsistentObjectDefinitions: "object-shorthand",
1655
1779
  useConsistentTestIt: ["jest/consistent-test-it", "vitest/consistent-test-it"],
1656
1780
  useConst: "prefer-const",
1781
+ useControlLabel: "jsx-a11y/control-has-associated-label",
1657
1782
  useDateNow: "unicorn/prefer-date-now",
1658
1783
  useDefaultParameterLast: "default-param-last",
1659
1784
  useDefaultSwitchClause: "default-case",
@@ -1720,7 +1845,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
1720
1845
  useParseIntRadix: "radix",
1721
1846
  useReadonlyClassProperties: "typescript/prefer-readonly",
1722
1847
  useReactFunctionComponentDefinition: "react/function-component-definition",
1723
- useReactCompiler: REACT_COMPILER_RECOMMENDED_RULES,
1848
+ useReactCompiler: REACT_COMPILER_RULES,
1724
1849
  useReactFunctionComponents: "react/prefer-function-component",
1725
1850
  useReduceTypeParameter: "typescript/prefer-reduce-type-parameter",
1726
1851
  useRegexLiterals: "prefer-regex-literals",
@@ -1734,6 +1859,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
1734
1859
  useSimplifiedLogicExpression: "unicorn/prefer-logical-operator-over-ternary",
1735
1860
  useSpread: "prefer-spread",
1736
1861
  useSpreadOverApply: "prefer-spread",
1862
+ useStaticResponseMethods: "unicorn/prefer-response-static-json",
1737
1863
  useStringStartsEndsWith: "typescript/prefer-string-starts-ends-with",
1738
1864
  useSymbolDescription: "symbol-description",
1739
1865
  useTemplate: "prefer-template",
@@ -1804,11 +1930,20 @@ function mapBiomeRuleOptionsToOxlintSeverity(biomeName, severity, biomeSeverity,
1804
1930
  "ts-nocheck": false,
1805
1931
  "ts-check": false
1806
1932
  }];
1933
+ if (biomeName === "useReactCompiler") {
1934
+ if (options?.compilationMode === "annotation") reporter.loss("Biome rule useReactCompiler option \"compilationMode\": \"annotation\" is not supported by Oxlint, which analyses every component and hook rather than only the functions carrying a \"use memo\" directive.");
1935
+ else if (options?.compilationMode === "all") reporter.loss("Biome rule useReactCompiler option \"compilationMode\": \"all\" is not supported by Oxlint, which analyses components and hooks only; React Compiler diagnostics in other functions are no longer reported.");
1936
+ return severity;
1937
+ }
1807
1938
  if (!options) return severity;
1808
1939
  if (biomeName === "noAmbiguousAnchorText") {
1809
1940
  const { words } = options;
1810
1941
  return Array.isArray(words) && words.every((value) => typeof value === "string") ? [severity, { words }] : severity;
1811
1942
  }
1943
+ if (biomeName === "noConsole") {
1944
+ const { allow } = options;
1945
+ return Array.isArray(allow) && allow.every((value) => typeof value === "string") ? [severity, { allow }] : severity;
1946
+ }
1812
1947
  if (biomeName === "noEmptySource") {
1813
1948
  if (options.allowComments === true) reporter.loss("Biome rule noEmptySource option \"allowComments\" is not supported by Oxlint unicorn/no-empty-file and was not migrated.");
1814
1949
  return severity;
@@ -1929,7 +2064,13 @@ function mapBiomeRuleSeverity(severity, reporter, biomeRuleName) {
1929
2064
  warnUnsupportedSeverityOnce(rawSeverity, reporter, biomeRuleName);
1930
2065
  return "warn";
1931
2066
  }
1932
- function mapBiomeRuleToOxlintRules(biomeName, reporter) {
2067
+ function mapBiomeRuleToOxlintRules(biomeName, reporter, typeAware) {
2068
+ const fallback = typeAware ? void 0 : TYPE_AWARE_RULE_FALLBACKS[biomeName];
2069
+ if (fallback) {
2070
+ const fallbackNote = TYPE_AWARE_FALLBACK_NOTES[biomeName];
2071
+ if (fallbackNote) warnPartialMappingOnce(biomeName, fallbackNote, reporter);
2072
+ return [normalizeOxlintRuleName(fallback)];
2073
+ }
1933
2074
  const mapped = BIOME_TO_OXLINT_RULE_MAP[biomeName];
1934
2075
  if (mapped) {
1935
2076
  const partialMappingNote = PARTIAL_RULE_MAPPING_NOTES[biomeName];
@@ -1979,7 +2120,8 @@ function warnUnsupportedSeverityOnce(rawSeverity, reporter, biomeRuleName) {
1979
2120
  function mapBiomeCategoryToOxlint(biomeCategory) {
1980
2121
  return BIOME_TO_OXLINT_CATEGORY_MAP[biomeCategory] || null;
1981
2122
  }
1982
- function extractRulesFromBiomeConfig(linterRules, reporter, applyImplicitRecommended = false) {
2123
+ function extractRulesFromBiomeConfig(linterRules, reporter, options = {}) {
2124
+ const { applyImplicitRecommended = false, typeAware = false } = options;
1983
2125
  const rules = {};
1984
2126
  const categories = {};
1985
2127
  const sourceRulesConverted = /* @__PURE__ */ new Set();
@@ -2009,7 +2151,7 @@ function extractRulesFromBiomeConfig(linterRules, reporter, applyImplicitRecomme
2009
2151
  if (ruleName === "recommended" || ruleName === "all" || ruleName === "preset") continue;
2010
2152
  if (typeof ruleSeverity === "boolean" || ruleSeverity === void 0) continue;
2011
2153
  if (!isBiomeRuleSeverity(ruleSeverity)) continue;
2012
- const oxlintRuleNames = mapBiomeRuleToOxlintRules(ruleName, reporter);
2154
+ const oxlintRuleNames = mapBiomeRuleToOxlintRules(ruleName, reporter, typeAware);
2013
2155
  if (oxlintRuleNames.length > 0) {
2014
2156
  sourceRulesConverted.add(ruleName);
2015
2157
  const oxlintSeverity = mapBiomeRuleOptionsToOxlintSeverity(ruleName, mapBiomeRuleSeverity(ruleSeverity, reporter, ruleName), ruleSeverity, reporter);
@@ -2061,7 +2203,7 @@ function isBiomeRuleSeverity(value) {
2061
2203
  }
2062
2204
  //#endregion
2063
2205
  //#region src/overrides-transformer.ts
2064
- function transformOverridesToOxlint(biomeOverrides, reporter) {
2206
+ function transformOverridesToOxlint(biomeOverrides, reporter, options = {}) {
2065
2207
  const oxlintOverrides = [];
2066
2208
  const sourceRulesConverted = /* @__PURE__ */ new Set();
2067
2209
  const sourceRulesSkipped = /* @__PURE__ */ new Set();
@@ -2080,7 +2222,7 @@ function transformOverridesToOxlint(biomeOverrides, reporter) {
2080
2222
  const excludeFiles = [.../* @__PURE__ */ new Set([...override.ignore ?? [], ...override.exclude ?? []])];
2081
2223
  if (excludeFiles.length > 0) oxlintOverride.excludeFiles = excludeFiles;
2082
2224
  if (override.linter?.rules) {
2083
- const { rules, categories, ...ruleStats } = extractRulesFromBiomeConfig(override.linter.rules, reporter);
2225
+ const { rules, categories, ...ruleStats } = extractRulesFromBiomeConfig(override.linter.rules, reporter, { typeAware: options.typeAware ?? false });
2084
2226
  for (const ruleName of ruleStats.sourceRulesConverted) sourceRulesConverted.add(ruleName);
2085
2227
  for (const ruleName of ruleStats.sourceRulesSkipped) sourceRulesSkipped.add(ruleName);
2086
2228
  if (Object.keys(rules).length > 0) oxlintOverride.rules = rules;
@@ -2143,7 +2285,10 @@ function generateOxlintConfig(biomeConfig, reporter, options = {}) {
2143
2285
  categories: { ...DISABLED_CATEGORIES },
2144
2286
  sourceRulesConverted: /* @__PURE__ */ new Set(),
2145
2287
  sourceRulesSkipped: /* @__PURE__ */ new Set()
2146
- } : extractRulesFromBiomeConfig(biomeConfig.linter?.rules ?? {}, reporter, true);
2288
+ } : extractRulesFromBiomeConfig(biomeConfig.linter?.rules ?? {}, reporter, {
2289
+ applyImplicitRecommended: true,
2290
+ typeAware: options.typeAware ?? false
2291
+ });
2147
2292
  if (Object.keys(categories).length > 0) oxlintConfig.categories = categories;
2148
2293
  if (Object.keys(rules).length > 0) oxlintConfig.rules = rules;
2149
2294
  warnAboutUnrepresentableIncludes(biomeConfig, reporter);
@@ -2915,7 +3060,7 @@ async function runMigration(options, reporter, biomeConfigPath) {
2915
3060
  if (biomeConfig.overrides) {
2916
3061
  appendUniquePatterns(oxlintConfig, "ignorePatterns", collectDisabledOxlintOverridePatterns(biomeConfig.overrides));
2917
3062
  appendUniquePatterns(oxfmtConfig, "ignorePatterns", collectDisabledOxfmtOverridePatterns(biomeConfig.overrides));
2918
- const oxlintOverrideResult = transformOverridesToOxlint(biomeConfig.overrides, reporter);
3063
+ const oxlintOverrideResult = transformOverridesToOxlint(biomeConfig.overrides, reporter, { typeAware: typeAwareEnabled });
2919
3064
  if (oxlintOverrideResult.overrides.length > 0) oxlintConfig.overrides = oxlintOverrideResult.overrides;
2920
3065
  for (const ruleName of oxlintOverrideResult.sourceRulesConverted) convertedSourceRules.add(ruleName);
2921
3066
  for (const ruleName of oxlintOverrideResult.sourceRulesSkipped) skippedSourceRules.add(ruleName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "biome-to-oxc",
3
- "version": "3.0.0",
3
+ "version": "3.5.0",
4
4
  "description": "Migrate from Biome to Oxc ecosystem (oxlint + oxfmt + oxlint-tsgolint)",
5
5
  "keywords": [
6
6
  "biome",
@@ -54,24 +54,24 @@
54
54
  "commander": "15.0.0",
55
55
  "jsonc-parser": "next",
56
56
  "picocolors": "^1.1.1",
57
- "zod": "^4.4.3"
57
+ "zod": "^4.5.4"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@arethetypeswrong/core": "^0.18.5",
61
- "@biomejs/biome": "^2.5.9",
62
- "@types/node": "^26.2.0",
61
+ "@biomejs/biome": "^2.5.11",
62
+ "@types/node": "^26.4.1",
63
63
  "@vitest/coverage-v8": "^4.1.11",
64
- "oxfmt": "^0.64.0",
65
- "oxlint": "^1.79.0",
64
+ "oxfmt": "^0.66.0",
65
+ "oxlint": "^1.81.0",
66
66
  "oxlint-tsgolint": "^7.0.2001",
67
67
  "publint": "^0.3.24",
68
- "tsdown": "^0.22.14",
68
+ "tsdown": "rc",
69
69
  "typescript": "next",
70
70
  "vitest": "^4.1.11"
71
71
  },
72
72
  "engines": {
73
73
  "node": ">=24.19.0",
74
- "pnpm": ">=11.22.0"
74
+ "pnpm": ">=11.25.0"
75
75
  },
76
- "packageManager": "pnpm@11.22.0"
76
+ "packageManager": "pnpm@11.25.0"
77
77
  }