zod-compiler
Version:
Compile Zod schemas to fast parsers or TypeScript types
1,090 lines (1,071 loc) • 125 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
var ts = require('typescript');
var standalone = require('./standalone.js');
var _apply_decs_2203_r = require('@swc/helpers/_/_apply_decs_2203_r');
var z = require('zod');
var _identity = require('@swc/helpers/_/_identity');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var ts__default = /*#__PURE__*/_interopDefault(ts);
var standalone__default = /*#__PURE__*/_interopDefault(standalone);
var z__default = /*#__PURE__*/_interopDefault(z);
function uniqueIdentifier(name) {
return ts.factory.createUniqueName(name, ts__default.default.GeneratedIdentifierFlags.ReservedInNestedScopes);
}
function local(ident, initializer, modifiable = false) {
return ts.factory.createVariableStatement([], ts.factory.createVariableDeclarationList([
ts.factory.createVariableDeclaration(ident, undefined, undefined, initializer)
], !modifiable ? ts.NodeFlags.Const : ts.NodeFlags.Let));
}
function objectLiteral(obj) {
const entries = Object.entries(obj).filter(([k, v])=>!!v);
return ts.factory.createObjectLiteralExpression(entries.map(([name, expr])=>ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(name), expr)), entries.length > 1);
}
const IDENT_REGEX = /^[$A-Z_a-z][\w$]*$/;
function identifierOrStringLiteral(value) {
if (IDENT_REGEX.test(value)) {
return ts.factory.createIdentifier(value);
} else {
return ts.factory.createStringLiteral(value);
}
}
function propertyChain(start, elements) {
for (let element of elements){
if (typeof element === 'string') {
if (IDENT_REGEX.test(element)) {
start = ts.factory.createPropertyAccessExpression(start, element);
continue;
}
element = ts.factory.createStringLiteral(element);
}
start = ts.factory.createElementAccessExpression(start, element);
}
return start;
}
function print(node, hint = ts.EmitHint.Unspecified) {
const file = ts__default.default.createSourceFile('print.ts', '', ts.ScriptTarget.ES2022, false, ts.ScriptKind.TS);
const printer = ts__default.default.createPrinter();
return printer.printNode(hint, node, file);
}
function callHelper(verifierContext, helper, ...args) {
return ts.factory.createCallExpression(propertyChain(verifierContext, [
'helpers',
helper
]), undefined, args);
}
class Path {
constructor(parts){
this.parts = parts;
}
static empty() {
return new Path([]);
}
get isEmpty() {
return this.parts.length === 0;
}
clone() {
return new Path([
...this.parts
]);
}
push(fragment) {
const parts = [
...this.parts
];
if (typeof fragment === 'string') {
parts.push(ts.factory.createStringLiteral(fragment));
} else if (typeof fragment === 'number') {
parts.push(ts.factory.createNumericLiteral(fragment, ts.TokenFlags.None));
} else {
parts.push(fragment);
}
return new Path(parts);
}
serialize() {
return ts.factory.createArrayLiteralExpression(this.parts, false);
}
}
/**
* In JavaScript, there exist two main types of values - primitives like strings, numbers, and booleans; and objects like
* arrays, `Map`s, `Set`s, and, well, *objects*. Two primitives with equal value are equal to each other: `42 === 42` and
* `"foo" === "foo"`, however ***two objects will never be equal to each other***: `{} !== {}`, `[] !== []`.
*
* Since `zod-compiler` outputs source code which is then {@linkcode eval}uated, it has to get values defined in types
* like `z.literal()` or `.default()` or `.catch()` from *somewhere*; for primitive types this is fine, and the value can
* be directly pasted into the source code. However, for objects, this can lead to unexpected behavior if you, for example,
* expect values returned by `.default()` to be equal to the original value provided in the schema definition.
*
* The default inlining mode is {@linkcode Default}, which inlines *primitives*, but not *objects*. This means that
* any object values are defined as a **dependency**; they are the *exact same values* taken from the schema definition
* that the compiled parser can use via a reference. This behavior provides the best compatibility for in-source usage of
* `zod-compiler`.
*
* For **standalone** builds, however, that would mean that you'd have to provide these dependency references to the parser.
* `zc.compile()` returns a dependency array which you could then pass to `standalone()`, though you'd have to figure
* out where those values come from and extract them out of your source tree. Alternatively, the {@linkcode InliningMode.Aggressive Aggressive}
* inlining mode *will* attempt to inline objects, arrays, `Map`s, and `Set`s. This does mean that these values would
* no longer be equivalent to their definition, but there's a good chance you don't depend on that behavior anyway.
*/ var InliningMode = /*#__PURE__*/ function(InliningMode) {
/** Does not inline any values; they will all be added as dependencies. */ InliningMode[InliningMode["None"] = 0] = "None";
/** Inlines most primitives: strings, numbers, `BigInt`s, booleans, and `null`/`undefined`. */ InliningMode[InliningMode["Default"] = 1] = "Default";
/**
* Like {@linkcode InliningMode.Default Default}, but also inlines objects, arrays, `Map`s and `Set`s, and regular
* expressions.
*
* Symbols and functions cannot be inlined.
*/ InliningMode[InliningMode["Aggressive"] = 2] = "Aggressive";
return InliningMode;
}({});
class Dependencies {
constructor(verifierContext, inliningMode){
this.verifierContext = verifierContext;
this.inliningMode = inliningMode;
this._dependencies = [];
}
add(value) {
const i = this._dependencies.push(value) - 1;
return propertyChain(this.verifierContext, [
'dependencies',
i
]);
}
addOrInline(value) {
if (this.inliningMode === 0) {
return this.add(value);
}
const expr = toLiteral(value, this.inliningMode);
if (expr === null) {
return this.add(value);
}
return expr;
}
get dependencies() {
return this._dependencies;
}
}
class AbstractGeneratorContextWithExprs {
constructor(input, output, verifierContext, dependencies){
this._input = input;
this._output = output;
this._verifierContext = verifierContext;
this._dependencies = dependencies;
}
get input() {
return this._input;
}
get output() {
return this._output;
}
get dependencies() {
return this._dependencies;
}
get verifierContext() {
return this._verifierContext;
}
*prelude() {}
*postlude() {}
*outputs(expr) {
yield ts.factory.createExpressionStatement(ts.factory.createAssignment(this._output, expr));
}
*report(issue, input = this.input) {
yield ts.factory.createExpressionStatement(ts.factory.createCallExpression(propertyChain(this.verifierContext, [
'reportIssue'
]), undefined, [
issue,
input
]));
}
}
class AbstractGeneratorContextWithExprsAndStatusVar extends AbstractGeneratorContextWithExprs {
*prelude() {
yield ts.factory.createVariableStatement([], ts.factory.createVariableDeclarationList([
ts.factory.createVariableDeclaration(this.statusVar, undefined, undefined, ts.factory.createNumericLiteral(standalone.ParseStatus.VALID))
], ts.NodeFlags.Let));
}
constructor(...args){
super(...args), this.statusVar = uniqueIdentifier('status');
}
}
class FunctionalGeneratorContext extends AbstractGeneratorContextWithExprsAndStatusVar {
*postlude() {
yield ts.factory.createReturnStatement(this.statusVar);
}
*status(status, allowShortCircuiting = true) {
if (typeof status === 'number') {
if (status === standalone.ParseStatus.INVALID && allowShortCircuiting) {
yield ts.factory.createReturnStatement(ts.factory.createNumericLiteral(status));
} else {
yield ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(this.statusVar, ts.SyntaxKind.BarEqualsToken, ts.factory.createNumericLiteral(status)));
}
} else {
if (allowShortCircuiting) {
yield ts.factory.createIfStatement(ts.factory.createBitwiseAnd(status, ts.factory.createNumericLiteral(standalone.ParseStatus.INVALID)), ts.factory.createReturnStatement(status));
}
yield ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(this.statusVar, ts.SyntaxKind.BarEqualsToken, status));
}
}
withInput(expr) {
const x = new FunctionalGeneratorContext(expr, this.output, this.verifierContext, this.dependencies);
x.statusVar = this.statusVar;
return x;
}
}
var LabeledShortCircuitMode = /*#__PURE__*/ function(LabeledShortCircuitMode) {
LabeledShortCircuitMode[LabeledShortCircuitMode["Continue"] = 0] = "Continue";
LabeledShortCircuitMode[LabeledShortCircuitMode["Break"] = 1] = "Break";
return LabeledShortCircuitMode;
}({});
class LabeledBlockScopeGeneratorContext extends AbstractGeneratorContextWithExprsAndStatusVar {
constructor(mode, label, input, output, verifierContext, dependencies){
super(input, output, verifierContext, dependencies), this.mode = mode, this.label = label;
}
*status(status, allowShortCircuiting = true) {
yield ts.factory.createExpressionStatement(ts.factory.createBinaryExpression(this.statusVar, ts.SyntaxKind.BarEqualsToken, typeof status === 'number' ? ts.factory.createNumericLiteral(status) : status));
if (allowShortCircuiting) {
const shortCircuit = ()=>{
switch(this.mode){
case 1:
return ts.factory.createBreakStatement(this.label);
case 0:
return ts.factory.createContinueStatement(this.label);
}
};
if (status === standalone.ParseStatus.INVALID) {
yield shortCircuit();
} else {
yield ts.factory.createIfStatement(ts.factory.createBitwiseAnd(this.statusVar, ts.factory.createNumericLiteral(standalone.ParseStatus.INVALID)), shortCircuit());
}
}
}
withInput(expr) {
const x = new LabeledBlockScopeGeneratorContext(this.mode, this.label, expr, this.output, this.verifierContext, this.dependencies);
x.statusVar = this.statusVar;
return x;
}
}
function toLiteral(value, mode) {
switch(typeof value){
case 'string':
return ts.factory.createStringLiteral(value);
case 'number':
return ts.factory.createNumericLiteral(value);
case 'bigint':
return ts.factory.createBigIntLiteral(value.toString());
case 'undefined':
return ts.factory.createIdentifier('undefined');
case 'boolean':
return value ? ts.factory.createTrue() : ts.factory.createFalse();
case 'object':
if (value === null) {
return ts.factory.createNull();
}
if (mode === 2) {
if (value instanceof RegExp) {
return ts.factory.createRegularExpressionLiteral(value.toString());
} else if (value instanceof Map) {
return ts.factory.createNewExpression(ts.factory.createIdentifier('Map'), undefined, [
ts.factory.createArrayLiteralExpression([
...value.entries()
].map(([k, v])=>ts.factory.createArrayLiteralExpression([
toLiteral(k, mode),
toLiteral(v, mode)
])))
]);
} else if (value instanceof Set) {
return ts.factory.createNewExpression(ts.factory.createIdentifier('Set'), undefined, [
ts.factory.createArrayLiteralExpression([
...value.values()
].map((v)=>toLiteral(v, mode)))
]);
} else if (Array.isArray(value)) {
return ts.factory.createArrayLiteralExpression(value.map((v)=>toLiteral(v, mode)));
} else if (value instanceof Date) {
return ts.factory.createNewExpression(ts.factory.createIdentifier('Date'), undefined, [
ts.factory.createNumericLiteral(value.getTime())
]);
} else if (value.constructor === Object) {
return ts.factory.createObjectLiteralExpression(Object.entries(value).map(([k, v])=>ts.factory.createPropertyAssignment(identifierOrStringLiteral(k), toLiteral(v, mode))));
} else {
throw new Error(`Value cannot be inlined: ${value}`);
}
}
break;
case 'function':
case 'symbol':
if (mode === 2) {
throw new Error(`${typeof value === 'function' ? 'Functions' : 'Symbols'} cannot be inlined`);
}
break;
}
return null;
}
class AbstractCompiledType {
constructor(type){
this.type = type;
}
}
const registry = new Map();
function register(zodType) {
return function(constructor, _context) {
registry.set(zodType, constructor);
};
}
function compilable(type) {
const typeName = type._def.typeName;
if (typeName === undefined) {
throw new TypeError('Third-party Zod types are not supported');
}
const base = registry.get(typeName);
if (!base) {
throw new TypeError(`Unimplemented Zod type \`z.${typeName}\``);
}
return new base(type);
}
// Mirrors ZodParsedType from src/helpers/util.ts
// Mirrors getParsedType from src/helpers/util.ts
function typeOf(data) {
switch(typeof data){
case 'undefined':
return "undefined";
case 'string':
return "string";
case 'number':
return isNaN(data) ? "nan" : "number";
case 'boolean':
return "boolean";
case 'function':
return "function";
case 'bigint':
return "bigint";
case 'symbol':
return "symbol";
case 'object':
if (Array.isArray(data)) {
return "array";
}
if (data === null) {
return "null";
}
if (typeof data.then === 'function' && typeof data.catch === 'function') {
return "promise";
}
if (data instanceof Map) {
return "map";
}
if (data instanceof Set) {
return "set";
}
if (data instanceof Date) {
return "date";
}
return "object";
default:
return "unknown";
}
}
function stringify(obj) {
return JSON.stringify(obj, (_, value)=>{
if (typeof value === 'bigint') {
return value.toString();
}
return value;
}, 2 /* ugggghhhhhhhh */ );
}
function joinValues(array, separator = ' | ') {
return array.map((val)=>typeof val === 'string' ? `'${val}'` : val).join(separator);
}
class ZcError extends Error {
get errors() {
return this.issues;
}
constructor(issues){
super(), this.issues = issues;
// TODO: why is this required?
const actualProto = new.target.prototype;
Object.setPrototypeOf(this, actualProto);
this.name = 'ZcError';
}
format(_mapper) {
const mapper = _mapper ?? ((issue)=>issue.message);
const fieldErrors = {
_errors: []
};
const processError = (error)=>{
for (const issue of error.issues){
if (issue.code === "invalid_union") {
issue.unionErrors.map(processError);
} else if (issue.code === "invalid_return_type") {
processError(issue.returnTypeError);
} else if (issue.code === "invalid_arguments") {
processError(issue.argumentsError);
} else if (issue.path.length === 0) {
fieldErrors._errors.push(mapper(issue));
} else {
let curr = fieldErrors;
let i = 0;
while(i < issue.path.length){
const el = issue.path[i];
curr[el] ||= {
_errors: []
};
const terminal = i === issue.path.length - 1;
if (terminal) {
curr[el]._errors.push(mapper(issue));
}
curr = curr[el];
i++;
}
}
}
};
processError(this);
return fieldErrors;
}
static create(issues) {
return new ZcError(issues);
}
toString() {
return this.message;
}
get message() {
return stringify(this.issues);
}
get isEmpty() {
return this.issues.length === 0;
}
addIssue(sub) {
// why not push...?
this.issues = [
...this.issues,
sub
];
}
addIssues(subs = []) {
this.issues = [
...this.issues,
...subs
];
}
flatten(mapper = (issue)=>issue.message) {
const fieldErrors = {};
const formErrors = [];
for (const sub of this.issues){
if (sub.path.length > 0) {
fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || [];
fieldErrors[sub.path[0]].push(mapper(sub));
} else {
formErrors.push(mapper(sub));
}
}
return {
formErrors,
fieldErrors
};
}
get formErrors() {
return this.flatten(); //.formErrors?;
}
}
var _dec$u, _initClass$u, _AbstractCompiledType$u;
exports.ZcAny = void 0;
_dec$u = register(z__default.default.ZodFirstPartyTypeKind.ZodAny);
class ZcAny extends (_AbstractCompiledType$u = AbstractCompiledType) {
static{
({ c: [exports.ZcAny, _initClass$u] } = _apply_decs_2203_r._(this, [], [
_dec$u
], _AbstractCompiledType$u));
}
compileType() {
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
}
*compileParser(ctx, path) {
yield* ctx.outputs(ctx.input);
}
static{
_initClass$u();
}
}
var _dec$t, _initClass$t, _AbstractCompiledType$t;
class ArrayGeneratorContext extends LabeledBlockScopeGeneratorContext {
constructor(input, output, verifierContext, dependencies, parentStatusSetter){
super(LabeledShortCircuitMode.Continue, undefined, input, output, verifierContext, dependencies), this.parentStatusSetter = parentStatusSetter;
}
*prelude() {}
*status(status, allowShortCircuiting = true) {
yield* this.parentStatusSetter(typeof status === 'number' ? ts.factory.createNumericLiteral(status) : status);
if (allowShortCircuiting) {
if (status === standalone.ParseStatus.INVALID) {
yield ts.factory.createContinueStatement();
} else if (typeof status !== 'number') {
yield ts.factory.createIfStatement(ts.factory.createBitwiseAnd(status, ts.factory.createNumericLiteral(standalone.ParseStatus.INVALID)), ts.factory.createContinueStatement());
}
}
}
withInput(expr) {
const x = new ArrayGeneratorContext(expr, this.output, this.verifierContext, this.dependencies, this.parentStatusSetter);
x.statusVar = this.statusVar;
return x;
}
}
exports.ZcArray = void 0;
_dec$t = register(z__default.default.ZodFirstPartyTypeKind.ZodArray);
class ZcArray extends (_AbstractCompiledType$t = AbstractCompiledType) {
static{
({ c: [exports.ZcArray, _initClass$t] } = _apply_decs_2203_r._(this, [], [
_dec$t
], _AbstractCompiledType$t));
}
compileType() {
return ts.factory.createArrayTypeNode(compilable(this.type._def.type).compileType());
}
*compileParser(ctx, path) {
yield ts.factory.createIfStatement(ts.factory.createLogicalNot(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Array'), 'isArray'), undefined, [
ctx.input
])), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_type'),
expected: ts.factory.createStringLiteral('array'),
received: callHelper(ctx.verifierContext, 'typeOf', ctx.input)
})),
...ctx.status(standalone.ParseStatus.INVALID)
], true));
if (this.type._def.exactLength !== null) {
const value = ts.factory.createNumericLiteral(this.type._def.exactLength.value);
const lengthAccessor = ts.factory.createPropertyAccessExpression(ctx.input, 'length');
const tooBigIdent = uniqueIdentifier('tooBig');
const tooSmallIdent = uniqueIdentifier('tooSmall');
yield ts.factory.createIfStatement(ts.factory.createStrictInequality(lengthAccessor, value), ts.factory.createBlock([
local(tooBigIdent, ts.factory.createGreaterThan(lengthAccessor, value)),
local(tooSmallIdent, ts.factory.createLessThan(lengthAccessor, value)),
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createConditionalExpression(tooBigIdent, undefined, ts.factory.createStringLiteral('too_big'), undefined, ts.factory.createStringLiteral('too_small')),
minimum: ts.factory.createConditionalExpression(tooSmallIdent, undefined, value, undefined, ts.factory.createIdentifier('undefined')),
maximum: ts.factory.createConditionalExpression(tooBigIdent, undefined, value, undefined, ts.factory.createIdentifier('undefined')),
type: ts.factory.createStringLiteral('array'),
inclusive: ts.factory.createTrue(),
exact: ts.factory.createTrue(),
message: this.type._def.exactLength.message ? ts.factory.createStringLiteral(this.type._def.exactLength.message) : undefined
})),
...ctx.status(standalone.ParseStatus.DIRTY)
], true));
}
if (this.type._def.minLength !== null) {
yield ts.factory.createIfStatement(ts.factory.createLessThan(ts.factory.createPropertyAccessExpression(ctx.input, 'length'), ts.factory.createNumericLiteral(this.type._def.minLength.value)), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('too_small'),
minimum: ts.factory.createNumericLiteral(this.type._def.minLength.value),
type: ts.factory.createStringLiteral('array'),
inclusive: ts.factory.createTrue(),
exact: ts.factory.createFalse(),
message: this.type._def.minLength.message ? ts.factory.createStringLiteral(this.type._def.minLength.message) : undefined
})),
...ctx.status(standalone.ParseStatus.DIRTY)
], true));
}
if (this.type._def.maxLength !== null) {
yield ts.factory.createIfStatement(ts.factory.createGreaterThan(ts.factory.createPropertyAccessExpression(ctx.input, 'length'), ts.factory.createNumericLiteral(this.type._def.maxLength.value)), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('too_big'),
minimum: ts.factory.createNumericLiteral(this.type._def.maxLength.value),
type: ts.factory.createStringLiteral('array'),
inclusive: ts.factory.createTrue(),
exact: ts.factory.createFalse(),
message: this.type._def.maxLength.message ? ts.factory.createStringLiteral(this.type._def.maxLength.message) : undefined
})),
...ctx.status(standalone.ParseStatus.DIRTY)
], true));
}
const output = uniqueIdentifier('outputArray');
yield local(output, ts.factory.createNewExpression(ts.factory.createIdentifier('Array'), undefined, [
ts.factory.createPropertyAccessExpression(ctx.input, 'length')
]));
const indexInitializer = ts.factory.createLoopVariable(true);
const elInitializer = uniqueIdentifier('el');
const elOutput = ts.factory.createElementAccessExpression(output, indexInitializer);
const childCtx = new ArrayGeneratorContext(elInitializer, elOutput, ctx.verifierContext, ctx.dependencies, (status)=>ctx.status(status, false));
yield ts.factory.createForOfStatement(undefined, ts.factory.createVariableDeclarationList([
ts.factory.createVariableDeclaration(ts.factory.createArrayBindingPattern([
ts.factory.createBindingElement(undefined, undefined, indexInitializer),
ts.factory.createBindingElement(undefined, undefined, elInitializer)
]))
], ts.NodeFlags.Const), ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ctx.input, 'entries'), undefined, undefined), ts.factory.createBlock([
...childCtx.prelude(),
...compilable(this.type._def.type).compileParser(childCtx, path.push(indexInitializer)),
...childCtx.postlude()
]));
yield* ctx.outputs(output);
}
static{
_initClass$t();
}
}
var _dec$s, _initClass$s, _AbstractCompiledType$s;
exports.ZcBigInt = void 0;
_dec$s = register(z__default.default.ZodFirstPartyTypeKind.ZodBigInt);
class ZcBigInt extends (_AbstractCompiledType$s = AbstractCompiledType) {
static{
({ c: [exports.ZcBigInt, _initClass$s] } = _apply_decs_2203_r._(this, [], [
_dec$s
], _AbstractCompiledType$s));
}
compileType() {
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BigIntKeyword);
}
*compileParser(ctx, path) {
let input = ctx.input;
if (this.type._def.coerce) {
const ident = uniqueIdentifier('coercedInput');
yield local(ident, undefined, true);
input = ident;
yield ts.factory.createTryStatement(ts.factory.createBlock([
ts.factory.createExpressionStatement(ts.factory.createAssignment(ident, ts.factory.createCallExpression(ts.factory.createIdentifier('BigInt'), undefined, [
ctx.input
])))
], true), ts.factory.createCatchClause(uniqueIdentifier('e'), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_type'),
expected: ts.factory.createStringLiteral('bigint'),
received: callHelper(ctx.verifierContext, 'typeOf', input)
}), input),
// hopefully this causes a short circuit and the rest of the body doesn't get executed...
...ctx.status(standalone.ParseStatus.INVALID)
], true)), undefined);
}
let stmt = ts.factory.createIfStatement(ts.factory.createStrictInequality(ts.factory.createTypeOfExpression(input), ts.factory.createStringLiteral('bigint')), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_type'),
expected: ts.factory.createStringLiteral('bigint'),
received: callHelper(ctx.verifierContext, 'typeOf', input)
}), input),
...ctx.status(standalone.ParseStatus.INVALID)
], true));
const checkStmts = [];
for (const check of this.type._def.checks){
switch(check.kind){
case 'min':
checkStmts.push(ts.factory.createIfStatement(ts.factory[check.inclusive ? 'createLessThan' : 'createLessThanEquals'](input, ts.factory.createBigIntLiteral(check.value.toString())), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('too_small'),
minimum: ts.factory.createBigIntLiteral(check.value.toString()),
type: ts.factory.createStringLiteral('bigint'),
inclusive: check.inclusive ? ts.factory.createTrue() : ts.factory.createFalse(),
exact: ts.factory.createFalse(),
message: check.message ? ts.factory.createStringLiteral(check.message) : undefined
}), input),
...ctx.status(standalone.ParseStatus.DIRTY)
], true)));
break;
case 'max':
checkStmts.push(ts.factory.createIfStatement(ts.factory[check.inclusive ? 'createGreaterThan' : 'createGreaterThanEquals'](input, ts.factory.createBigIntLiteral(check.value.toString())), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('too_big'),
minimum: ts.factory.createBigIntLiteral(check.value.toString()),
type: ts.factory.createStringLiteral('bigint'),
inclusive: check.inclusive ? ts.factory.createTrue() : ts.factory.createFalse(),
exact: ts.factory.createFalse(),
message: check.message ? ts.factory.createStringLiteral(check.message) : undefined
}), input),
...ctx.status(standalone.ParseStatus.DIRTY)
], true)));
break;
case 'multipleOf':
checkStmts.push(ts.factory.createIfStatement(ts.factory.createStrictInequality(ts.factory.createModulo(input, ts.factory.createBigIntLiteral(check.value.toString())), ts.factory.createBigIntLiteral('0')), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('not_multiple_of'),
multipleOf: ts.factory.createBigIntLiteral(check.value.toString()),
message: check.message ? ts.factory.createStringLiteral(check.message) : undefined
}), input),
...ctx.status(standalone.ParseStatus.DIRTY)
], true)));
break;
default:
throw new Error(`Unsupported ZcBigInt check: ${check}`);
}
}
if (checkStmts.length === 0) {
yield stmt;
} else {
stmt = ts.factory.updateIfStatement(stmt, stmt.expression, stmt.thenStatement, ts.factory.createBlock([
...checkStmts
], true));
yield stmt;
}
yield* ctx.outputs(input);
}
static{
_initClass$s();
}
}
var _dec$r, _initClass$r, _AbstractCompiledType$r;
exports.ZcBoolean = void 0;
_dec$r = register(z__default.default.ZodFirstPartyTypeKind.ZodBoolean);
class ZcBoolean extends (_AbstractCompiledType$r = AbstractCompiledType) {
static{
({ c: [exports.ZcBoolean, _initClass$r] } = _apply_decs_2203_r._(this, [], [
_dec$r
], _AbstractCompiledType$r));
}
compileType() {
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
}
*compileParser(ctx, path) {
let input = ctx.input;
if (this.type._def.coerce) {
const ident = uniqueIdentifier('coercedInput');
yield local(ident, ts.factory.createCallExpression(ts.factory.createIdentifier('Boolean'), [], [
ctx.input
]), false);
input = ident;
}
yield ts.factory.createIfStatement(ts.factory.createStrictInequality(ts.factory.createTypeOfExpression(input), ts.factory.createStringLiteral('boolean')), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_type'),
expected: ts.factory.createStringLiteral('boolean'),
received: callHelper(ctx.verifierContext, 'typeOf', ctx.input)
}), input),
...ctx.status(standalone.ParseStatus.INVALID)
], true));
yield* ctx.outputs(ctx.input);
}
static{
_initClass$r();
}
}
var _dec$q, _initClass$q, _AbstractCompiledType$q;
exports.ZcBranded = void 0;
_dec$q = register(z__default.default.ZodFirstPartyTypeKind.ZodBranded);
class ZcBranded extends (_AbstractCompiledType$q = AbstractCompiledType) {
static{
({ c: [exports.ZcBranded, _initClass$q] } = _apply_decs_2203_r._(this, [], [
_dec$q
], _AbstractCompiledType$q));
}
compileType() {
return compilable(this.type._def.type).compileType();
}
*compileParser(ctx, path) {
yield* compilable(this.type._def.type).compileParser(ctx, path);
}
static{
_initClass$q();
}
}
var _dec$p, _initClass$p, _AbstractCompiledType$p;
class CatchGeneratorContext extends LabeledBlockScopeGeneratorContext {
constructor(label, input, output, verifierContext, dependencies, statusVar){
super(LabeledShortCircuitMode.Break, label, input, output, verifierContext, dependencies);
this.statusVar = statusVar;
}
*prelude() {}
withInput(expr) {
const x = new CatchGeneratorContext(this.label, expr, this.output, this.verifierContext, this.dependencies, this.statusVar);
x.statusVar = this.statusVar;
return x;
}
}
exports.ZcCatch = void 0;
_dec$p = register(z__default.default.ZodFirstPartyTypeKind.ZodCatch);
class ZcCatch extends (_AbstractCompiledType$p = AbstractCompiledType) {
static{
({ c: [exports.ZcCatch, _initClass$p] } = _apply_decs_2203_r._(this, [], [
_dec$p
], _AbstractCompiledType$p));
}
compileType() {
return compilable(this.type._def.innerType).compileType();
}
*compileParser(ctx, path) {
const caughtStatus = uniqueIdentifier('caughtStatus');
yield local(caughtStatus, ts.factory.createNumericLiteral(standalone.ParseStatus.VALID), true);
const output = uniqueIdentifier('caughtOutput');
yield local(output, undefined, true);
const verifierCtxVar = uniqueIdentifier('variantCtx');
yield local(verifierCtxVar, ts.factory.createObjectLiteralExpression([
ts.factory.createSpreadAssignment(ctx.verifierContext),
ts.factory.createPropertyAssignment('issues', ts.factory.createArrayLiteralExpression())
], true));
const label = uniqueIdentifier('catch');
const childCtx = new CatchGeneratorContext(label, ctx.input, output, verifierCtxVar, ctx.dependencies, caughtStatus);
const catchValue = ctx.dependencies.addOrInline(this.type._def.catchValue(null));
yield ts.factory.createLabeledStatement(label, ts.factory.createBlock([
...childCtx.prelude(),
...compilable(this.type._def.innerType).compileParser(childCtx, path),
...childCtx.postlude()
]));
yield ts.factory.createIfStatement(ts.factory.createStrictInequality(caughtStatus, ts.factory.createNumericLiteral(standalone.ParseStatus.VALID)), ts.factory.createBlock([
...ctx.outputs(catchValue)
], true), ts.factory.createBlock([
...ctx.outputs(output)
], true));
}
static{
_initClass$p();
}
}
var _dec$o, _initClass$o, _AbstractCompiledType$o;
exports.ZcDate = void 0;
_dec$o = register(z__default.default.ZodFirstPartyTypeKind.ZodDate);
class ZcDate extends (_AbstractCompiledType$o = AbstractCompiledType) {
static{
({ c: [exports.ZcDate, _initClass$o] } = _apply_decs_2203_r._(this, [], [
_dec$o
], _AbstractCompiledType$o));
}
compileType() {
return ts.factory.createTypeReferenceNode('Date');
}
*compileParser(ctx, path) {
let input = ctx.input;
if (this.type._def.coerce) {
const ident = uniqueIdentifier('coercedInput');
yield local(ident, ts.factory.createNewExpression(ts.factory.createIdentifier('Date'), [], [
ctx.input
]), false);
input = ident;
}
let stmt = ts.factory.createIfStatement(ts.factory.createLogicalNot(ts.factory.createBinaryExpression(input, ts.SyntaxKind.InstanceOfKeyword, ts.factory.createIdentifier('Date'))), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_type'),
expected: ts.factory.createStringLiteral('date'),
received: callHelper(ctx.verifierContext, 'typeOf', input)
}), input),
...ctx.status(standalone.ParseStatus.INVALID)
], true));
const timeVar = uniqueIdentifier('time');
const checkStmts = [
local(timeVar, ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(input, 'getTime'), undefined, [])),
ts.factory.createIfStatement(ts.factory.createCallExpression(ts.factory.createIdentifier('isNaN'), undefined, [
timeVar
]), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_date')
}), input),
...ctx.status(standalone.ParseStatus.INVALID)
], true))
];
for (const check of this.type._def.checks){
switch(check.kind){
case 'min':
checkStmts.push(ts.factory.createIfStatement(ts.factory.createLessThan(timeVar, ts.factory.createNumericLiteral(check.value)), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('too_small'),
minimum: ts.factory.createNumericLiteral(check.value),
type: ts.factory.createStringLiteral('date'),
inclusive: ts.factory.createTrue(),
exact: ts.factory.createFalse(),
message: check.message ? ts.factory.createStringLiteral(check.message) : undefined
}), input),
...ctx.status(standalone.ParseStatus.DIRTY)
], true)));
break;
case 'max':
checkStmts.push(ts.factory.createIfStatement(ts.factory.createGreaterThan(timeVar, ts.factory.createNumericLiteral(check.value)), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('too_big'),
minimum: ts.factory.createNumericLiteral(check.value),
type: ts.factory.createStringLiteral('date'),
inclusive: ts.factory.createTrue(),
exact: ts.factory.createFalse(),
message: check.message ? ts.factory.createStringLiteral(check.message) : undefined
}), input),
...ctx.status(standalone.ParseStatus.DIRTY)
], true)));
break;
default:
throw new Error(`Unsupported ZcDate check: ${check}`);
}
}
yield ts.factory.updateIfStatement(stmt, stmt.expression, stmt.thenStatement, ts.factory.createBlock([
...checkStmts
], true));
yield* ctx.outputs(input);
}
static{
_initClass$o();
}
}
var _dec$n, _initClass$n, _AbstractCompiledType$n;
exports.ZcDefault = void 0;
_dec$n = register(z__default.default.ZodFirstPartyTypeKind.ZodDefault);
class ZcDefault extends (_AbstractCompiledType$n = AbstractCompiledType) {
static{
({ c: [exports.ZcDefault, _initClass$n] } = _apply_decs_2203_r._(this, [], [
_dec$n
], _AbstractCompiledType$n));
}
compileType() {
return compilable(this.type._def.innerType).compileType();
}
*compileParser(ctx, path) {
const newInput = uniqueIdentifier('defaultInput');
yield local(newInput, ctx.input, true);
const defaultValue = ctx.dependencies.addOrInline(this.type._def.defaultValue());
yield ts.factory.createIfStatement(ts.factory.createStrictEquality(ts.factory.createTypeOfExpression(newInput), ts.factory.createStringLiteral('undefined')), ts.factory.createBlock([
ts.factory.createExpressionStatement(ts.factory.createAssignment(newInput, defaultValue))
], true));
yield* compilable(this.type._def.innerType).compileParser(ctx.withInput(newInput), path);
}
static{
_initClass$n();
}
}
var _dec$m, _initClass$m, _AbstractCompiledType$m;
class ObjectGeneratorContext extends LabeledBlockScopeGeneratorContext {
constructor(label, input, output, verifierContext, dependencies, parentStatusSetter){
super(LabeledShortCircuitMode.Break, label, input, output, verifierContext, dependencies), this.parentStatusSetter = parentStatusSetter;
}
*prelude() {}
*status(status, allowShortCircuiting = true) {
yield* this.parentStatusSetter(typeof status === 'number' ? ts.factory.createNumericLiteral(status) : status);
if (allowShortCircuiting) {
if (status === standalone.ParseStatus.INVALID) {
yield ts.factory.createBreakStatement(this.label);
} else if (typeof status !== 'number') {
yield ts.factory.createIfStatement(ts.factory.createBitwiseAnd(status, ts.factory.createNumericLiteral(standalone.ParseStatus.INVALID)), ts.factory.createBreakStatement(this.label));
}
}
}
withInput(expr) {
const x = new ObjectGeneratorContext(this.label, expr, this.output, this.verifierContext, this.dependencies, this.parentStatusSetter);
x.statusVar = this.statusVar;
return x;
}
}
exports.ZcObject = void 0;
_dec$m = register(z__default.default.ZodFirstPartyTypeKind.ZodObject);
class ZcObject extends (_AbstractCompiledType$m = AbstractCompiledType) {
static{
({ c: [exports.ZcObject, _initClass$m] } = _apply_decs_2203_r._(this, [], [
_dec$m
], _AbstractCompiledType$m));
}
compileType() {
return ts.factory.createTypeLiteralNode(Object.entries(this.type._def.shape()).map(([key, value])=>{
const type = compilable(value);
const isOptional = value._def.typeName === z__default.default.ZodFirstPartyTypeKind.ZodOptional || value.isOptional();
const node = ts.factory.createPropertySignature(undefined, identifierOrStringLiteral(key), isOptional && value._def.typeName !== z__default.default.ZodFirstPartyTypeKind.ZodDefault ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, type.compileType());
if (value.description) {
ts__default.default.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, `* ${value.description} `, true);
}
return node;
}));
}
*compileParser(ctx, path) {
if (!this.canSkipTypeCheck) {
const typeIdentifier = uniqueIdentifier('type');
yield local(typeIdentifier, callHelper(ctx.verifierContext, 'typeOf', ctx.input));
yield ts.factory.createIfStatement(ts.factory.createStrictInequality(typeIdentifier, ts.factory.createStringLiteral('object')), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_type'),
expected: ts.factory.createStringLiteral('object'),
received: typeIdentifier
})),
...ctx.status(standalone.ParseStatus.INVALID)
], true));
}
const shape = this.type._def.shape();
// TODO: catchall/passthrough/strict
// const shapeKeysIdent = uniqueIdentifier('shapeKeys');
// yield local(
// shapeKeysIdent,
// factory.createNewExpression(
// factory.createIdentifier('Set'),
// [],
// [ factory.createArrayLiteralExpression(Object.keys(shape).map(key => factory.createStringLiteral(key))) ]
// )
// );
const output = uniqueIdentifier('outputObject');
yield local(output, ts.factory.createObjectLiteralExpression());
for (const [i, [key, value]] of Object.entries(shape).entries()){
const label = uniqueIdentifier(`prop${i}`);
const inputExpr = propertyChain(ctx.input, [
key
]);
const outputExpr = propertyChain(output, [
key
]);
const childCtx = new ObjectGeneratorContext(label, inputExpr, outputExpr, ctx.verifierContext, ctx.dependencies, (status)=>ctx.status(status, false));
yield ts.factory.createLabeledStatement(label, ts.factory.createBlock([
...compilable(value).compileParser(childCtx, path.push(key))
]));
}
yield* ctx.outputs(output);
}
static{
_initClass$m();
}
constructor(...args){
super(...args), // In the case of discriminated unions, we already check that the type is an object before passing off parsing
// to a ZcObject.
this.canSkipTypeCheck = false;
}
}
var _dec$l, _initClass$l, _AbstractCompiledType$l;
exports.ZcDiscriminatedUnion = void 0;
_dec$l = register(z__default.default.ZodFirstPartyTypeKind.ZodDiscriminatedUnion);
class ZcDiscriminatedUnion extends (_AbstractCompiledType$l = AbstractCompiledType) {
static{
({ c: [exports.ZcDiscriminatedUnion, _initClass$l] } = _apply_decs_2203_r._(this, [], [
_dec$l
], _AbstractCompiledType$l));
}
compileType() {
return ts.factory.createUnionTypeNode(this.type._def.options.map((ty)=>compilable(ty).compileType()));
}
*compileParser(ctx, path) {
const typeIdentifier = uniqueIdentifier('type');
yield local(typeIdentifier, callHelper(ctx.verifierContext, 'typeOf', ctx.input));
yield ts.factory.createIfStatement(ts.factory.createStrictInequality(typeIdentifier, ts.factory.createStringLiteral('object')), ts.factory.createBlock([
...ctx.report(objectLiteral({
path: path.serialize(),
code: ts.factory.createStringLiteral('invalid_type'),
expected: ts.factory.createStringLiteral('object'),
received: typeIdentifier
})),
...ctx.status(standalone.ParseStatus.INVALID)
], true));
yield ts.factory.createSwitchStatement(propertyChain(ctx.input, [
this.type._def.discriminator
]), ts.factory.createCaseBlock([
...[
...this.type._def.optionsMap.entries()
].map(([discriminator, zodTy])=>{
const ty = compilable(zodTy);
if (ty instanceof exports.ZcObject) {
// We've already checked that the input is an object.
ty.canSkipTypeCheck = true;
}
return ts.factory.createCaseClause(ctx.dependencies.addOrInline(discriminator), [
...ty.compileParser(ctx, path),
ts.factory.createBreakStatement()
]);
}),
ts.factory.createDefaultClause([
...ctx.report(objectLiteral({
path: path.push(this.type._def.discriminator).serialize(),
code: ts.factory.createStringLiteral('invalid_union_discriminator'),
options: ctx.dependencies.add(Array.from(this.type._def.optionsMap.keys()))
})),
...ctx.status(standalone.ParseStatus.INVALID)
])
]));
}
static{
_initClass$l();
}
}
var _dec$k, _init