zenstack
Version:
FullStack enhancement for Prisma ORM: seamless integration from database to UI
238 lines • 8.98 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeFieldSchema = makeFieldSchema;
exports.getFieldSchemaDefault = getFieldSchemaDefault;
const sdk_1 = require("@zenstackhq/sdk");
const ast_1 = require("@zenstackhq/sdk/ast");
const upper_case_first_1 = require("upper-case-first");
const enhancer_utils_1 = require("../../enhancer/enhancer-utils");
function makeFieldSchema(field) {
var _a, _b;
if ((0, ast_1.isDataModel)((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref)) {
if (field.type.array) {
// array field is always optional
return `z.array(z.unknown()).optional()`;
}
else {
return field.type.optional ? `z.record(z.unknown()).optional()` : `z.record(z.unknown())`;
}
}
let schema = makeZodSchema(field);
const isDecimal = field.type.type === 'Decimal';
for (const attr of field.attributes) {
const message = getAttrLiteralArg(attr, 'message');
const messageArg = message ? `, { message: ${JSON.stringify(message)} }` : '';
const messageArgFirst = message ? `{ message: ${JSON.stringify(message)} }` : '';
switch ((_b = attr.decl.ref) === null || _b === void 0 ? void 0 : _b.name) {
case '@length': {
const min = getAttrLiteralArg(attr, 'min');
if (min) {
schema += `.min(${min}${messageArg})`;
}
const max = getAttrLiteralArg(attr, 'max');
if (max) {
schema += `.max(${max}${messageArg})`;
}
break;
}
case '@contains': {
const expr = getAttrLiteralArg(attr, 'text');
if (expr) {
schema += `.includes(${JSON.stringify(expr)}${messageArg})`;
}
break;
}
case '@regex': {
const expr = getAttrLiteralArg(attr, 'regex');
if (expr) {
schema += `.regex(new RegExp(${JSON.stringify(expr)})${messageArg})`;
}
break;
}
case '@startsWith': {
const text = getAttrLiteralArg(attr, 'text');
if (text) {
schema += `.startsWith(${JSON.stringify(text)}${messageArg})`;
}
break;
}
case '@endsWith': {
const text = getAttrLiteralArg(attr, 'text');
if (text) {
schema += `.endsWith(${JSON.stringify(text)}${messageArg})`;
}
break;
}
case '@email': {
schema += `.email(${messageArgFirst})`;
break;
}
case '@url': {
schema += `.url(${messageArgFirst})`;
break;
}
case '@trim': {
schema += `.trim()`;
break;
}
case '@lower': {
schema += `.toLowerCase()`;
break;
}
case '@upper': {
schema += `.toUpperCase()`;
break;
}
case '@db.Uuid': {
schema += `.uuid()`;
break;
}
case '@datetime': {
schema += `.datetime({ offset: true${message ? ', message: ' + JSON.stringify(message) : ''} })`;
break;
}
case '@gt': {
const value = getAttrLiteralArg(attr, 'value');
if (value !== undefined) {
schema += isDecimal ? refineDecimal('gt', value, messageArg) : `.gt(${value}${messageArg})`;
}
break;
}
case '@gte': {
const value = getAttrLiteralArg(attr, 'value');
if (value !== undefined) {
schema += isDecimal ? refineDecimal('gte', value, messageArg) : `.gte(${value}${messageArg})`;
}
break;
}
case '@lt': {
const value = getAttrLiteralArg(attr, 'value');
if (value !== undefined) {
schema += isDecimal ? refineDecimal('lt', value, messageArg) : `.lt(${value}${messageArg})`;
}
break;
}
case '@lte': {
const value = getAttrLiteralArg(attr, 'value');
if (value !== undefined) {
schema += isDecimal ? refineDecimal('lte', value, messageArg) : `.lte(${value}${messageArg})`;
}
break;
}
}
}
if (field.attributes.some(enhancer_utils_1.isDefaultWithAuth)) {
if (field.type.optional) {
schema += '.nullish()';
}
else {
// field uses `auth()` in `@default()`, this was transformed into a pseudo default
// value, while compiling to zod we should turn it into an optional field instead
// of `.default()`
schema += '.optional()';
}
}
else {
const schemaDefault = getFieldSchemaDefault(field);
if (schemaDefault !== undefined) {
if (field.type.type === 'BigInt') {
// we can't use the `n` BigInt literal notation, since it needs
// ES2020 or later, which TypeScript doesn't use by default
schema += `.default(BigInt("${schemaDefault}"))`;
}
else {
schema += `.default(${schemaDefault})`;
}
}
if (field.type.optional) {
schema += '.nullish()';
}
}
return schema;
}
function makeZodSchema(field) {
var _a, _b, _c;
let schema;
if ((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref) {
if ((0, ast_1.isEnum)((_b = field.type.reference) === null || _b === void 0 ? void 0 : _b.ref)) {
schema = `${(0, upper_case_first_1.upperCaseFirst)(field.type.reference.ref.name)}Schema`;
}
else if ((0, ast_1.isTypeDef)((_c = field.type.reference) === null || _c === void 0 ? void 0 : _c.ref)) {
schema = `z.lazy(() => ${(0, upper_case_first_1.upperCaseFirst)(field.type.reference.ref.name)}Schema)`;
}
else {
schema = 'z.any()';
}
}
else {
switch (field.type.type) {
case 'Int':
case 'Float':
schema = 'z.number()';
break;
case 'Decimal':
schema = 'DecimalSchema';
break;
case 'BigInt':
schema = 'z.bigint()';
break;
case 'String':
schema = 'z.string()';
break;
case 'Boolean':
schema = 'z.boolean()';
break;
case 'DateTime':
schema = 'z.coerce.date()';
break;
case 'Bytes':
schema = 'z.union([z.string(), z.custom<Buffer | Uint8Array>(data => data instanceof Uint8Array)])';
break;
default:
schema = 'z.any()';
break;
}
}
if (field.type.array) {
schema = `z.array(${schema})`;
}
return schema;
}
function getAttrLiteralArg(attr, paramName) {
const arg = attr.args.find((arg) => { var _a; return ((_a = arg.$resolvedParam) === null || _a === void 0 ? void 0 : _a.name) === paramName; });
return arg && (0, sdk_1.getLiteral)(arg.value);
}
function refineDecimal(op, value, messageArg) {
return `.refine(v => {
try {
return new Decimal(v.toString()).${op}(${value});
} catch {
return false;
}
}${messageArg})`;
}
function getFieldSchemaDefault(field) {
const attr = field.attributes.find((attr) => { var _a; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@default'; });
if (!attr) {
return undefined;
}
const arg = attr.args.find((arg) => { var _a; return ((_a = arg.$resolvedParam) === null || _a === void 0 ? void 0 : _a.name) === 'value'; });
if (arg) {
if ((0, ast_1.isStringLiteral)(arg.value)) {
return JSON.stringify(arg.value.value);
}
else if ((0, ast_1.isNumberLiteral)(arg.value)) {
return arg.value.value;
}
else if ((0, ast_1.isBooleanLiteral)(arg.value)) {
return arg.value.value;
}
else if ((0, ast_1.isInvocationExpr)(arg.value) &&
(0, sdk_1.isFromStdlib)(arg.value.function.ref) &&
arg.value.function.$refText === 'now') {
return `() => new Date()`;
}
}
return undefined;
}
//# sourceMappingURL=schema-gen.js.map
;