biome-to-oxc 2.0.0 → 3.0.1
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 +6 -0
- package/dist/bin/biome-to-oxc.mjs +4 -2
- package/dist/src/index.d.mts +11 -0
- package/dist/src/index.mjs +1 -1
- package/dist/{src-CYMpPpfK.mjs → src-C66EI3xm.mjs} +209 -7
- package/package.json +29 -25
package/README.md
CHANGED
|
@@ -135,6 +135,12 @@ ignore configuration before removing Biome.
|
|
|
135
135
|
- `docs/oxfmt-rules.tsv`: Oxfmt configuration surface inventory
|
|
136
136
|
- `docs/tsgolint-rules.tsv`: typed linting implementation matrix
|
|
137
137
|
- `docs/oxlint-vs-tsgolint.tsv`: typed rule availability cross-reference
|
|
138
|
+
- `docs/biome-rules.tsv`: Biome rule inventory, so a mapping cannot key off a rule Biome dropped
|
|
139
|
+
- `docs/biome-formatter-options.tsv`: Biome formatter surface inventory
|
|
140
|
+
|
|
141
|
+
All six are generated from the schemas of the installed `oxlint`, `oxfmt`,
|
|
142
|
+
`oxlint-tsgolint`, and `@biomejs/biome` packages by `pnpm docs:sync`; `pnpm docs:check`
|
|
143
|
+
fails when they drift, and it runs as part of `pnpm check`.
|
|
138
144
|
|
|
139
145
|
✅ **Script Rewrite Strategy Controls**
|
|
140
146
|
|
|
@@ -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-C66EI3xm.mjs";
|
|
3
3
|
import { realpath } from "node:fs/promises";
|
|
4
4
|
import { dirname } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -19,6 +19,7 @@ const MigrationOptionsSchema = z.object({
|
|
|
19
19
|
delete: z.boolean().default(false),
|
|
20
20
|
noBackup: z.boolean().default(false),
|
|
21
21
|
updateScripts: z.boolean().default(false),
|
|
22
|
+
dom: z.boolean().default(false),
|
|
22
23
|
verbose: z.boolean().default(false),
|
|
23
24
|
typeAware: z.boolean().default(false),
|
|
24
25
|
typeCheck: z.boolean().default(false),
|
|
@@ -106,7 +107,7 @@ function createCommand(packageMetadata, streams) {
|
|
|
106
107
|
writeOut: (chunk) => {
|
|
107
108
|
streams.stdout.write(chunk);
|
|
108
109
|
}
|
|
109
|
-
}).option("-c, --config <path>", "Path to biome.json or biome.jsonc").option("-o, --output-dir <path>", "Output directory for generated configs").option("--dry-run", "Show what would be done without making changes").option("--delete", "Delete legacy Biome files after migration (biome.json/biome.jsonc and .biomeignore)").option("--no-backup", "Skip backup of existing config files").option("--update-scripts", "Update package.json scripts to use oxlint/oxfmt").option("--type-aware", "Include type-aware linting guidance and dependencies").option("--type-check", "Enable strict typed linting mode (implies --type-aware)").addOption(new Option("--type-aware-profile <profile>", "Type-aware profile: standard (--type-aware) or strict (--type-aware --type-check)").choices(["standard", "strict"]).default("standard")).addOption(new Option("--fix-strategy <strategy>", "Fix mode for rewritten scripts: safe | suggestions | dangerous").choices([
|
|
110
|
+
}).option("-c, --config <path>", "Path to biome.json or biome.jsonc").option("-o, --output-dir <path>", "Output directory for generated configs").option("--dry-run", "Show what would be done without making changes").option("--delete", "Delete legacy Biome files after migration (biome.json/biome.jsonc and .biomeignore)").option("--no-backup", "Skip backup of existing config files").option("--update-scripts", "Update package.json scripts to use oxlint/oxfmt").addOption(new Option("--dom").hideHelp()).option("--type-aware", "Include type-aware linting guidance and dependencies").option("--type-check", "Enable strict typed linting mode (implies --type-aware)").addOption(new Option("--type-aware-profile <profile>", "Type-aware profile: standard (--type-aware) or strict (--type-aware --type-check)").choices(["standard", "strict"]).default("standard")).addOption(new Option("--fix-strategy <strategy>", "Fix mode for rewritten scripts: safe | suggestions | dangerous").choices([
|
|
110
111
|
"safe",
|
|
111
112
|
"suggestions",
|
|
112
113
|
"dangerous"
|
|
@@ -130,6 +131,7 @@ function normalizeMigrationOptions(options) {
|
|
|
130
131
|
delete: options.delete,
|
|
131
132
|
noBackup: options.backup === false,
|
|
132
133
|
updateScripts: options.updateScripts,
|
|
134
|
+
dom: options.dom,
|
|
133
135
|
verbose: options.verbose,
|
|
134
136
|
typeAware,
|
|
135
137
|
typeCheck,
|
package/dist/src/index.d.mts
CHANGED
|
@@ -69,6 +69,9 @@ interface BiomeFormatterConfig {
|
|
|
69
69
|
lineWidth?: number;
|
|
70
70
|
attributePosition?: 'auto' | 'multiline';
|
|
71
71
|
bracketSpacing?: boolean;
|
|
72
|
+
bracketSameLine?: boolean;
|
|
73
|
+
expand?: 'auto' | 'always' | 'never';
|
|
74
|
+
trailingNewline?: boolean;
|
|
72
75
|
[key: string]: unknown;
|
|
73
76
|
}
|
|
74
77
|
interface BiomeJavaScriptConfig {
|
|
@@ -86,10 +89,13 @@ interface BiomeJavaScriptConfig {
|
|
|
86
89
|
arrowParentheses?: 'always' | 'asNeeded';
|
|
87
90
|
bracketSameLine?: boolean;
|
|
88
91
|
bracketSpacing?: boolean;
|
|
92
|
+
expand?: 'auto' | 'always' | 'never';
|
|
89
93
|
indentStyle?: 'tab' | 'space';
|
|
90
94
|
indentWidth?: number;
|
|
91
95
|
lineEnding?: 'lf' | 'crlf' | 'cr' | 'auto';
|
|
92
96
|
lineWidth?: number;
|
|
97
|
+
operatorLinebreak?: 'after' | 'before';
|
|
98
|
+
trailingNewline?: boolean;
|
|
93
99
|
[key: string]: unknown;
|
|
94
100
|
};
|
|
95
101
|
linter?: {
|
|
@@ -105,11 +111,13 @@ interface BiomeJsonConfig {
|
|
|
105
111
|
};
|
|
106
112
|
formatter?: {
|
|
107
113
|
enabled?: boolean;
|
|
114
|
+
expand?: 'auto' | 'always' | 'never';
|
|
108
115
|
indentStyle?: 'tab' | 'space';
|
|
109
116
|
indentWidth?: number;
|
|
110
117
|
lineEnding?: 'lf' | 'crlf' | 'cr' | 'auto';
|
|
111
118
|
lineWidth?: number;
|
|
112
119
|
trailingCommas?: 'none' | 'all';
|
|
120
|
+
trailingNewline?: boolean;
|
|
113
121
|
};
|
|
114
122
|
linter?: {
|
|
115
123
|
enabled?: boolean;
|
|
@@ -126,6 +134,7 @@ interface BiomeCssConfig {
|
|
|
126
134
|
lineEnding?: 'lf' | 'crlf' | 'cr' | 'auto';
|
|
127
135
|
lineWidth?: number;
|
|
128
136
|
quoteStyle?: 'single' | 'double';
|
|
137
|
+
trailingNewline?: boolean;
|
|
129
138
|
};
|
|
130
139
|
linter?: {
|
|
131
140
|
enabled?: boolean;
|
|
@@ -233,6 +242,7 @@ interface OxfmtConfig {
|
|
|
233
242
|
endOfLine?: 'lf' | 'crlf' | 'cr';
|
|
234
243
|
singleAttributePerLine?: boolean;
|
|
235
244
|
objectWrap?: 'preserve' | 'collapse';
|
|
245
|
+
experimentalOperatorPosition?: 'start' | 'end';
|
|
236
246
|
insertFinalNewline?: boolean;
|
|
237
247
|
embeddedLanguageFormatting?: 'auto' | 'off';
|
|
238
248
|
htmlWhitespaceSensitivity?: 'css' | 'strict' | 'ignore';
|
|
@@ -306,6 +316,7 @@ interface MigrationOptions {
|
|
|
306
316
|
delete?: boolean;
|
|
307
317
|
noBackup?: boolean;
|
|
308
318
|
updateScripts?: boolean;
|
|
319
|
+
dom?: boolean;
|
|
309
320
|
verbose?: boolean;
|
|
310
321
|
typeAware?: boolean;
|
|
311
322
|
typeCheck?: boolean;
|
package/dist/src/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as migrate } from "../src-
|
|
1
|
+
import { t as migrate } from "../src-C66EI3xm.mjs";
|
|
2
2
|
export { migrate };
|
|
@@ -373,7 +373,14 @@ const BiomeFormatterConfigSchema = IncludeFieldsSchema.extend({
|
|
|
373
373
|
]).optional(),
|
|
374
374
|
lineWidth: z.number().int().optional(),
|
|
375
375
|
attributePosition: z.enum(["auto", "multiline"]).optional(),
|
|
376
|
-
bracketSpacing: z.boolean().optional()
|
|
376
|
+
bracketSpacing: z.boolean().optional(),
|
|
377
|
+
bracketSameLine: z.boolean().optional(),
|
|
378
|
+
expand: z.enum([
|
|
379
|
+
"auto",
|
|
380
|
+
"always",
|
|
381
|
+
"never"
|
|
382
|
+
]).optional(),
|
|
383
|
+
trailingNewline: z.boolean().optional()
|
|
377
384
|
}).passthrough();
|
|
378
385
|
const BiomeJavaScriptFormatterSchema = z.object({
|
|
379
386
|
enabled: z.boolean().optional(),
|
|
@@ -389,6 +396,11 @@ const BiomeJavaScriptFormatterSchema = z.object({
|
|
|
389
396
|
arrowParentheses: z.enum(["always", "asNeeded"]).optional(),
|
|
390
397
|
bracketSameLine: z.boolean().optional(),
|
|
391
398
|
bracketSpacing: z.boolean().optional(),
|
|
399
|
+
expand: z.enum([
|
|
400
|
+
"auto",
|
|
401
|
+
"always",
|
|
402
|
+
"never"
|
|
403
|
+
]).optional(),
|
|
392
404
|
indentStyle: z.enum(["tab", "space"]).optional(),
|
|
393
405
|
indentWidth: z.number().int().optional(),
|
|
394
406
|
lineEnding: z.enum([
|
|
@@ -397,7 +409,9 @@ const BiomeJavaScriptFormatterSchema = z.object({
|
|
|
397
409
|
"cr",
|
|
398
410
|
"auto"
|
|
399
411
|
]).optional(),
|
|
400
|
-
lineWidth: z.number().int().optional()
|
|
412
|
+
lineWidth: z.number().int().optional(),
|
|
413
|
+
operatorLinebreak: z.enum(["after", "before"]).optional(),
|
|
414
|
+
trailingNewline: z.boolean().optional()
|
|
401
415
|
}).passthrough();
|
|
402
416
|
const BiomeJavaScriptConfigSchema = z.object({
|
|
403
417
|
parser: z.object({
|
|
@@ -415,6 +429,11 @@ const BiomeJsonConfigSchema = z.object({
|
|
|
415
429
|
}).passthrough().optional(),
|
|
416
430
|
formatter: z.object({
|
|
417
431
|
enabled: z.boolean().optional(),
|
|
432
|
+
expand: z.enum([
|
|
433
|
+
"auto",
|
|
434
|
+
"always",
|
|
435
|
+
"never"
|
|
436
|
+
]).optional(),
|
|
418
437
|
indentStyle: z.enum(["tab", "space"]).optional(),
|
|
419
438
|
indentWidth: z.number().int().optional(),
|
|
420
439
|
lineEnding: z.enum([
|
|
@@ -424,7 +443,8 @@ const BiomeJsonConfigSchema = z.object({
|
|
|
424
443
|
"auto"
|
|
425
444
|
]).optional(),
|
|
426
445
|
lineWidth: z.number().int().optional(),
|
|
427
|
-
trailingCommas: z.enum(["none", "all"]).optional()
|
|
446
|
+
trailingCommas: z.enum(["none", "all"]).optional(),
|
|
447
|
+
trailingNewline: z.boolean().optional()
|
|
428
448
|
}).passthrough().optional(),
|
|
429
449
|
linter: z.object({ enabled: z.boolean().optional() }).passthrough().optional()
|
|
430
450
|
}).passthrough();
|
|
@@ -441,7 +461,8 @@ const BiomeCssConfigSchema = z.object({
|
|
|
441
461
|
"auto"
|
|
442
462
|
]).optional(),
|
|
443
463
|
lineWidth: z.number().int().optional(),
|
|
444
|
-
quoteStyle: z.enum(["single", "double"]).optional()
|
|
464
|
+
quoteStyle: z.enum(["single", "double"]).optional(),
|
|
465
|
+
trailingNewline: z.boolean().optional()
|
|
445
466
|
}).passthrough().optional(),
|
|
446
467
|
linter: z.object({ enabled: z.boolean().optional() }).passthrough().optional()
|
|
447
468
|
}).passthrough();
|
|
@@ -692,6 +713,7 @@ function generateESLintFormatterBridgeSuggestions() {
|
|
|
692
713
|
//#region src/oxfmt-overrides.ts
|
|
693
714
|
const EXPLICIT_OXFMT_OPTION_KEYS$1 = [
|
|
694
715
|
"objectWrap",
|
|
716
|
+
"experimentalOperatorPosition",
|
|
695
717
|
"insertFinalNewline",
|
|
696
718
|
"embeddedLanguageFormatting",
|
|
697
719
|
"htmlWhitespaceSensitivity",
|
|
@@ -731,11 +753,13 @@ const CSS_EXTENSIONS = [
|
|
|
731
753
|
];
|
|
732
754
|
const JSON_FORMATTER_KEYS = /* @__PURE__ */ new Set([
|
|
733
755
|
"enabled",
|
|
756
|
+
"expand",
|
|
734
757
|
"indentStyle",
|
|
735
758
|
"indentWidth",
|
|
736
759
|
"lineEnding",
|
|
737
760
|
"lineWidth",
|
|
738
761
|
"trailingCommas",
|
|
762
|
+
"trailingNewline",
|
|
739
763
|
...EXPLICIT_OXFMT_OPTION_KEYS$1,
|
|
740
764
|
...Object.keys(LEGACY_EXPLICIT_OXFMT_OPTION_ALIASES$1)
|
|
741
765
|
]);
|
|
@@ -746,9 +770,25 @@ const CSS_FORMATTER_KEYS = /* @__PURE__ */ new Set([
|
|
|
746
770
|
"lineEnding",
|
|
747
771
|
"lineWidth",
|
|
748
772
|
"quoteStyle",
|
|
773
|
+
"trailingNewline",
|
|
749
774
|
...EXPLICIT_OXFMT_OPTION_KEYS$1,
|
|
750
775
|
...Object.keys(LEGACY_EXPLICIT_OXFMT_OPTION_ALIASES$1)
|
|
751
776
|
]);
|
|
777
|
+
/**
|
|
778
|
+
* Biome's `expand` and Oxfmt's `objectWrap` agree on two of three modes: Biome's `auto`
|
|
779
|
+
* (expand when the literal already has a newline after `{`) is Oxfmt's `preserve`, and
|
|
780
|
+
* Biome's `never` is Oxfmt's `collapse`. Biome's `always` has no Oxfmt counterpart.
|
|
781
|
+
*/
|
|
782
|
+
function mapBiomeExpandToObjectWrap(expand, label, reporter) {
|
|
783
|
+
if (expand === "auto") return "preserve";
|
|
784
|
+
if (expand === "never") return "collapse";
|
|
785
|
+
if (expand === "always") reporter.loss(`Biome ${label}.expand "always" has no Oxfmt equivalent; Oxfmt's objectWrap only offers "preserve" and "collapse", so objects and arrays that fit on one line will not be forced to expand.`);
|
|
786
|
+
}
|
|
787
|
+
/** Biome places the operator after or before the break; Oxfmt names the same two positions. */
|
|
788
|
+
function mapBiomeOperatorLinebreakToOxfmt(operatorLinebreak) {
|
|
789
|
+
if (operatorLinebreak === "after") return "end";
|
|
790
|
+
if (operatorLinebreak === "before") return "start";
|
|
791
|
+
}
|
|
752
792
|
function generateOxfmtOverrides(biomeOverrides, reporter) {
|
|
753
793
|
if (!biomeOverrides || biomeOverrides.length === 0) return [];
|
|
754
794
|
const oxfmtOverrides = [];
|
|
@@ -792,7 +832,11 @@ function mapBaseFormatterOptions(formatter, reporter) {
|
|
|
792
832
|
if (formatter.indentWidth !== void 0) options.tabWidth = formatter.indentWidth;
|
|
793
833
|
if (formatter.lineEnding !== void 0) options.endOfLine = formatter.lineEnding;
|
|
794
834
|
if (formatter.bracketSpacing !== void 0) options.bracketSpacing = formatter.bracketSpacing;
|
|
835
|
+
if (formatter.bracketSameLine !== void 0) options.bracketSameLine = formatter.bracketSameLine;
|
|
795
836
|
if (formatter.attributePosition !== void 0) options.singleAttributePerLine = formatter.attributePosition === "multiline";
|
|
837
|
+
const objectWrap = mapBiomeExpandToObjectWrap(formatter.expand, "formatter", reporter);
|
|
838
|
+
if (objectWrap) options.objectWrap = objectWrap;
|
|
839
|
+
if (formatter.trailingNewline !== void 0) options.insertFinalNewline = formatter.trailingNewline;
|
|
796
840
|
if (formatter.formatWithErrors) reporter.warn("Biome's formatWithErrors option is not supported in Oxfmt overrides");
|
|
797
841
|
applyExplicitFormatterOptionPassThrough$1([formatter], options, reporter);
|
|
798
842
|
return options;
|
|
@@ -812,6 +856,12 @@ function mapJavaScriptFormatterOptions(jsFormatter, reporter) {
|
|
|
812
856
|
if (jsFormatter.arrowParentheses !== void 0) options.arrowParens = jsFormatter.arrowParentheses === "always" ? "always" : "avoid";
|
|
813
857
|
if (jsFormatter.bracketSpacing !== void 0) options.bracketSpacing = jsFormatter.bracketSpacing;
|
|
814
858
|
if (jsFormatter.bracketSameLine !== void 0) options.bracketSameLine = jsFormatter.bracketSameLine;
|
|
859
|
+
if (jsFormatter.attributePosition !== void 0) options.singleAttributePerLine = jsFormatter.attributePosition === "multiline";
|
|
860
|
+
const objectWrap = mapBiomeExpandToObjectWrap(jsFormatter.expand, "javascript.formatter", reporter);
|
|
861
|
+
if (objectWrap) options.objectWrap = objectWrap;
|
|
862
|
+
const operatorPosition = mapBiomeOperatorLinebreakToOxfmt(jsFormatter.operatorLinebreak);
|
|
863
|
+
if (operatorPosition) options.experimentalOperatorPosition = operatorPosition;
|
|
864
|
+
if (jsFormatter.trailingNewline !== void 0) options.insertFinalNewline = jsFormatter.trailingNewline;
|
|
815
865
|
applyExplicitFormatterOptionPassThrough$1([jsFormatter], options, reporter);
|
|
816
866
|
return options;
|
|
817
867
|
}
|
|
@@ -824,6 +874,9 @@ function mapJsonFormatterOptions(jsonFormatter, reporter) {
|
|
|
824
874
|
if (jsonFormatter.indentWidth !== void 0) options.tabWidth = jsonFormatter.indentWidth;
|
|
825
875
|
if (jsonFormatter.lineEnding !== void 0) options.endOfLine = jsonFormatter.lineEnding;
|
|
826
876
|
if (jsonFormatter.trailingCommas !== void 0) options.trailingComma = jsonFormatter.trailingCommas === "none" ? "none" : "all";
|
|
877
|
+
const objectWrap = mapBiomeExpandToObjectWrap(jsonFormatter.expand, "json.formatter", reporter);
|
|
878
|
+
if (objectWrap) options.objectWrap = objectWrap;
|
|
879
|
+
if (jsonFormatter.trailingNewline !== void 0) options.insertFinalNewline = jsonFormatter.trailingNewline;
|
|
827
880
|
applyExplicitFormatterOptionPassThrough$1([jsonFormatter], options, reporter);
|
|
828
881
|
return options;
|
|
829
882
|
}
|
|
@@ -836,6 +889,7 @@ function mapCssFormatterOptions(cssFormatter, reporter) {
|
|
|
836
889
|
if (cssFormatter.indentWidth !== void 0) options.tabWidth = cssFormatter.indentWidth;
|
|
837
890
|
if (cssFormatter.lineEnding !== void 0) options.endOfLine = cssFormatter.lineEnding;
|
|
838
891
|
if (cssFormatter.quoteStyle !== void 0) options.singleQuote = cssFormatter.quoteStyle === "single";
|
|
892
|
+
if (cssFormatter.trailingNewline !== void 0) options.insertFinalNewline = cssFormatter.trailingNewline;
|
|
839
893
|
applyExplicitFormatterOptionPassThrough$1([cssFormatter], options, reporter);
|
|
840
894
|
return options;
|
|
841
895
|
}
|
|
@@ -878,6 +932,7 @@ function patternTargetsExtension(pattern, extensions) {
|
|
|
878
932
|
//#region src/formatter-mapper.ts
|
|
879
933
|
const EXPLICIT_OXFMT_OPTION_KEYS = [
|
|
880
934
|
"objectWrap",
|
|
935
|
+
"experimentalOperatorPosition",
|
|
881
936
|
"insertFinalNewline",
|
|
882
937
|
"embeddedLanguageFormatting",
|
|
883
938
|
"htmlWhitespaceSensitivity",
|
|
@@ -906,6 +961,9 @@ const GLOBAL_FORMATTER_KEYS = /* @__PURE__ */ new Set([
|
|
|
906
961
|
"lineWidth",
|
|
907
962
|
"attributePosition",
|
|
908
963
|
"bracketSpacing",
|
|
964
|
+
"bracketSameLine",
|
|
965
|
+
"expand",
|
|
966
|
+
"trailingNewline",
|
|
909
967
|
...EXPLICIT_OXFMT_OPTION_KEYS,
|
|
910
968
|
...Object.keys(LEGACY_EXPLICIT_OXFMT_OPTION_ALIASES)
|
|
911
969
|
]);
|
|
@@ -919,10 +977,13 @@ const JAVASCRIPT_FORMATTER_KEYS = /* @__PURE__ */ new Set([
|
|
|
919
977
|
"arrowParentheses",
|
|
920
978
|
"bracketSameLine",
|
|
921
979
|
"bracketSpacing",
|
|
980
|
+
"expand",
|
|
922
981
|
"indentStyle",
|
|
923
982
|
"indentWidth",
|
|
924
983
|
"lineEnding",
|
|
925
984
|
"lineWidth",
|
|
985
|
+
"operatorLinebreak",
|
|
986
|
+
"trailingNewline",
|
|
926
987
|
...EXPLICIT_OXFMT_OPTION_KEYS,
|
|
927
988
|
...Object.keys(LEGACY_EXPLICIT_OXFMT_OPTION_ALIASES)
|
|
928
989
|
]);
|
|
@@ -1010,9 +1071,13 @@ function mapFormatterOptions(formatter, oxfmtConfig, reporter) {
|
|
|
1010
1071
|
oxfmtConfig.arrowParens = "always";
|
|
1011
1072
|
const bracketSpacing = formatter?.bracketSpacing;
|
|
1012
1073
|
if (bracketSpacing !== void 0) oxfmtConfig.bracketSpacing = bracketSpacing;
|
|
1074
|
+
if (formatter?.bracketSameLine !== void 0) oxfmtConfig.bracketSameLine = formatter.bracketSameLine;
|
|
1013
1075
|
const attributePosition = formatter?.attributePosition;
|
|
1014
1076
|
if (attributePosition === "multiline") oxfmtConfig.singleAttributePerLine = true;
|
|
1015
1077
|
else if (attributePosition === "auto") oxfmtConfig.singleAttributePerLine = false;
|
|
1078
|
+
const objectWrap = mapBiomeExpandToObjectWrap(formatter?.expand, "formatter", reporter);
|
|
1079
|
+
if (objectWrap) oxfmtConfig.objectWrap = objectWrap;
|
|
1080
|
+
if (formatter?.trailingNewline !== void 0) oxfmtConfig.insertFinalNewline = formatter.trailingNewline;
|
|
1016
1081
|
if (formatter?.formatWithErrors) reporter.warn("Biome's formatWithErrors option is not supported in Oxfmt");
|
|
1017
1082
|
}
|
|
1018
1083
|
function mapIgnorePatterns$1(biomeConfig, oxfmtConfig, additionalIgnorePatterns) {
|
|
@@ -1290,6 +1355,40 @@ const OXLINT_CATEGORIES = [
|
|
|
1290
1355
|
"style",
|
|
1291
1356
|
"suspicious"
|
|
1292
1357
|
];
|
|
1358
|
+
/**
|
|
1359
|
+
* The React Compiler rules Oxlint activates for ESLint's `react-hooks/recommended` preset.
|
|
1360
|
+
*
|
|
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.
|
|
1365
|
+
*
|
|
1366
|
+
* @see https://oxc.rs/blog/2026-08-18-react-compiler-support
|
|
1367
|
+
*/
|
|
1368
|
+
const REACT_COMPILER_RECOMMENDED_RULES = [
|
|
1369
|
+
"react/error-boundaries",
|
|
1370
|
+
"react/globals",
|
|
1371
|
+
"react/immutability",
|
|
1372
|
+
"react/incompatible-library",
|
|
1373
|
+
"react/preserve-manual-memoization",
|
|
1374
|
+
"react/purity",
|
|
1375
|
+
"react/refs",
|
|
1376
|
+
"react/set-state-in-effect",
|
|
1377
|
+
"react/set-state-in-render",
|
|
1378
|
+
"react/static-components",
|
|
1379
|
+
"react/unsupported-syntax",
|
|
1380
|
+
"react/use-memo"
|
|
1381
|
+
];
|
|
1382
|
+
/**
|
|
1383
|
+
* Mappings where the Oxlint rule covers only part of what the Biome rule checked. The note
|
|
1384
|
+
* is reported once per migration so the narrowing is visible rather than silent.
|
|
1385
|
+
*/
|
|
1386
|
+
const PARTIAL_RULE_MAPPING_NOTES = {
|
|
1387
|
+
noComponentHookFactories: "Biome rule noComponentHookFactories was mapped to react/no-unstable-nested-components, which reports nested component definitions but not nested custom hook definitions.",
|
|
1388
|
+
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
|
+
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`
|
|
1391
|
+
};
|
|
1293
1392
|
const BIOME_TO_OXLINT_RULE_MAP = {
|
|
1294
1393
|
noAccessKey: "jsx-a11y/no-access-key",
|
|
1295
1394
|
noAdjacentSpacesInRegex: "no-regex-spaces",
|
|
@@ -1311,6 +1410,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1311
1410
|
noBaseToString: "typescript/no-base-to-string",
|
|
1312
1411
|
noBeforeInteractiveScriptOutsideDocument: "nextjs/no-before-interactive-script-outside-document",
|
|
1313
1412
|
noBitwiseOperators: "no-bitwise",
|
|
1413
|
+
noBlankTarget: "react/jsx-no-target-blank",
|
|
1314
1414
|
noCatchAssign: "no-ex-assign",
|
|
1315
1415
|
noChildrenProp: "react/no-children-prop",
|
|
1316
1416
|
noClassAssign: "no-class-assign",
|
|
@@ -1321,6 +1421,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1321
1421
|
"typescript/no-require-imports",
|
|
1322
1422
|
"typescript/no-var-requires"
|
|
1323
1423
|
],
|
|
1424
|
+
noComponentHookFactories: "react/no-unstable-nested-components",
|
|
1324
1425
|
noCompareNegZero: "no-compare-neg-zero",
|
|
1325
1426
|
noConfusingLabels: "no-labels",
|
|
1326
1427
|
noConfusingVoidType: "typescript/no-invalid-void-type",
|
|
@@ -1358,18 +1459,24 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1358
1459
|
noEqualsToNull: "no-eq-null",
|
|
1359
1460
|
noExcessiveClassesPerFile: "max-classes-per-file",
|
|
1360
1461
|
noExcessiveCognitiveComplexity: "complexity",
|
|
1462
|
+
noExcessiveLinesPerFile: "max-lines",
|
|
1463
|
+
noExcessiveLinesPerFunction: "max-lines-per-function",
|
|
1361
1464
|
noExcessiveNestedCallbacks: "max-nested-callbacks",
|
|
1362
1465
|
noExplicitAny: "typescript/no-explicit-any",
|
|
1363
1466
|
noExtendNative: "no-extend-native",
|
|
1364
1467
|
noExtraBooleanCast: "no-extra-boolean-cast",
|
|
1365
1468
|
noExtraNonNullAssertion: "typescript/no-extra-non-null-assertion",
|
|
1366
1469
|
noFallthroughSwitchClause: "no-fallthrough",
|
|
1470
|
+
noFlatMapIdentity: "unicorn/prefer-array-flat",
|
|
1367
1471
|
noFloatingPromises: "typescript/no-floating-promises",
|
|
1368
1472
|
noFocusedTests: ["jest/no-focused-tests", "vitest/no-focused-tests"],
|
|
1369
1473
|
noForEach: "unicorn/no-array-for-each",
|
|
1370
1474
|
noFunctionAssign: "no-func-assign",
|
|
1371
1475
|
noGlobalAssign: "no-global-assign",
|
|
1476
|
+
noGlobalDirnameFilename: "unicorn/prefer-module",
|
|
1372
1477
|
noGlobalEval: "no-eval",
|
|
1478
|
+
noGlobalIsFinite: "unicorn/prefer-number-properties",
|
|
1479
|
+
noGlobalIsNan: "unicorn/prefer-number-properties",
|
|
1373
1480
|
noGlobalObjectCalls: "no-obj-calls",
|
|
1374
1481
|
noHeaderScope: "jsx-a11y/scope",
|
|
1375
1482
|
noHeadElement: "nextjs/no-head-element",
|
|
@@ -1389,6 +1496,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1389
1496
|
noIrregularWhitespace: "no-irregular-whitespace",
|
|
1390
1497
|
noInteractiveElementToNoninteractiveRole: "jsx-a11y/no-interactive-element-to-noninteractive-role",
|
|
1391
1498
|
noInvalidNewBuiltin: "no-new-native-nonconstructor",
|
|
1499
|
+
noJsRestrictedProperties: "no-restricted-properties",
|
|
1392
1500
|
noJsxLiterals: "react/jsx-no-literals",
|
|
1393
1501
|
noJsxNamespace: "react/no-namespace",
|
|
1394
1502
|
noLabelWithoutControl: "jsx-a11y/label-has-associated-control",
|
|
@@ -1403,6 +1511,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1403
1511
|
noMultilineString: "no-multi-str",
|
|
1404
1512
|
noMultiStr: "no-multi-str",
|
|
1405
1513
|
noNegationElse: "no-negated-condition",
|
|
1514
|
+
noNegationInEqualityCheck: "unicorn/no-negation-in-equality-check",
|
|
1406
1515
|
noNewSymbol: "no-new-native-nonconstructor",
|
|
1407
1516
|
noNodejsModules: "import/no-nodejs-modules",
|
|
1408
1517
|
noNamespace: "typescript/no-namespace",
|
|
@@ -1426,12 +1535,14 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1426
1535
|
noProto: "no-proto",
|
|
1427
1536
|
noPrototypeBuiltins: "no-prototype-builtins",
|
|
1428
1537
|
noRedeclare: "no-redeclare",
|
|
1538
|
+
noReactPropAssignments: "react/immutability",
|
|
1429
1539
|
noRedundantAlt: "jsx-a11y/img-redundant-alt",
|
|
1430
1540
|
noRedundantRoles: "jsx-a11y/no-redundant-roles",
|
|
1431
1541
|
noReactStringRefs: "react/no-string-refs",
|
|
1432
1542
|
noDuplicateTestHooks: ["jest/no-duplicate-hooks", "vitest/no-duplicate-hooks"],
|
|
1433
1543
|
noConditionalExpect: ["jest/no-conditional-expect", "vitest/no-conditional-expect"],
|
|
1434
1544
|
noExcessiveNestedTestSuites: ["jest/max-nested-describe", "vitest/max-nested-describe"],
|
|
1545
|
+
noExportsInTest: "jest/no-export",
|
|
1435
1546
|
noIdenticalTestTitle: ["jest/no-identical-title", "vitest/no-identical-title"],
|
|
1436
1547
|
noMisplacedAssertion: ["jest/no-standalone-expect", "vitest/no-standalone-expect"],
|
|
1437
1548
|
noRenderReturnValue: "react/no-render-return-value",
|
|
@@ -1469,6 +1580,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1469
1580
|
noUnreachable: "no-unreachable",
|
|
1470
1581
|
noUnreachableSuper: "constructor-super",
|
|
1471
1582
|
noUnsafeDeclarationMerging: "typescript/no-unsafe-declaration-merging",
|
|
1583
|
+
noUnsafeTypeAssertion: "typescript/no-unsafe-type-assertion",
|
|
1472
1584
|
noUnsafeFinally: "no-unsafe-finally",
|
|
1473
1585
|
noUnsafeNegation: "no-unsafe-negation",
|
|
1474
1586
|
noUnsafeOptionalChaining: "no-unsafe-optional-chaining",
|
|
@@ -1479,8 +1591,10 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1479
1591
|
noUnusedVariables: "no-unused-vars",
|
|
1480
1592
|
noUnwantedPolyfillio: "nextjs/no-unwanted-polyfillio",
|
|
1481
1593
|
noUselessCatch: "no-useless-catch",
|
|
1594
|
+
noUselessContinue: "no-continue",
|
|
1482
1595
|
noUselessCatchBinding: "unicorn/prefer-optional-catch-binding",
|
|
1483
1596
|
noUselessConstructor: "no-useless-constructor",
|
|
1597
|
+
noUselessElse: "no-else-return",
|
|
1484
1598
|
noUselessEmptyExport: "typescript/no-useless-empty-export",
|
|
1485
1599
|
noUselessEscapeInRegex: "no-useless-escape",
|
|
1486
1600
|
noUselessEscapeInString: "no-useless-escape",
|
|
@@ -1497,6 +1611,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1497
1611
|
noUselessTypeConstraint: "typescript/no-unnecessary-type-constraint",
|
|
1498
1612
|
noUselessTypeConversion: "typescript/no-unnecessary-type-conversion",
|
|
1499
1613
|
noUselessUndefined: "unicorn/no-useless-undefined",
|
|
1614
|
+
noUselessUndefinedInitialization: "unicorn/no-useless-undefined",
|
|
1500
1615
|
noVoid: "no-void",
|
|
1501
1616
|
noVar: "no-var",
|
|
1502
1617
|
noVoidElementsWithChildren: "react/void-dom-elements-no-children",
|
|
@@ -1537,6 +1652,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1537
1652
|
useConsistentMethodSignatures: "typescript/method-signature-style",
|
|
1538
1653
|
useConsistentTypeDefinitions: "typescript/consistent-type-definitions",
|
|
1539
1654
|
useConsistentMemberAccessibility: "typescript/explicit-member-accessibility",
|
|
1655
|
+
useConsistentObjectDefinitions: "object-shorthand",
|
|
1540
1656
|
useConsistentTestIt: ["jest/consistent-test-it", "vitest/consistent-test-it"],
|
|
1541
1657
|
useConst: "prefer-const",
|
|
1542
1658
|
useDateNow: "unicorn/prefer-date-now",
|
|
@@ -1551,6 +1667,8 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1551
1667
|
useErrorMessage: "unicorn/error-message",
|
|
1552
1668
|
useExpect: ["jest/expect-expect", "vitest/expect-expect"],
|
|
1553
1669
|
useExplicitLengthCheck: "unicorn/explicit-length-check",
|
|
1670
|
+
useExplicitReturnType: "typescript/explicit-function-return-type",
|
|
1671
|
+
useExplicitType: "typescript/explicit-function-return-type",
|
|
1554
1672
|
useExponentiationOperator: "prefer-exponentiation-operator",
|
|
1555
1673
|
useExportsLast: "import/exports-last",
|
|
1556
1674
|
useExportType: "typescript/consistent-type-exports",
|
|
@@ -1573,6 +1691,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1573
1691
|
useHookAtTopLevel: "react/rules-of-hooks",
|
|
1574
1692
|
useIframeSandbox: "react/iframe-missing-sandbox",
|
|
1575
1693
|
useIframeTitle: "jsx-a11y/iframe-has-title",
|
|
1694
|
+
useImportExtensions: "import/extensions",
|
|
1576
1695
|
useImportsFirst: "import/first",
|
|
1577
1696
|
useImportType: "typescript/consistent-type-imports",
|
|
1578
1697
|
useIncludes: "typescript/prefer-includes",
|
|
@@ -1602,6 +1721,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1602
1721
|
useParseIntRadix: "radix",
|
|
1603
1722
|
useReadonlyClassProperties: "typescript/prefer-readonly",
|
|
1604
1723
|
useReactFunctionComponentDefinition: "react/function-component-definition",
|
|
1724
|
+
useReactCompiler: REACT_COMPILER_RECOMMENDED_RULES,
|
|
1605
1725
|
useReactFunctionComponents: "react/prefer-function-component",
|
|
1606
1726
|
useReduceTypeParameter: "typescript/prefer-reduce-type-parameter",
|
|
1607
1727
|
useRegexLiterals: "prefer-regex-literals",
|
|
@@ -1611,6 +1731,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1611
1731
|
useSelfClosingElements: "react/self-closing-comp",
|
|
1612
1732
|
useShorthandAssign: "operator-assignment",
|
|
1613
1733
|
useShorthandFunctionType: "typescript/prefer-function-type",
|
|
1734
|
+
useSingleVarDeclarator: "one-var",
|
|
1614
1735
|
useSimplifiedLogicExpression: "unicorn/prefer-logical-operator-over-ternary",
|
|
1615
1736
|
useSpread: "prefer-spread",
|
|
1616
1737
|
useSpreadOverApply: "prefer-spread",
|
|
@@ -1639,6 +1760,7 @@ const BIOME_TO_OXLINT_RULE_MAP = {
|
|
|
1639
1760
|
useYield: "require-yield"
|
|
1640
1761
|
};
|
|
1641
1762
|
const WARNED_UNMAPPED_RULES_BY_REPORTER = /* @__PURE__ */ new WeakMap();
|
|
1763
|
+
const WARNED_PARTIAL_MAPPINGS_BY_REPORTER = /* @__PURE__ */ new WeakMap();
|
|
1642
1764
|
const WARNED_UNSUPPORTED_SEVERITIES_BY_REPORTER = /* @__PURE__ */ new WeakMap();
|
|
1643
1765
|
const OXLINT_SEVERITY_NORMALIZATION = {
|
|
1644
1766
|
allow: "off",
|
|
@@ -1663,6 +1785,20 @@ function mapBiomeRuleOptionsToOxlintSeverity(biomeName, severity, biomeSeverity,
|
|
|
1663
1785
|
if (biomeName === "noExcessiveNestedCallbacks") return [severity, { max: options && isNonNegativeInteger(options.max) ? options.max : 5 }];
|
|
1664
1786
|
if (biomeName === "useErrorCause") return [severity, { requireCatchParameter: options && typeof options.requireCatchParameter === "boolean" ? options.requireCatchParameter : true }];
|
|
1665
1787
|
if (biomeName === "useMaxParams") return [severity, { max: options && isNonNegativeInteger(options.max) ? options.max : 4 }];
|
|
1788
|
+
if (biomeName === "noExcessiveLinesPerFile") return [severity, {
|
|
1789
|
+
max: options && isNonNegativeInteger(options.maxLines) ? options.maxLines : 300,
|
|
1790
|
+
skipBlankLines: options?.skipBlankLines === true
|
|
1791
|
+
}];
|
|
1792
|
+
if (biomeName === "noExcessiveLinesPerFunction") return [severity, {
|
|
1793
|
+
max: options && isNonNegativeInteger(options.maxLines) ? options.maxLines : 50,
|
|
1794
|
+
skipBlankLines: options?.skipBlankLines === true,
|
|
1795
|
+
IIFEs: options?.skipIifes !== true
|
|
1796
|
+
}];
|
|
1797
|
+
if (biomeName === "useSingleVarDeclarator") return [severity, "never"];
|
|
1798
|
+
if (biomeName === "useImportExtensions") {
|
|
1799
|
+
if (options?.extensionMappings !== void 0 || options?.forceJsExtensions !== void 0) reporter.loss("Biome rule useImportExtensions options \"extensionMappings\" and \"forceJsExtensions\" are not supported by Oxlint import/extensions; the rule requires an extension without rewriting it.");
|
|
1800
|
+
return [severity, "ignorePackages"];
|
|
1801
|
+
}
|
|
1666
1802
|
if (biomeName === "noTsIgnore") return [severity, {
|
|
1667
1803
|
"ts-ignore": true,
|
|
1668
1804
|
"ts-expect-error": false,
|
|
@@ -1674,6 +1810,10 @@ function mapBiomeRuleOptionsToOxlintSeverity(biomeName, severity, biomeSeverity,
|
|
|
1674
1810
|
const { words } = options;
|
|
1675
1811
|
return Array.isArray(words) && words.every((value) => typeof value === "string") ? [severity, { words }] : severity;
|
|
1676
1812
|
}
|
|
1813
|
+
if (biomeName === "noConsole") {
|
|
1814
|
+
const { allow } = options;
|
|
1815
|
+
return Array.isArray(allow) && allow.every((value) => typeof value === "string") ? [severity, { allow }] : severity;
|
|
1816
|
+
}
|
|
1677
1817
|
if (biomeName === "noEmptySource") {
|
|
1678
1818
|
if (options.allowComments === true) reporter.loss("Biome rule noEmptySource option \"allowComments\" is not supported by Oxlint unicorn/no-empty-file and was not migrated.");
|
|
1679
1819
|
return severity;
|
|
@@ -1714,6 +1854,22 @@ function mapBiomeRuleOptionsToOxlintSeverity(biomeName, severity, biomeSeverity,
|
|
|
1714
1854
|
{ requireReturnForObjectLiteral: options.requireForObjectLiteral }
|
|
1715
1855
|
] : [severity, mode];
|
|
1716
1856
|
}
|
|
1857
|
+
if (biomeName === "noJsRestrictedProperties") {
|
|
1858
|
+
const { entries } = options;
|
|
1859
|
+
if (!Array.isArray(entries) || !entries.every(isRecord)) return severity;
|
|
1860
|
+
return [severity, ...entries];
|
|
1861
|
+
}
|
|
1862
|
+
if (biomeName === "useConsistentObjectDefinitions") {
|
|
1863
|
+
const { syntax } = options;
|
|
1864
|
+
return syntax === "shorthand" ? [severity, "always"] : syntax === "explicit" ? [severity, "never"] : severity;
|
|
1865
|
+
}
|
|
1866
|
+
if (biomeName === "useExplicitReturnType") {
|
|
1867
|
+
const oxlintOptions = {};
|
|
1868
|
+
if (typeof options.allowExpressions === "boolean") oxlintOptions.allowExpressions = options.allowExpressions;
|
|
1869
|
+
if (typeof options.allowIifes === "boolean") oxlintOptions.allowIIFEs = options.allowIifes;
|
|
1870
|
+
if (Array.isArray(options.allowedNames) && options.allowedNames.every((value) => typeof value === "string")) oxlintOptions.allowedNames = options.allowedNames;
|
|
1871
|
+
return Object.keys(oxlintOptions).length > 0 ? [severity, oxlintOptions] : severity;
|
|
1872
|
+
}
|
|
1717
1873
|
if (biomeName === "useConsistentMethodSignatures") {
|
|
1718
1874
|
const { style } = options;
|
|
1719
1875
|
return style === "method" || style === "property" ? [severity, style] : severity;
|
|
@@ -1780,10 +1936,24 @@ function mapBiomeRuleSeverity(severity, reporter, biomeRuleName) {
|
|
|
1780
1936
|
}
|
|
1781
1937
|
function mapBiomeRuleToOxlintRules(biomeName, reporter) {
|
|
1782
1938
|
const mapped = BIOME_TO_OXLINT_RULE_MAP[biomeName];
|
|
1783
|
-
if (mapped)
|
|
1939
|
+
if (mapped) {
|
|
1940
|
+
const partialMappingNote = PARTIAL_RULE_MAPPING_NOTES[biomeName];
|
|
1941
|
+
if (partialMappingNote) warnPartialMappingOnce(biomeName, partialMappingNote, reporter);
|
|
1942
|
+
return [...new Set((Array.isArray(mapped) ? mapped : [mapped]).map((ruleName) => normalizeOxlintRuleName(ruleName)))];
|
|
1943
|
+
}
|
|
1784
1944
|
warnUnmappedRuleOnce(biomeName, reporter);
|
|
1785
1945
|
return [];
|
|
1786
1946
|
}
|
|
1947
|
+
function warnPartialMappingOnce(biomeName, note, reporter) {
|
|
1948
|
+
let warnedRules = WARNED_PARTIAL_MAPPINGS_BY_REPORTER.get(reporter);
|
|
1949
|
+
if (!warnedRules) {
|
|
1950
|
+
warnedRules = /* @__PURE__ */ new Set();
|
|
1951
|
+
WARNED_PARTIAL_MAPPINGS_BY_REPORTER.set(reporter, warnedRules);
|
|
1952
|
+
}
|
|
1953
|
+
if (warnedRules.has(biomeName)) return;
|
|
1954
|
+
warnedRules.add(biomeName);
|
|
1955
|
+
reporter.loss(note);
|
|
1956
|
+
}
|
|
1787
1957
|
function warnUnmappedRuleOnce(biomeName, reporter) {
|
|
1788
1958
|
let warnedRules = WARNED_UNMAPPED_RULES_BY_REPORTER.get(reporter);
|
|
1789
1959
|
if (!warnedRules) {
|
|
@@ -2121,15 +2291,19 @@ async function updatePackageJson(projectDir, reporter, dryRun, options = {}) {
|
|
|
2121
2291
|
summary.found = true;
|
|
2122
2292
|
let modified = false;
|
|
2123
2293
|
const updateScriptsEnabled = options.updateScripts ?? false;
|
|
2294
|
+
const domModeEnabled = options.dom ?? false;
|
|
2124
2295
|
const removeBiomeAllowed = options.removeBiome ?? false;
|
|
2125
2296
|
const typeAwareProfile = options.typeAwareProfile ?? "standard";
|
|
2126
2297
|
const typeCheckEnabled = options.typeCheck ?? typeAwareProfile === "strict";
|
|
2127
2298
|
const typeAwareEnabled = options.typeAware ?? (typeCheckEnabled || typeAwareProfile === "strict");
|
|
2128
|
-
const needsTypeAwareDependency = typeAwareEnabled || typeCheckEnabled;
|
|
2299
|
+
const needsTypeAwareDependency = typeAwareEnabled || typeCheckEnabled || domModeEnabled;
|
|
2129
2300
|
const fixStrategy = options.fixStrategy ?? "safe";
|
|
2130
2301
|
const oxlintCommand = buildConfiguredCommand("oxlint", packageJsonPath, options.oxlintConfigPath);
|
|
2131
2302
|
const oxfmtCommand = buildConfiguredCommand("oxfmt", packageJsonPath, options.oxfmtConfigPath);
|
|
2132
|
-
if (
|
|
2303
|
+
if (domModeEnabled) {
|
|
2304
|
+
packageJson.scripts ??= {};
|
|
2305
|
+
modified = applyDomScriptPreset(packageJson.scripts, summary.scriptsUpdated, oxlintCommand, oxfmtCommand) || modified;
|
|
2306
|
+
} else if (updateScriptsEnabled && packageJson.scripts) modified = updateScripts(packageJson.scripts, reporter, summary.scriptsUpdated, {
|
|
2133
2307
|
typeAwareEnabled,
|
|
2134
2308
|
typeCheckEnabled,
|
|
2135
2309
|
fixStrategy,
|
|
@@ -2204,6 +2378,32 @@ async function detectLockfile(packageRoot, dependenciesChanged) {
|
|
|
2204
2378
|
};
|
|
2205
2379
|
}
|
|
2206
2380
|
}
|
|
2381
|
+
function applyDomScriptPreset(scripts, updates, oxlintCommand, oxfmtCommand) {
|
|
2382
|
+
let modified = false;
|
|
2383
|
+
const preset = {
|
|
2384
|
+
check: `${oxlintCommand} . && ${oxfmtCommand} --check .`,
|
|
2385
|
+
"check:fix": `${oxlintCommand} --fix . && ${oxfmtCommand} --write .`,
|
|
2386
|
+
format: `${oxfmtCommand} --write .`,
|
|
2387
|
+
"format:check": `${oxfmtCommand} --check .`,
|
|
2388
|
+
lint: `${oxlintCommand} -f github . > lint.md 2>&1`,
|
|
2389
|
+
"lint:fix": `${oxlintCommand} -f stylish --fix .`,
|
|
2390
|
+
"lint:fix-unsafe": `${oxlintCommand} -f stylish --react-plugin --import-plugin --react-perf-plugin --nextjs-plugin --type-aware --type-check --vitest-plugin --fix --fix-suggestions --fix-dangerously .`,
|
|
2391
|
+
"check:fix-suggestions": `${oxlintCommand} -f stylish --react-plugin --import-plugin --react-perf-plugin --nextjs-plugin --type-aware --type-check --vitest-plugin --fix --fix-suggestions . && ${oxfmtCommand} --write .`,
|
|
2392
|
+
"type-check": "tsc --noEmit"
|
|
2393
|
+
};
|
|
2394
|
+
for (const [scriptName, scriptValue] of Object.entries(preset)) {
|
|
2395
|
+
const before = scripts[scriptName];
|
|
2396
|
+
if (before === scriptValue) continue;
|
|
2397
|
+
scripts[scriptName] = scriptValue;
|
|
2398
|
+
updates.push({
|
|
2399
|
+
name: scriptName,
|
|
2400
|
+
before: before ?? "<missing>",
|
|
2401
|
+
after: scriptValue
|
|
2402
|
+
});
|
|
2403
|
+
modified = true;
|
|
2404
|
+
}
|
|
2405
|
+
return modified;
|
|
2406
|
+
}
|
|
2207
2407
|
function updateScripts(scripts, reporter, updates, options) {
|
|
2208
2408
|
let modified = false;
|
|
2209
2409
|
const lintBase = buildLintBaseCommand(options.oxlintCommand, options.typeAwareEnabled, options.typeCheckEnabled);
|
|
@@ -2810,6 +3010,7 @@ async function runMigration(options, reporter, biomeConfigPath) {
|
|
|
2810
3010
|
const packageJsonErrorCount = reporter.getErrors().length;
|
|
2811
3011
|
packageJsonSummary = await updatePackageJson(projectDir, reporter, false, {
|
|
2812
3012
|
updateScripts: options.updateScripts,
|
|
3013
|
+
dom: options.dom,
|
|
2813
3014
|
removeBiome: cleanupAllowed,
|
|
2814
3015
|
typeAware: typeAwareEnabled,
|
|
2815
3016
|
typeCheck: typeCheckEnabled,
|
|
@@ -2838,6 +3039,7 @@ async function runMigration(options, reporter, biomeConfigPath) {
|
|
|
2838
3039
|
const packageJsonErrorCount = reporter.getErrors().length;
|
|
2839
3040
|
packageJsonSummary = await updatePackageJson(projectDir, reporter, true, {
|
|
2840
3041
|
updateScripts: options.updateScripts,
|
|
3042
|
+
dom: options.dom,
|
|
2841
3043
|
removeBiome: cleanupAllowed,
|
|
2842
3044
|
typeAware: typeAwareEnabled,
|
|
2843
3045
|
typeCheck: typeCheckEnabled,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "biome-to-oxc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Migrate from Biome to Oxc ecosystem (oxlint + oxfmt + oxlint-tsgolint)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"biome",
|
|
@@ -32,6 +32,24 @@
|
|
|
32
32
|
"types": "./dist/src/index.d.mts",
|
|
33
33
|
"import": "./dist/src/index.mjs"
|
|
34
34
|
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "vitest",
|
|
37
|
+
"test:run": "vitest --run",
|
|
38
|
+
"test:coverage": "vitest --run --coverage",
|
|
39
|
+
"format": "oxfmt --write .",
|
|
40
|
+
"format:check": "oxfmt --check .",
|
|
41
|
+
"lint": "oxlint .",
|
|
42
|
+
"lint:fix": "oxlint --fix .",
|
|
43
|
+
"lint:fix-unsafe": "oxlint --import-plugin --node-plugin --type-aware --type-check --vitest-plugin --fix --fix-suggestions --fix-dangerously .",
|
|
44
|
+
"check:fix-suggestions": "oxlint --import-plugin --node-plugin --type-aware --type-check --vitest-plugin --fix --fix-suggestions . && oxfmt --write .",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"docs:sync": "node scripts/sync-rule-inventories.ts",
|
|
47
|
+
"docs:check": "node scripts/sync-rule-inventories.ts --check",
|
|
48
|
+
"check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm docs:check && pnpm test:run",
|
|
49
|
+
"build": "tsdown",
|
|
50
|
+
"dev": "tsdown --watch",
|
|
51
|
+
"prepublishOnly": "pnpm check && pnpm build"
|
|
52
|
+
},
|
|
35
53
|
"dependencies": {
|
|
36
54
|
"commander": "15.0.0",
|
|
37
55
|
"jsonc-parser": "next",
|
|
@@ -40,34 +58,20 @@
|
|
|
40
58
|
},
|
|
41
59
|
"devDependencies": {
|
|
42
60
|
"@arethetypeswrong/core": "^0.18.5",
|
|
43
|
-
"@biomejs/biome": "^2.5.
|
|
61
|
+
"@biomejs/biome": "^2.5.9",
|
|
44
62
|
"@types/node": "^26.2.0",
|
|
45
|
-
"@vitest/coverage-v8": "^4.1.
|
|
46
|
-
"oxfmt": "^0.
|
|
47
|
-
"oxlint": "^1.
|
|
63
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
64
|
+
"oxfmt": "^0.64.0",
|
|
65
|
+
"oxlint": "^1.79.0",
|
|
48
66
|
"oxlint-tsgolint": "^7.0.2001",
|
|
49
|
-
"publint": "^0.3.
|
|
67
|
+
"publint": "^0.3.24",
|
|
50
68
|
"tsdown": "^0.22.14",
|
|
51
|
-
"typescript": "
|
|
52
|
-
"vitest": "^4.1.
|
|
69
|
+
"typescript": "next",
|
|
70
|
+
"vitest": "^4.1.11"
|
|
53
71
|
},
|
|
54
72
|
"engines": {
|
|
55
73
|
"node": ">=24.19.0",
|
|
56
|
-
"pnpm": ">=11.
|
|
74
|
+
"pnpm": ">=11.22.0"
|
|
57
75
|
},
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
"test:run": "vitest --run",
|
|
61
|
-
"test:coverage": "vitest --run --coverage",
|
|
62
|
-
"format": "oxfmt --write .",
|
|
63
|
-
"format:check": "oxfmt --check .",
|
|
64
|
-
"lint": "oxlint .",
|
|
65
|
-
"lint:fix": "oxlint --fix .",
|
|
66
|
-
"lint:fix-unsafe": "oxlint --import-plugin --node-plugin --type-aware --type-check --vitest-plugin --fix --fix-suggestions --fix-dangerously .",
|
|
67
|
-
"check:fix-suggestions": "oxlint --import-plugin --node-plugin --type-aware --type-check --vitest-plugin --fix --fix-suggestions . && oxfmt --write .",
|
|
68
|
-
"typecheck": "tsc --noEmit",
|
|
69
|
-
"check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm test:run",
|
|
70
|
-
"build": "tsdown",
|
|
71
|
-
"dev": "tsdown --watch"
|
|
72
|
-
}
|
|
73
|
-
}
|
|
76
|
+
"packageManager": "pnpm@11.22.0"
|
|
77
|
+
}
|