@schemashift/zod-valibot 0.8.0 → 0.10.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 +31 -2
- package/dist/index.cjs +361 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +359 -0
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/dist/index.d.cts
CHANGED
|
@@ -55,4 +55,71 @@ declare class ZodToValibotTransformer {
|
|
|
55
55
|
private transformCallChainFallback;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
declare function createValibotToZodHandler(): TransformHandler;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Valibot → Zod transformer.
|
|
62
|
+
*
|
|
63
|
+
* Converts Valibot's pipe-based API back to Zod's fluent method chain API.
|
|
64
|
+
* Uses AST-based import handling for safety, with text-based pipe expression
|
|
65
|
+
* transformation for the complex pipe-to-chain conversions.
|
|
66
|
+
*
|
|
67
|
+
* Valibot: v.pipe(v.string(), v.email(), v.minLength(5), v.maxLength(100))
|
|
68
|
+
* Zod: z.string().email().min(5).max(100)
|
|
69
|
+
*
|
|
70
|
+
* Valibot: v.optional(v.string())
|
|
71
|
+
* Zod: z.string().optional()
|
|
72
|
+
*
|
|
73
|
+
* Valibot: v.partial(v.object({ name: v.string() }))
|
|
74
|
+
* Zod: z.object({ name: z.string() }).partial()
|
|
75
|
+
*/
|
|
76
|
+
declare class ValibotToZodTransformer {
|
|
77
|
+
private errors;
|
|
78
|
+
private warnings;
|
|
79
|
+
private stringLiteralRanges;
|
|
80
|
+
private commentRanges;
|
|
81
|
+
transform(sourceFile: SourceFile): TransformResult;
|
|
82
|
+
/**
|
|
83
|
+
* Collect string literal and comment ranges from the AST
|
|
84
|
+
* so text-based transforms can avoid modifying them.
|
|
85
|
+
*/
|
|
86
|
+
private collectProtectedRanges;
|
|
87
|
+
/**
|
|
88
|
+
* Check if a position is inside a protected range (string literal or comment).
|
|
89
|
+
*/
|
|
90
|
+
private isProtected;
|
|
91
|
+
/**
|
|
92
|
+
* AST-based import transformation.
|
|
93
|
+
* Replaces valibot imports with zod imports using the AST.
|
|
94
|
+
*/
|
|
95
|
+
private transformImportsAST;
|
|
96
|
+
private transformTypeHelpers;
|
|
97
|
+
/**
|
|
98
|
+
* Transform Valibot wrapper functions to Zod method chains.
|
|
99
|
+
* v.optional(schema) → schema.optional()
|
|
100
|
+
* v.nullable(schema) → schema.nullable()
|
|
101
|
+
* v.nullish(schema) → schema.nullish()
|
|
102
|
+
* v.readonly(schema) → schema.readonly()
|
|
103
|
+
* v.partial(schema) → schema.partial()
|
|
104
|
+
* v.required(schema) → schema.required()
|
|
105
|
+
*/
|
|
106
|
+
private transformWrappers;
|
|
107
|
+
/**
|
|
108
|
+
* Replace wrapper calls using balanced parenthesis matching.
|
|
109
|
+
* Skips matches inside string literals and comments.
|
|
110
|
+
*/
|
|
111
|
+
private replaceWrapperCall;
|
|
112
|
+
/**
|
|
113
|
+
* Transform v.pipe(factory, ...validators) to factory.validator1().validator2()
|
|
114
|
+
* Skips matches inside string literals and comments.
|
|
115
|
+
*/
|
|
116
|
+
private transformPipeExpressions;
|
|
117
|
+
/**
|
|
118
|
+
* Split arguments at top-level commas (not inside nested parens/brackets/braces).
|
|
119
|
+
*/
|
|
120
|
+
private splitTopLevelArgs;
|
|
121
|
+
private convertPipeValidator;
|
|
122
|
+
private transformFactories;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { FACTORY_MAPPINGS, MODIFIER_METHODS, NUMBER_VALIDATION_MAPPINGS, OBJECT_METHODS, VALIDATION_MAPPINGS, ValibotToZodTransformer, ZodToValibotTransformer, createValibotToZodHandler, createZodToValibotHandler };
|
package/dist/index.d.ts
CHANGED
|
@@ -55,4 +55,71 @@ declare class ZodToValibotTransformer {
|
|
|
55
55
|
private transformCallChainFallback;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
declare function createValibotToZodHandler(): TransformHandler;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Valibot → Zod transformer.
|
|
62
|
+
*
|
|
63
|
+
* Converts Valibot's pipe-based API back to Zod's fluent method chain API.
|
|
64
|
+
* Uses AST-based import handling for safety, with text-based pipe expression
|
|
65
|
+
* transformation for the complex pipe-to-chain conversions.
|
|
66
|
+
*
|
|
67
|
+
* Valibot: v.pipe(v.string(), v.email(), v.minLength(5), v.maxLength(100))
|
|
68
|
+
* Zod: z.string().email().min(5).max(100)
|
|
69
|
+
*
|
|
70
|
+
* Valibot: v.optional(v.string())
|
|
71
|
+
* Zod: z.string().optional()
|
|
72
|
+
*
|
|
73
|
+
* Valibot: v.partial(v.object({ name: v.string() }))
|
|
74
|
+
* Zod: z.object({ name: z.string() }).partial()
|
|
75
|
+
*/
|
|
76
|
+
declare class ValibotToZodTransformer {
|
|
77
|
+
private errors;
|
|
78
|
+
private warnings;
|
|
79
|
+
private stringLiteralRanges;
|
|
80
|
+
private commentRanges;
|
|
81
|
+
transform(sourceFile: SourceFile): TransformResult;
|
|
82
|
+
/**
|
|
83
|
+
* Collect string literal and comment ranges from the AST
|
|
84
|
+
* so text-based transforms can avoid modifying them.
|
|
85
|
+
*/
|
|
86
|
+
private collectProtectedRanges;
|
|
87
|
+
/**
|
|
88
|
+
* Check if a position is inside a protected range (string literal or comment).
|
|
89
|
+
*/
|
|
90
|
+
private isProtected;
|
|
91
|
+
/**
|
|
92
|
+
* AST-based import transformation.
|
|
93
|
+
* Replaces valibot imports with zod imports using the AST.
|
|
94
|
+
*/
|
|
95
|
+
private transformImportsAST;
|
|
96
|
+
private transformTypeHelpers;
|
|
97
|
+
/**
|
|
98
|
+
* Transform Valibot wrapper functions to Zod method chains.
|
|
99
|
+
* v.optional(schema) → schema.optional()
|
|
100
|
+
* v.nullable(schema) → schema.nullable()
|
|
101
|
+
* v.nullish(schema) → schema.nullish()
|
|
102
|
+
* v.readonly(schema) → schema.readonly()
|
|
103
|
+
* v.partial(schema) → schema.partial()
|
|
104
|
+
* v.required(schema) → schema.required()
|
|
105
|
+
*/
|
|
106
|
+
private transformWrappers;
|
|
107
|
+
/**
|
|
108
|
+
* Replace wrapper calls using balanced parenthesis matching.
|
|
109
|
+
* Skips matches inside string literals and comments.
|
|
110
|
+
*/
|
|
111
|
+
private replaceWrapperCall;
|
|
112
|
+
/**
|
|
113
|
+
* Transform v.pipe(factory, ...validators) to factory.validator1().validator2()
|
|
114
|
+
* Skips matches inside string literals and comments.
|
|
115
|
+
*/
|
|
116
|
+
private transformPipeExpressions;
|
|
117
|
+
/**
|
|
118
|
+
* Split arguments at top-level commas (not inside nested parens/brackets/braces).
|
|
119
|
+
*/
|
|
120
|
+
private splitTopLevelArgs;
|
|
121
|
+
private convertPipeValidator;
|
|
122
|
+
private transformFactories;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { FACTORY_MAPPINGS, MODIFIER_METHODS, NUMBER_VALIDATION_MAPPINGS, OBJECT_METHODS, VALIDATION_MAPPINGS, ValibotToZodTransformer, ZodToValibotTransformer, createValibotToZodHandler, createZodToValibotHandler };
|
package/dist/index.js
CHANGED
|
@@ -443,13 +443,372 @@ function createZodToValibotHandler() {
|
|
|
443
443
|
}
|
|
444
444
|
};
|
|
445
445
|
}
|
|
446
|
+
|
|
447
|
+
// src/valibot-to-zod-transformer.ts
|
|
448
|
+
import { SyntaxKind } from "ts-morph";
|
|
449
|
+
var VALIBOT_TO_ZOD_FACTORY = {
|
|
450
|
+
"v.string": "z.string",
|
|
451
|
+
"v.number": "z.number",
|
|
452
|
+
"v.boolean": "z.boolean",
|
|
453
|
+
"v.date": "z.date",
|
|
454
|
+
"v.bigint": "z.bigint",
|
|
455
|
+
"v.symbol": "z.symbol",
|
|
456
|
+
"v.undefined_": "z.undefined",
|
|
457
|
+
"v.null_": "z.null",
|
|
458
|
+
"v.void_": "z.void",
|
|
459
|
+
"v.any": "z.any",
|
|
460
|
+
"v.unknown": "z.unknown",
|
|
461
|
+
"v.never": "z.never",
|
|
462
|
+
"v.nan": "z.nan",
|
|
463
|
+
"v.literal": "z.literal",
|
|
464
|
+
"v.picklist": "z.enum",
|
|
465
|
+
"v.enum_": "z.nativeEnum",
|
|
466
|
+
"v.array": "z.array",
|
|
467
|
+
"v.object": "z.object",
|
|
468
|
+
"v.record": "z.record",
|
|
469
|
+
"v.tuple": "z.tuple",
|
|
470
|
+
"v.union": "z.union",
|
|
471
|
+
"v.variant": "z.discriminatedUnion",
|
|
472
|
+
"v.intersect": "z.intersection",
|
|
473
|
+
"v.lazy": "z.lazy",
|
|
474
|
+
"v.promise": "z.promise",
|
|
475
|
+
"v.instance": "z.instanceof"
|
|
476
|
+
};
|
|
477
|
+
var PIPE_TO_CHAIN = {
|
|
478
|
+
"v.email": ".email",
|
|
479
|
+
"v.url": ".url",
|
|
480
|
+
"v.uuid": ".uuid",
|
|
481
|
+
"v.cuid2": ".cuid2",
|
|
482
|
+
"v.ulid": ".ulid",
|
|
483
|
+
"v.regex": ".regex",
|
|
484
|
+
"v.ip": ".ip",
|
|
485
|
+
"v.isoDateTime": ".datetime",
|
|
486
|
+
"v.isoDate": ".date",
|
|
487
|
+
"v.isoTime": ".time",
|
|
488
|
+
"v.emoji": ".emoji",
|
|
489
|
+
"v.includes": ".includes",
|
|
490
|
+
"v.startsWith": ".startsWith",
|
|
491
|
+
"v.endsWith": ".endsWith",
|
|
492
|
+
"v.trim": ".trim",
|
|
493
|
+
"v.toLowerCase": ".toLowerCase",
|
|
494
|
+
"v.toUpperCase": ".toUpperCase",
|
|
495
|
+
"v.minLength": ".min",
|
|
496
|
+
"v.maxLength": ".max",
|
|
497
|
+
"v.length": ".length",
|
|
498
|
+
"v.minValue": ".min",
|
|
499
|
+
"v.maxValue": ".max",
|
|
500
|
+
"v.integer": ".int",
|
|
501
|
+
"v.finite": ".finite",
|
|
502
|
+
"v.safeInteger": ".safe",
|
|
503
|
+
"v.multipleOf": ".multipleOf",
|
|
504
|
+
"v.nonEmpty": ".nonempty"
|
|
505
|
+
};
|
|
506
|
+
var ValibotToZodTransformer = class {
|
|
507
|
+
errors = [];
|
|
508
|
+
warnings = [];
|
|
509
|
+
stringLiteralRanges = [];
|
|
510
|
+
commentRanges = [];
|
|
511
|
+
transform(sourceFile) {
|
|
512
|
+
this.errors = [];
|
|
513
|
+
this.warnings = [];
|
|
514
|
+
this.stringLiteralRanges = [];
|
|
515
|
+
this.commentRanges = [];
|
|
516
|
+
const filePath = sourceFile.getFilePath();
|
|
517
|
+
const originalCode = sourceFile.getFullText();
|
|
518
|
+
try {
|
|
519
|
+
this.collectProtectedRanges(sourceFile);
|
|
520
|
+
this.transformImportsAST(sourceFile);
|
|
521
|
+
let text = sourceFile.getFullText();
|
|
522
|
+
text = this.transformTypeHelpers(text);
|
|
523
|
+
text = this.transformWrappers(text);
|
|
524
|
+
text = this.transformPipeExpressions(text);
|
|
525
|
+
text = this.transformFactories(text);
|
|
526
|
+
sourceFile.replaceWithText(text);
|
|
527
|
+
return {
|
|
528
|
+
success: this.errors.length === 0,
|
|
529
|
+
filePath,
|
|
530
|
+
originalCode,
|
|
531
|
+
transformedCode: sourceFile.getFullText(),
|
|
532
|
+
errors: this.errors,
|
|
533
|
+
warnings: this.warnings
|
|
534
|
+
};
|
|
535
|
+
} catch (error) {
|
|
536
|
+
this.errors.push({
|
|
537
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
538
|
+
});
|
|
539
|
+
return {
|
|
540
|
+
success: false,
|
|
541
|
+
filePath,
|
|
542
|
+
originalCode,
|
|
543
|
+
errors: this.errors,
|
|
544
|
+
warnings: this.warnings
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Collect string literal and comment ranges from the AST
|
|
550
|
+
* so text-based transforms can avoid modifying them.
|
|
551
|
+
*/
|
|
552
|
+
collectProtectedRanges(sourceFile) {
|
|
553
|
+
this.stringLiteralRanges = [];
|
|
554
|
+
this.commentRanges = [];
|
|
555
|
+
sourceFile.forEachDescendant((node) => {
|
|
556
|
+
if (node.getKind() === SyntaxKind.StringLiteral || node.getKind() === SyntaxKind.TemplateExpression || node.getKind() === SyntaxKind.NoSubstitutionTemplateLiteral) {
|
|
557
|
+
this.stringLiteralRanges.push({
|
|
558
|
+
start: node.getStart(),
|
|
559
|
+
end: node.getEnd()
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
const text = sourceFile.getFullText();
|
|
564
|
+
const commentRegex = /\/\/[^\n]*|\/\*[\s\S]*?\*\//g;
|
|
565
|
+
for (const match of text.matchAll(commentRegex)) {
|
|
566
|
+
if (match.index !== void 0) {
|
|
567
|
+
this.commentRanges.push({
|
|
568
|
+
start: match.index,
|
|
569
|
+
end: match.index + match[0].length
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Check if a position is inside a protected range (string literal or comment).
|
|
576
|
+
*/
|
|
577
|
+
isProtected(position) {
|
|
578
|
+
for (const range of this.stringLiteralRanges) {
|
|
579
|
+
if (position >= range.start && position < range.end) return true;
|
|
580
|
+
}
|
|
581
|
+
for (const range of this.commentRanges) {
|
|
582
|
+
if (position >= range.start && position < range.end) return true;
|
|
583
|
+
}
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* AST-based import transformation.
|
|
588
|
+
* Replaces valibot imports with zod imports using the AST.
|
|
589
|
+
*/
|
|
590
|
+
transformImportsAST(sourceFile) {
|
|
591
|
+
const imports = sourceFile.getImportDeclarations();
|
|
592
|
+
const valibotImports = [];
|
|
593
|
+
for (const imp of imports) {
|
|
594
|
+
const moduleSpecifier = imp.getModuleSpecifierValue();
|
|
595
|
+
if (moduleSpecifier === "valibot") {
|
|
596
|
+
valibotImports.push(imp);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
for (const imp of valibotImports) {
|
|
600
|
+
imp.setModuleSpecifier("zod");
|
|
601
|
+
const namespaceImport = imp.getNamespaceImport();
|
|
602
|
+
if (namespaceImport) {
|
|
603
|
+
imp.removeNamespaceImport();
|
|
604
|
+
imp.addNamedImport("z");
|
|
605
|
+
} else {
|
|
606
|
+
const namedImports = imp.getNamedImports();
|
|
607
|
+
for (const named of namedImports) {
|
|
608
|
+
named.remove();
|
|
609
|
+
}
|
|
610
|
+
imp.addNamedImport("z");
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
transformTypeHelpers(text) {
|
|
615
|
+
text = text.replace(/\bv\.InferOutput</g, "z.infer<");
|
|
616
|
+
text = text.replace(/\bv\.InferInput</g, "z.input<");
|
|
617
|
+
return text;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Transform Valibot wrapper functions to Zod method chains.
|
|
621
|
+
* v.optional(schema) → schema.optional()
|
|
622
|
+
* v.nullable(schema) → schema.nullable()
|
|
623
|
+
* v.nullish(schema) → schema.nullish()
|
|
624
|
+
* v.readonly(schema) → schema.readonly()
|
|
625
|
+
* v.partial(schema) → schema.partial()
|
|
626
|
+
* v.required(schema) → schema.required()
|
|
627
|
+
*/
|
|
628
|
+
transformWrappers(text) {
|
|
629
|
+
const twoArgWrappers = [
|
|
630
|
+
{
|
|
631
|
+
prefix: "v.optional",
|
|
632
|
+
transform: (schema, value) => `${schema}.default(${value})`
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
prefix: "v.fallback",
|
|
636
|
+
transform: (schema, value) => `${schema}.catch(${value})`
|
|
637
|
+
}
|
|
638
|
+
];
|
|
639
|
+
const singleArgWrappers = [
|
|
640
|
+
{ prefix: "v.optional", suffix: ".optional()" },
|
|
641
|
+
{ prefix: "v.nullable", suffix: ".nullable()" },
|
|
642
|
+
{ prefix: "v.nullish", suffix: ".nullish()" },
|
|
643
|
+
{ prefix: "v.readonly", suffix: ".readonly()" },
|
|
644
|
+
{ prefix: "v.partial", suffix: ".partial()" },
|
|
645
|
+
{ prefix: "v.required", suffix: ".required()" },
|
|
646
|
+
{ prefix: "v.strict", suffix: ".strict()" }
|
|
647
|
+
];
|
|
648
|
+
for (const { prefix, transform } of twoArgWrappers) {
|
|
649
|
+
text = this.replaceWrapperCall(text, prefix, (args) => {
|
|
650
|
+
if (args.length >= 2) {
|
|
651
|
+
return transform(args[0] ?? "", args[1] ?? "");
|
|
652
|
+
}
|
|
653
|
+
return null;
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
for (const { prefix, suffix } of singleArgWrappers) {
|
|
657
|
+
text = this.replaceWrapperCall(text, prefix, (args) => {
|
|
658
|
+
if (args.length === 1) {
|
|
659
|
+
return `${args[0] ?? ""}${suffix}`;
|
|
660
|
+
}
|
|
661
|
+
return null;
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
return text;
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Replace wrapper calls using balanced parenthesis matching.
|
|
668
|
+
* Skips matches inside string literals and comments.
|
|
669
|
+
*/
|
|
670
|
+
replaceWrapperCall(text, prefix, replacer) {
|
|
671
|
+
const pattern = new RegExp(`\\b${prefix.replace(".", "\\.")}\\(`, "g");
|
|
672
|
+
let result = text;
|
|
673
|
+
let offset = 0;
|
|
674
|
+
for (const match of text.matchAll(pattern)) {
|
|
675
|
+
const matchIdx = match.index ?? 0;
|
|
676
|
+
if (this.isProtected(matchIdx)) continue;
|
|
677
|
+
const startIdx = matchIdx + offset;
|
|
678
|
+
const openParen = startIdx + prefix.length;
|
|
679
|
+
let depth = 1;
|
|
680
|
+
let i = openParen + 1;
|
|
681
|
+
const current = result;
|
|
682
|
+
while (i < current.length && depth > 0) {
|
|
683
|
+
if (current[i] === "(") depth++;
|
|
684
|
+
else if (current[i] === ")") depth--;
|
|
685
|
+
i++;
|
|
686
|
+
}
|
|
687
|
+
if (depth !== 0) continue;
|
|
688
|
+
const innerContent = current.substring(openParen + 1, i - 1);
|
|
689
|
+
const args = this.splitTopLevelArgs(innerContent);
|
|
690
|
+
const replacement = replacer(args);
|
|
691
|
+
if (replacement === null) continue;
|
|
692
|
+
const before = current.substring(0, startIdx);
|
|
693
|
+
const after = current.substring(i);
|
|
694
|
+
result = before + replacement + after;
|
|
695
|
+
offset += replacement.length - (i - startIdx);
|
|
696
|
+
}
|
|
697
|
+
return result;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Transform v.pipe(factory, ...validators) to factory.validator1().validator2()
|
|
701
|
+
* Skips matches inside string literals and comments.
|
|
702
|
+
*/
|
|
703
|
+
transformPipeExpressions(text) {
|
|
704
|
+
const pipePattern = /\bv\.pipe\(/g;
|
|
705
|
+
let result = text;
|
|
706
|
+
let offset = 0;
|
|
707
|
+
for (const match of text.matchAll(pipePattern)) {
|
|
708
|
+
const matchIdx = match.index ?? 0;
|
|
709
|
+
if (this.isProtected(matchIdx)) continue;
|
|
710
|
+
const startIdx = matchIdx + offset;
|
|
711
|
+
const openParen = startIdx + "v.pipe".length;
|
|
712
|
+
let depth = 1;
|
|
713
|
+
let i = openParen + 1;
|
|
714
|
+
const current = result;
|
|
715
|
+
while (i < current.length && depth > 0) {
|
|
716
|
+
if (current[i] === "(") depth++;
|
|
717
|
+
else if (current[i] === ")") depth--;
|
|
718
|
+
i++;
|
|
719
|
+
}
|
|
720
|
+
if (depth !== 0) continue;
|
|
721
|
+
const innerContent = current.substring(openParen + 1, i - 1);
|
|
722
|
+
const args = this.splitTopLevelArgs(innerContent);
|
|
723
|
+
if (args.length === 0) continue;
|
|
724
|
+
let zodExpr = args[0] ?? "";
|
|
725
|
+
for (let j = 1; j < args.length; j++) {
|
|
726
|
+
const validator = (args[j] ?? "").trim();
|
|
727
|
+
zodExpr = this.convertPipeValidator(zodExpr, validator);
|
|
728
|
+
}
|
|
729
|
+
const before = current.substring(0, startIdx);
|
|
730
|
+
const after = current.substring(i);
|
|
731
|
+
result = before + zodExpr + after;
|
|
732
|
+
offset += zodExpr.length - (i - startIdx);
|
|
733
|
+
}
|
|
734
|
+
return result;
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Split arguments at top-level commas (not inside nested parens/brackets/braces).
|
|
738
|
+
*/
|
|
739
|
+
splitTopLevelArgs(text) {
|
|
740
|
+
const args = [];
|
|
741
|
+
let depth = 0;
|
|
742
|
+
let current = "";
|
|
743
|
+
for (const char of text) {
|
|
744
|
+
if (char === "(" || char === "[" || char === "{") depth++;
|
|
745
|
+
else if (char === ")" || char === "]" || char === "}") depth--;
|
|
746
|
+
if (char === "," && depth === 0) {
|
|
747
|
+
args.push(current.trim());
|
|
748
|
+
current = "";
|
|
749
|
+
} else {
|
|
750
|
+
current += char;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
if (current.trim()) {
|
|
754
|
+
args.push(current.trim());
|
|
755
|
+
}
|
|
756
|
+
return args;
|
|
757
|
+
}
|
|
758
|
+
convertPipeValidator(base, validator) {
|
|
759
|
+
for (const [valibotFn, zodMethod] of Object.entries(PIPE_TO_CHAIN)) {
|
|
760
|
+
const fnCall = `${valibotFn}(`;
|
|
761
|
+
if (validator.startsWith(fnCall)) {
|
|
762
|
+
const argsStr = validator.substring(fnCall.length, validator.length - 1);
|
|
763
|
+
return argsStr ? `${base}${zodMethod}(${argsStr})` : `${base}${zodMethod}()`;
|
|
764
|
+
}
|
|
765
|
+
if (validator === `${valibotFn}()`) {
|
|
766
|
+
return `${base}${zodMethod}()`;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (validator.startsWith("v.transform(")) {
|
|
770
|
+
const args = validator.substring("v.transform(".length, validator.length - 1);
|
|
771
|
+
return `${base}.transform(${args})`;
|
|
772
|
+
}
|
|
773
|
+
if (validator.startsWith("v.check(")) {
|
|
774
|
+
const args = validator.substring("v.check(".length, validator.length - 1);
|
|
775
|
+
return `${base}.refine(${args})`;
|
|
776
|
+
}
|
|
777
|
+
if (validator.startsWith("v.brand(")) {
|
|
778
|
+
const args = validator.substring("v.brand(".length, validator.length - 1);
|
|
779
|
+
return `${base}.brand(${args})`;
|
|
780
|
+
}
|
|
781
|
+
this.warnings.push(`Unknown Valibot pipe validator: ${validator} \u2014 kept as-is`);
|
|
782
|
+
return `${base} /* TODO(schemashift): convert ${validator} */`;
|
|
783
|
+
}
|
|
784
|
+
transformFactories(text) {
|
|
785
|
+
for (const [valibotFactory, zodFactory] of Object.entries(VALIBOT_TO_ZOD_FACTORY)) {
|
|
786
|
+
const escaped = valibotFactory.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
787
|
+
const regex = new RegExp(`\\b${escaped}\\(`, "g");
|
|
788
|
+
text = text.replace(regex, `${zodFactory}(`);
|
|
789
|
+
}
|
|
790
|
+
return text;
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
// src/valibot-to-zod-handler.ts
|
|
795
|
+
function createValibotToZodHandler() {
|
|
796
|
+
const transformer = new ValibotToZodTransformer();
|
|
797
|
+
return {
|
|
798
|
+
transform(sourceFile, _options) {
|
|
799
|
+
return transformer.transform(sourceFile);
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
}
|
|
446
803
|
export {
|
|
447
804
|
FACTORY_MAPPINGS,
|
|
448
805
|
MODIFIER_METHODS,
|
|
449
806
|
NUMBER_VALIDATION_MAPPINGS,
|
|
450
807
|
OBJECT_METHODS,
|
|
451
808
|
VALIDATION_MAPPINGS,
|
|
809
|
+
ValibotToZodTransformer,
|
|
452
810
|
ZodToValibotTransformer,
|
|
811
|
+
createValibotToZodHandler,
|
|
453
812
|
createZodToValibotHandler
|
|
454
813
|
};
|
|
455
814
|
//# sourceMappingURL=index.js.map
|