zenstack
Version:
FullStack enhancement for Prisma ORM: seamless integration from database to UI
640 lines • 32.9 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ZodSchemaGenerator = void 0;
exports.computePrismaClientImport = computePrismaClientImport;
const runtime_1 = require("@zenstackhq/runtime");
const sdk_1 = require("@zenstackhq/sdk");
const ast_1 = require("@zenstackhq/sdk/ast");
const dmmf_helpers_1 = require("@zenstackhq/sdk/dmmf-helpers");
const prisma_1 = require("@zenstackhq/sdk/prisma");
const langium_1 = require("langium");
const path_1 = __importDefault(require("path"));
const upper_case_first_1 = require("upper-case-first");
const _1 = require(".");
const plugin_utils_1 = require("../plugin-utils");
const transformer_1 = __importDefault(require("./transformer"));
const schema_gen_1 = require("./utils/schema-gen");
class ZodSchemaGenerator {
constructor(model, options, dmmf, globalOptions) {
var _a;
this.model = model;
this.options = options;
this.dmmf = dmmf;
this.sourceFiles = [];
if (!globalOptions) {
throw new Error('Global options are required');
}
this.globalOptions = globalOptions;
// options validation
if (this.options.mode &&
(typeof this.options.mode !== 'string' || !['strip', 'strict', 'passthrough'].includes(this.options.mode))) {
throw new sdk_1.PluginError(_1.name, `Invalid mode option: "${this.options.mode}". Must be one of 'strip', 'strict', or 'passthrough'.`);
}
this.mode = ((_a = this.options.mode) !== null && _a !== void 0 ? _a : 'strict');
}
generate() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
let output = this.options.output;
if (!output) {
const defaultOutputFolder = (0, plugin_utils_1.getDefaultOutputFolder)(this.globalOptions);
if (defaultOutputFolder) {
output = path_1.default.join(defaultOutputFolder, 'zod');
}
else {
output = './generated/zod';
}
}
output = (0, sdk_1.resolvePath)(output, this.options);
(0, sdk_1.ensureEmptyDir)(output);
transformer_1.default.setOutputPath(output);
// calculate the models to be excluded
const excludeModels = this.getExcludedModels();
const prismaClientDmmf = this.dmmf;
const modelOperations = prismaClientDmmf.mappings.modelOperations.filter((o) => !excludeModels.find((e) => e === o.model));
const inputObjectTypes = prismaClientDmmf.schema.inputObjectTypes.prisma.filter((type) => !excludeModels.some((e) => type.name.toLowerCase().startsWith(e.toLocaleLowerCase())) &&
// exclude delegate aux related types
!type.name.toLowerCase().includes(runtime_1.DELEGATE_AUX_RELATION_PREFIX));
const outputObjectTypes = prismaClientDmmf.schema.outputObjectTypes.prisma.filter((type) => !excludeModels.some((e) => type.name.toLowerCase().startsWith(e.toLowerCase())) &&
// exclude delegate aux related types
!type.name.toLowerCase().includes(runtime_1.DELEGATE_AUX_RELATION_PREFIX));
const models = prismaClientDmmf.datamodel.models.filter((m) => !excludeModels.find((e) => e === m.name));
// common schemas
yield this.generateCommonSchemas(output);
// enums
yield this.generateEnumSchemas(prismaClientDmmf.schema.enumTypes.prisma, (_a = prismaClientDmmf.schema.enumTypes.model) !== null && _a !== void 0 ? _a : []);
yield this.generateModelSchemas(output, excludeModels);
if (this.options.modelOnly) {
// generate stub for object and input schemas, so the exports from '@zenstackhq/runtime/zod' are available
this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'objects', 'index.ts'), '', { overwrite: true }));
this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'input', 'index.ts'), '', { overwrite: true }));
}
else {
// detailed object schemas referenced from input schemas
(0, dmmf_helpers_1.addMissingInputObjectTypes)(inputObjectTypes, outputObjectTypes, models);
const aggregateOperationSupport = (0, dmmf_helpers_1.resolveAggregateOperationSupport)(inputObjectTypes);
yield this.generateObjectSchemas(inputObjectTypes, output);
// input schemas
const transformer = new transformer_1.default({
models,
modelOperations,
aggregateOperationSupport,
project: this.project,
inputObjectTypes,
zmodel: this.model,
mode: this.mode,
});
yield transformer.generateInputSchemas(this.options, this.model);
this.sourceFiles.push(...transformer.sourceFiles);
}
// create barrel file
const exports = [`export * as models from './models'`, `export * as enums from './enums'`];
if (this.options.modelOnly !== true) {
exports.push(`export * as input from './input'`, `export * as objects from './objects'`);
}
this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'index.ts'), exports.join(';\n'), { overwrite: true }));
if (this.options.preserveTsFiles === true || this.options.output) {
// if preserveTsFiles is true or the user provided a custom output directory,
// save the generated files
this.sourceFiles.forEach(sdk_1.saveSourceFile);
}
});
}
get project() {
return this.globalOptions.tsProject;
}
getExcludedModels() {
// resolve "generateModels" option
const generateModels = (0, sdk_1.parseOptionAsStrings)(this.options, 'generateModels', _1.name);
if (generateModels) {
if (this.options.modelOnly === true) {
// no model reference needs to be considered, directly exclude any model not included
return this.model.declarations
.filter((d) => (0, ast_1.isDataModel)(d) && !generateModels.includes(d.name))
.map((m) => m.name);
}
else {
// calculate a transitive closure of models to be included
const todo = (0, sdk_1.getDataModels)(this.model).filter((dm) => generateModels.includes(dm.name));
const included = new Set();
while (todo.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const dm = todo.pop();
included.add(dm);
// add referenced models to the todo list
dm.fields
.map((f) => { var _a; return (_a = f.type.reference) === null || _a === void 0 ? void 0 : _a.ref; })
.filter((type) => (0, ast_1.isDataModel)(type))
.forEach((type) => {
if (!included.has(type)) {
todo.push(type);
}
});
}
// finally find the models to be excluded
return (0, sdk_1.getDataModels)(this.model)
.filter((dm) => !included.has(dm))
.map((m) => m.name);
}
}
else {
return [];
}
}
generateCommonSchemas(output) {
return __awaiter(this, void 0, void 0, function* () {
// Decimal
this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'common', 'index.ts'), `
import { z } from 'zod';
export const DecimalSchema = z.union([z.number(), z.string(), z.object({d: z.number().array(), e: z.number(), s: z.number()}).passthrough()]);
`, { overwrite: true }));
});
}
generateEnumSchemas(prismaSchemaEnum, modelSchemaEnum) {
return __awaiter(this, void 0, void 0, function* () {
const enumTypes = [...prismaSchemaEnum, ...modelSchemaEnum];
const enumNames = enumTypes.map((enumItem) => (0, upper_case_first_1.upperCaseFirst)(enumItem.name));
transformer_1.default.enumNames = enumNames !== null && enumNames !== void 0 ? enumNames : [];
const transformer = new transformer_1.default({
enumTypes,
project: this.project,
inputObjectTypes: [],
zmodel: this.model,
mode: this.mode,
});
yield transformer.generateEnumSchemas();
this.sourceFiles.push(...transformer.sourceFiles);
});
}
generateObjectSchemas(inputObjectTypes, output) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
// whether Prisma's Unchecked* series of input types should be generated
const generateUnchecked = this.options.noUncheckedInput !== true;
const moduleNames = [];
for (let i = 0; i < inputObjectTypes.length; i += 1) {
// exclude delegate aux fields
const fields = (_b = (_a = inputObjectTypes[i]) === null || _a === void 0 ? void 0 : _a.fields) === null || _b === void 0 ? void 0 : _b.filter((f) => !f.name.includes(runtime_1.DELEGATE_AUX_RELATION_PREFIX));
const name = (_c = inputObjectTypes[i]) === null || _c === void 0 ? void 0 : _c.name;
if (!generateUnchecked && name.includes('Unchecked')) {
continue;
}
if (name.includes('CreateMany') && !(0, prisma_1.supportCreateMany)(this.model)) {
continue;
}
const transformer = new transformer_1.default({
name,
fields,
project: this.project,
inputObjectTypes,
zmodel: this.model,
mode: this.mode,
});
const moduleName = transformer.generateObjectSchema(generateUnchecked, this.options);
moduleNames.push(moduleName);
this.sourceFiles.push(...transformer.sourceFiles);
}
this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'objects/index.ts'), moduleNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true }));
});
}
generateModelSchemas(output, excludedModels) {
return __awaiter(this, void 0, void 0, function* () {
const schemaNames = [];
for (const dm of (0, sdk_1.getDataModels)(this.model)) {
if (!excludedModels.includes(dm.name)) {
schemaNames.push(yield this.generateModelSchema(dm, output));
}
}
for (const typeDef of this.model.declarations.filter(ast_1.isTypeDef)) {
if (!excludedModels.includes(typeDef.name)) {
schemaNames.push(yield this.generateTypeDefSchema(typeDef, output));
}
}
this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'models', 'index.ts'), schemaNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true }));
});
}
generateTypeDefSchema(typeDef, output) {
const schemaName = `${(0, upper_case_first_1.upperCaseFirst)(typeDef.name)}.schema`;
const sf = this.project.createSourceFile(path_1.default.join(output, 'models', `${schemaName}.ts`), undefined, {
overwrite: true,
});
this.sourceFiles.push(sf);
sf.replaceWithText((writer) => {
this.addPreludeAndImports(typeDef, writer, output);
writer.write(`const baseSchema = z.object(`);
writer.inlineBlock(() => {
typeDef.fields.forEach((field) => {
writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
});
});
switch (this.options.mode) {
case 'strip':
// zod strips by default
writer.writeLine(')');
break;
case 'passthrough':
writer.writeLine(').passthrough();');
break;
default:
writer.writeLine(').strict();');
break;
}
// compile "@@validate" to a function calling zod's `.refine()`
const refineFuncName = this.createRefineFunction(typeDef, writer);
if (refineFuncName) {
// export a schema without refinement for extensibility: `[Model]WithoutRefineSchema`
const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(typeDef.name)}WithoutRefineSchema`;
writer.writeLine(`
/**
* \`${typeDef.name}\` schema prior to calling \`.refine()\` for extensibility.
*/
export const ${noRefineSchema} = baseSchema;
export const ${typeDef.name}Schema = ${refineFuncName}(${noRefineSchema});
`);
}
else {
writer.writeLine(`export const ${typeDef.name}Schema = baseSchema;`);
}
});
return schemaName;
}
addPreludeAndImports(decl, writer, output) {
var _a, _b, _c;
writer.writeLine(`import { z } from 'zod';`);
// import user-defined enums from Prisma as they might be referenced in the expressions
const importEnums = new Set();
for (const node of (0, langium_1.streamAllContents)(decl)) {
if ((0, sdk_1.isEnumFieldReference)(node)) {
const field = node.target.ref;
if (!(0, sdk_1.isFromStdlib)(field.$container)) {
importEnums.add(field.$container.name);
}
}
}
if (importEnums.size > 0) {
const prismaImport = computePrismaClientImport(path_1.default.join(output, 'models'), this.options);
writer.writeLine(`import { ${[...importEnums].join(', ')} } from '${prismaImport}';`);
}
// import enum schemas
const importedEnumSchemas = new Set();
for (const field of decl.fields) {
if (((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref) && (0, ast_1.isEnum)((_b = field.type.reference) === null || _b === void 0 ? void 0 : _b.ref)) {
const name = (0, upper_case_first_1.upperCaseFirst)((_c = field.type.reference) === null || _c === void 0 ? void 0 : _c.ref.name);
if (!importedEnumSchemas.has(name)) {
writer.writeLine(`import { ${name}Schema } from '../enums/${name}.schema';`);
importedEnumSchemas.add(name);
}
}
}
// import Decimal
if (decl.fields.some((field) => field.type.type === 'Decimal')) {
writer.writeLine(`import { DecimalSchema } from '../common';`);
writer.writeLine(`import { Decimal } from 'decimal.js';`);
}
// import referenced types' schemas
const referencedTypes = new Set(decl.fields
.filter((field) => { var _a, _b; return (0, ast_1.isTypeDef)((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref) && ((_b = field.type.reference) === null || _b === void 0 ? void 0 : _b.ref.name) !== decl.name; })
.map((field) => field.type.reference.ref.name));
for (const refType of referencedTypes) {
writer.writeLine(`import { ${(0, upper_case_first_1.upperCaseFirst)(refType)}Schema } from './${(0, upper_case_first_1.upperCaseFirst)(refType)}.schema';`);
}
}
generateModelSchema(model, output) {
return __awaiter(this, void 0, void 0, function* () {
const schemaName = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}.schema`;
const sf = this.project.createSourceFile(path_1.default.join(output, 'models', `${schemaName}.ts`), undefined, {
overwrite: true,
});
this.sourceFiles.push(sf);
sf.replaceWithText((writer) => {
const scalarFields = model.fields.filter((field) => {
var _a;
// id fields are always included
return (0, sdk_1.isIdField)(field) ||
// regular fields only
(!(0, ast_1.isDataModel)((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref) && !(0, sdk_1.isForeignKeyField)(field));
});
const relations = model.fields.filter((field) => { var _a; return (0, ast_1.isDataModel)((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref); });
const fkFields = model.fields.filter((field) => (0, sdk_1.isForeignKeyField)(field));
this.addPreludeAndImports(model, writer, output);
// base schema - including all scalar fields, with optionality following the schema
writer.write(`const baseSchema = z.object(`);
writer.inlineBlock(() => {
scalarFields.forEach((field) => {
writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
});
});
switch (this.options.mode) {
case 'strip':
// zod strips by default
writer.writeLine(')');
break;
case 'passthrough':
writer.writeLine(').passthrough();');
break;
default:
writer.writeLine(').strict();');
break;
}
// relation fields
let relationSchema;
let fkSchema;
if (relations.length > 0) {
relationSchema = 'relationSchema';
writer.write(`const ${relationSchema} = z.object(`);
writer.inlineBlock(() => {
[...relations].forEach((field) => {
writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
});
});
writer.writeLine(');');
}
if (fkFields.length > 0) {
fkSchema = 'fkSchema';
writer.write(`const ${fkSchema} = z.object(`);
writer.inlineBlock(() => {
fkFields.forEach((field) => {
writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
});
});
writer.writeLine(');');
}
// compile "@@validate" to ".refine"
const refineFuncName = this.createRefineFunction(model, writer);
// delegate discriminator fields are to be excluded from mutation schemas
const delegateDiscriminatorFields = model.fields.filter((field) => (0, sdk_1.isDiscriminatorField)(field));
const omitDiscriminators = delegateDiscriminatorFields.length > 0
? `.omit({ ${delegateDiscriminatorFields.map((f) => `${f.name}: true`).join(', ')} })`
: '';
////////////////////////////////////////////////
// 1. Model schema
////////////////////////////////////////////////
let modelSchema = 'baseSchema';
// omit fields
const fieldsToOmit = scalarFields.filter((field) => (0, sdk_1.hasAttribute)(field, '@omit'));
if (fieldsToOmit.length > 0) {
modelSchema = this.makeOmit(modelSchema, fieldsToOmit.map((f) => f.name));
}
// export schema with only scalar fields: `[Model]ScalarSchema`
const modelScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}ScalarSchema`;
writer.writeLine(`
/**
* \`${model.name}\` schema excluding foreign keys and relations.
*/
export const ${modelScalarSchema} = ${modelSchema};
`);
modelSchema = modelScalarSchema;
// merge fk fields
if (fkSchema) {
modelSchema = this.makeMerge(modelSchema, fkSchema);
}
// merge relation fields (all optional)
if (relationSchema) {
modelSchema = this.makeMerge(modelSchema, this.makePartial(relationSchema));
}
// refine
if (refineFuncName) {
// export a schema without refinement for extensibility: `[Model]WithoutRefineSchema`
const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}WithoutRefineSchema`;
writer.writeLine(`
/**
* \`${model.name}\` schema prior to calling \`.refine()\` for extensibility.
*/
export const ${noRefineSchema} = ${modelSchema};
`);
modelSchema = `${refineFuncName}(${noRefineSchema})`;
}
// export the final model schema: `[Model]Schema`
writer.writeLine(`
/**
* \`${model.name}\` schema including all fields (scalar, foreign key, and relations) and validations.
*/
export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}Schema = ${modelSchema};
`);
////////////////////////////////////////////////
// 2. Prisma create & update
////////////////////////////////////////////////
// schema for validating prisma create input (all fields optional)
let prismaCreateSchema = this.makePassthrough(this.makePartial(`baseSchema${omitDiscriminators}`));
if (refineFuncName) {
prismaCreateSchema = `${refineFuncName}(${prismaCreateSchema})`;
}
writer.writeLine(`
/**
* Schema used for validating Prisma create input. For internal use only.
* @private
*/
export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}PrismaCreateSchema = ${prismaCreateSchema};
`);
// schema for validating prisma update input (all fields optional)
// note numeric fields can be simple update or atomic operations
let prismaUpdateSchema = `z.object({
${scalarFields
.filter((f) => !(0, sdk_1.isDiscriminatorField)(f))
.map((field) => {
let fieldSchema = (0, schema_gen_1.makeFieldSchema)(field);
if (field.type.type === 'Int' || field.type.type === 'Float') {
fieldSchema = `z.union([${fieldSchema}, z.record(z.unknown())])`;
}
return `\t${field.name}: ${fieldSchema}`;
})
.join(',\n')}
})`;
prismaUpdateSchema = this.makePassthrough(this.makePartial(prismaUpdateSchema));
writer.writeLine(`
/**
* Schema used for validating Prisma update input. For internal use only.
* @private
*/
export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}PrismaUpdateSchema = ${prismaUpdateSchema};
`);
////////////////////////////////////////////////
// 3. Create schema
////////////////////////////////////////////////
let createSchema = `baseSchema${omitDiscriminators}`;
const fieldsWithDefault = scalarFields.filter((field) => (0, sdk_1.hasAttribute)(field, '@default') || (0, sdk_1.hasAttribute)(field, '@updatedAt') || field.type.array);
// mark fields with default as optional
if (fieldsWithDefault.length > 0) {
// delegate discriminator fields are omitted from the base schema, so we need
// to take care not to make them partial otherwise the schema won't compile
createSchema = this.makePartial(createSchema, fieldsWithDefault.filter((f) => !delegateDiscriminatorFields.includes(f)).map((f) => f.name));
}
// export schema with only scalar fields: `[Model]CreateScalarSchema`
const createScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateScalarSchema`;
writer.writeLine(`
/**
* \`${model.name}\` schema for create operations excluding foreign keys and relations.
*/
export const ${createScalarSchema} = ${createSchema};
`);
if (fkSchema) {
// merge fk fields
createSchema = this.makeMerge(createScalarSchema, fkSchema);
}
if (refineFuncName) {
// export a schema without refinement for extensibility: `[Model]CreateWithoutRefineSchema`
const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateWithoutRefineSchema`;
writer.writeLine(`
/**
* \`${model.name}\` schema for create operations prior to calling \`.refine()\` for extensibility.
*/
export const ${noRefineSchema} = ${createSchema};
`);
createSchema = `${refineFuncName}(${noRefineSchema})`;
}
// export the final create schema: `[Model]CreateSchema`
writer.writeLine(`
/**
* \`${model.name}\` schema for create operations including scalar fields, foreign key fields, and validations.
*/
export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateSchema = ${createSchema};
`);
////////////////////////////////////////////////
// 3. Update schema
////////////////////////////////////////////////
// for update all fields are optional
let updateSchema = this.makePartial(`baseSchema${omitDiscriminators}`);
// export schema with only scalar fields: `[Model]UpdateScalarSchema`
const updateScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateScalarSchema`;
writer.writeLine(`
/**
* \`${model.name}\` schema for update operations excluding foreign keys and relations.
*/
export const ${updateScalarSchema} = ${updateSchema};
`);
updateSchema = updateScalarSchema;
if (fkSchema) {
// merge fk fields
updateSchema = this.makeMerge(updateSchema, this.makePartial(fkSchema));
}
if (refineFuncName) {
// export a schema without refinement for extensibility: `[Model]UpdateWithoutRefineSchema`
const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateWithoutRefineSchema`;
writer.writeLine(`
/**
* \`${model.name}\` schema for update operations prior to calling \`.refine()\` for extensibility.
*/
export const ${noRefineSchema} = ${updateSchema};
`);
updateSchema = `${refineFuncName}(${noRefineSchema})`;
}
// export the final update schema: `[Model]UpdateSchema`
writer.writeLine(`
/**
* \`${model.name}\` schema for update operations including scalar fields, foreign key fields, and validations.
*/
export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateSchema = ${updateSchema};
`);
});
return schemaName;
});
}
createRefineFunction(decl, writer) {
const refinements = this.makeValidationRefinements(decl);
let refineFuncName;
if (refinements.length > 0) {
refineFuncName = `refine${(0, upper_case_first_1.upperCaseFirst)(decl.name)}`;
writer.writeLine(`
/**
* Schema refinement function for applying \`@@validate\` rules.
*/
export function ${refineFuncName}<T, D extends z.ZodTypeDef>(schema: z.ZodType<T, D, T>) { return schema${refinements.join('\n')};
}
`);
return refineFuncName;
}
else {
return undefined;
}
}
makeValidationRefinements(decl) {
const attrs = decl.attributes.filter((attr) => { var _a; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@@validate'; });
const refinements = attrs
.map((attr) => {
var _a;
const valueArg = (0, sdk_1.getAttributeArg)(attr, 'value');
if (!valueArg) {
return undefined;
}
const messageArg = (0, sdk_1.getAttributeArgLiteral)(attr, 'message');
const message = messageArg ? `message: ${JSON.stringify(messageArg)},` : '';
const pathArg = (0, sdk_1.getAttributeArg)(attr, 'path');
const path = pathArg && (0, ast_1.isArrayExpr)(pathArg)
? `path: ['${(_a = (0, sdk_1.getLiteralArray)(pathArg)) === null || _a === void 0 ? void 0 : _a.join(`', '`)}'],`
: '';
const options = `, { ${message} ${path} }`;
try {
let expr = new sdk_1.TypeScriptExpressionTransformer({
context: sdk_1.ExpressionContext.ValidationRule,
fieldReferenceContext: 'value',
}).transform(valueArg);
if ((0, sdk_1.isDataModelFieldReference)(valueArg)) {
// if the expression is a simple field reference, treat undefined
// as true since the all fields are optional in validation context
expr = `${expr} ?? true`;
}
return `.refine((value: any) => ${expr}${options})`;
}
catch (err) {
if (err instanceof sdk_1.TypeScriptExpressionTransformerError) {
throw new sdk_1.PluginError(_1.name, err.message);
}
else {
throw err;
}
}
})
.filter((r) => !!r);
return refinements;
}
makePartial(schema, fields) {
if (fields) {
if (fields.length === 0) {
return schema;
}
else {
return `${schema}.partial({
${fields.map((f) => `${f}: true`).join(', ')}
})`;
}
}
else {
return `${schema}.partial()`;
}
}
makeOmit(schema, fields) {
return `${schema}.omit({
${fields.map((f) => `${f}: true`).join(', ')},
})`;
}
makeMerge(schema1, schema2) {
return `${schema1}.merge(${schema2})`;
}
makePassthrough(schema) {
return `${schema}.passthrough()`;
}
}
exports.ZodSchemaGenerator = ZodSchemaGenerator;
function computePrismaClientImport(importingFrom, options) {
let importPath = (0, prisma_1.getPrismaClientImportSpec)(importingFrom, options);
if (importPath.startsWith(sdk_1.RUNTIME_PACKAGE) && !options.output) {
// default import from `@zenstackhq/runtime` and this plugin is generating
// into default location, we should correct the prisma client import into a
// importing from `.zenstack` to avoid cyclic dependencies with runtime
importPath = importPath.replace(sdk_1.RUNTIME_PACKAGE, '.zenstack');
}
return importPath;
}
//# sourceMappingURL=generator.js.map
;