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 +55 -1
- package/dist/bin/biome-to-oxc.d.mts +3 -4
- package/dist/bin/biome-to-oxc.mjs +1 -1
- package/dist/src/index.d.mts +59 -35
- package/dist/src/index.mjs +1 -1
- package/dist/{src-CUWW9YZ_.mjs → src-Dz7Nl3tJ.mjs} +161 -16
- package/package.json +9 -9
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
|
|
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-
|
|
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";
|
package/dist/src/index.d.mts
CHANGED
|
@@ -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
|
-
|
|
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
|
package/dist/src/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as migrate } from "../src-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
1363
|
-
* `
|
|
1364
|
-
*
|
|
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
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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,
|
|
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.
|
|
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
|
|
57
|
+
"zod": "^4.5.4"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@arethetypeswrong/core": "^0.18.5",
|
|
61
|
-
"@biomejs/biome": "^2.5.
|
|
62
|
-
"@types/node": "^26.
|
|
61
|
+
"@biomejs/biome": "^2.5.11",
|
|
62
|
+
"@types/node": "^26.4.1",
|
|
63
63
|
"@vitest/coverage-v8": "^4.1.11",
|
|
64
|
-
"oxfmt": "^0.
|
|
65
|
-
"oxlint": "^1.
|
|
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": "
|
|
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.
|
|
74
|
+
"pnpm": ">=11.25.0"
|
|
75
75
|
},
|
|
76
|
-
"packageManager": "pnpm@11.
|
|
76
|
+
"packageManager": "pnpm@11.25.0"
|
|
77
77
|
}
|