zenstack 2.0.0-alpha.1 → 2.0.0-alpha.3

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.
Files changed (59) hide show
  1. package/README.md +29 -1
  2. package/bin/post-install.js +1 -1
  3. package/cli/actions/repl.js +31 -4
  4. package/cli/actions/repl.js.map +1 -1
  5. package/cli/cli-util.js +1 -1
  6. package/cli/cli-util.js.map +1 -1
  7. package/cli/plugin-runner.js +63 -42
  8. package/cli/plugin-runner.js.map +1 -1
  9. package/constants.js +1 -1
  10. package/language-server/validator/datamodel-validator.js +17 -7
  11. package/language-server/validator/datamodel-validator.js.map +1 -1
  12. package/language-server/validator/schema-validator.js +2 -1
  13. package/language-server/validator/schema-validator.js.map +1 -1
  14. package/package.json +5 -5
  15. package/plugins/enhancer/enhance/index.d.ts +4 -1
  16. package/plugins/enhancer/enhance/index.js +245 -111
  17. package/plugins/enhancer/enhance/index.js.map +1 -1
  18. package/plugins/enhancer/enhancer-utils.d.ts +5 -0
  19. package/plugins/enhancer/enhancer-utils.js +22 -0
  20. package/plugins/enhancer/enhancer-utils.js.map +1 -0
  21. package/plugins/enhancer/index.js +25 -21
  22. package/plugins/enhancer/index.js.map +1 -1
  23. package/plugins/enhancer/model-meta/index.js +3 -0
  24. package/plugins/enhancer/model-meta/index.js.map +1 -1
  25. package/plugins/enhancer/policy/policy-guard-generator.d.ts +1 -1
  26. package/plugins/enhancer/policy/policy-guard-generator.js +7 -2
  27. package/plugins/enhancer/policy/policy-guard-generator.js.map +1 -1
  28. package/plugins/plugin-utils.js +3 -0
  29. package/plugins/plugin-utils.js.map +1 -1
  30. package/plugins/prisma/index.d.ts +1 -0
  31. package/plugins/prisma/index.js +92 -2
  32. package/plugins/prisma/index.js.map +1 -1
  33. package/plugins/prisma/schema-generator.d.ts +4 -4
  34. package/plugins/prisma/schema-generator.js +48 -81
  35. package/plugins/prisma/schema-generator.js.map +1 -1
  36. package/plugins/zod/generator.d.ts +21 -1
  37. package/plugins/zod/generator.js +364 -352
  38. package/plugins/zod/generator.js.map +1 -1
  39. package/plugins/zod/index.js +2 -1
  40. package/plugins/zod/index.js.map +1 -1
  41. package/plugins/zod/transformer.d.ts +7 -5
  42. package/plugins/zod/transformer.js +18 -14
  43. package/plugins/zod/transformer.js.map +1 -1
  44. package/plugins/zod/types.d.ts +0 -2
  45. package/plugins/zod/utils/schema-gen.js +1 -1
  46. package/plugins/zod/utils/schema-gen.js.map +1 -1
  47. package/res/stdlib.zmodel +2 -2
  48. package/telemetry.d.ts +1 -1
  49. package/telemetry.js +1 -1
  50. package/telemetry.js.map +1 -1
  51. package/utils/exec-utils.d.ts +6 -0
  52. package/utils/exec-utils.js +10 -1
  53. package/utils/exec-utils.js.map +1 -1
  54. package/utils/pkg-utils.d.ts +29 -0
  55. package/utils/pkg-utils.js +42 -22
  56. package/utils/pkg-utils.js.map +1 -1
  57. package/plugins/enhancer/delegate/index.d.ts +0 -4
  58. package/plugins/enhancer/delegate/index.js +0 -31
  59. package/plugins/enhancer/delegate/index.js.map +0 -1
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.generate = void 0;
15
+ exports.ZodSchemaGenerator = void 0;
16
16
  const sdk_1 = require("@zenstackhq/sdk");
17
17
  const ast_1 = require("@zenstackhq/sdk/ast");
18
18
  const dmmf_helpers_1 = require("@zenstackhq/sdk/dmmf-helpers");
@@ -25,385 +25,397 @@ const plugin_utils_1 = require("../plugin-utils");
25
25
  const transformer_1 = __importDefault(require("./transformer"));
26
26
  const removeDir_1 = __importDefault(require("./utils/removeDir"));
27
27
  const schema_gen_1 = require("./utils/schema-gen");
28
- function generate(model, options, dmmf, globalOptions) {
29
- var _a, _b;
30
- return __awaiter(this, void 0, void 0, function* () {
31
- let output = options.output;
32
- if (!output) {
33
- const defaultOutputFolder = (0, plugin_utils_1.getDefaultOutputFolder)(globalOptions);
34
- if (defaultOutputFolder) {
35
- output = path_1.default.join(defaultOutputFolder, 'zod');
28
+ class ZodSchemaGenerator {
29
+ constructor(model, options, dmmf, globalOptions) {
30
+ this.model = model;
31
+ this.options = options;
32
+ this.dmmf = dmmf;
33
+ this.sourceFiles = [];
34
+ if (!globalOptions) {
35
+ throw new Error('Global options are required');
36
+ }
37
+ this.globalOptions = globalOptions;
38
+ }
39
+ generate() {
40
+ var _a, _b;
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ let output = this.options.output;
43
+ if (!output) {
44
+ const defaultOutputFolder = (0, plugin_utils_1.getDefaultOutputFolder)(this.globalOptions);
45
+ if (defaultOutputFolder) {
46
+ output = path_1.default.join(defaultOutputFolder, 'zod');
47
+ }
48
+ else {
49
+ output = './generated/zod';
50
+ }
51
+ }
52
+ output = (0, sdk_1.resolvePath)(output, this.options);
53
+ yield this.handleGeneratorOutputValue(output);
54
+ // calculate the models to be excluded
55
+ const excludeModels = this.getExcludedModels();
56
+ const prismaClientDmmf = this.dmmf;
57
+ const modelOperations = prismaClientDmmf.mappings.modelOperations.filter((o) => !excludeModels.find((e) => e === o.model));
58
+ // TODO: better way of filtering than string startsWith?
59
+ const inputObjectTypes = prismaClientDmmf.schema.inputObjectTypes.prisma.filter((type) => !excludeModels.find((e) => type.name.toLowerCase().startsWith(e.toLocaleLowerCase())));
60
+ const outputObjectTypes = prismaClientDmmf.schema.outputObjectTypes.prisma.filter((type) => !excludeModels.find((e) => type.name.toLowerCase().startsWith(e.toLowerCase())));
61
+ const models = prismaClientDmmf.datamodel.models.filter((m) => !excludeModels.find((e) => e === m.name));
62
+ // common schemas
63
+ yield this.generateCommonSchemas(output);
64
+ // enums
65
+ yield this.generateEnumSchemas(prismaClientDmmf.schema.enumTypes.prisma, (_a = prismaClientDmmf.schema.enumTypes.model) !== null && _a !== void 0 ? _a : []);
66
+ const dataSource = this.model.declarations.find((d) => (0, ast_1.isDataSource)(d));
67
+ const dataSourceProvider = (0, sdk_1.getLiteral)((_b = dataSource === null || dataSource === void 0 ? void 0 : dataSource.fields.find((f) => f.name === 'provider')) === null || _b === void 0 ? void 0 : _b.value);
68
+ yield this.generateModelSchemas(output, excludeModels);
69
+ if (this.options.modelOnly !== true) {
70
+ // detailed object schemas referenced from input schemas
71
+ transformer_1.default.provider = dataSourceProvider;
72
+ (0, dmmf_helpers_1.addMissingInputObjectTypes)(inputObjectTypes, outputObjectTypes, models);
73
+ const aggregateOperationSupport = (0, dmmf_helpers_1.resolveAggregateOperationSupport)(inputObjectTypes);
74
+ yield this.generateObjectSchemas(inputObjectTypes, output);
75
+ // input schemas
76
+ const transformer = new transformer_1.default({
77
+ models,
78
+ modelOperations,
79
+ aggregateOperationSupport,
80
+ project: this.project,
81
+ inputObjectTypes,
82
+ });
83
+ yield transformer.generateInputSchemas(this.options);
84
+ this.sourceFiles.push(...transformer.sourceFiles);
85
+ }
86
+ // create barrel file
87
+ const exports = [`export * as models from './models'`, `export * as enums from './enums'`];
88
+ if (this.options.modelOnly !== true) {
89
+ exports.push(`export * as input from './input'`, `export * as objects from './objects'`);
90
+ }
91
+ this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'index.ts'), exports.join(';\n'), { overwrite: true }));
92
+ if (this.options.preserveTsFiles === true || this.options.output) {
93
+ // if preserveTsFiles is true or the user provided a custom output directory,
94
+ // save the generated files
95
+ yield Promise.all(this.sourceFiles.map((sf) => __awaiter(this, void 0, void 0, function* () {
96
+ yield sf.formatText();
97
+ yield sf.save();
98
+ })));
99
+ }
100
+ });
101
+ }
102
+ get project() {
103
+ return this.globalOptions.tsProject;
104
+ }
105
+ getExcludedModels() {
106
+ // resolve "generateModels" option
107
+ const generateModels = (0, sdk_1.parseOptionAsStrings)(this.options, 'generateModels', _1.name);
108
+ if (generateModels) {
109
+ if (this.options.modelOnly === true) {
110
+ // no model reference needs to be considered, directly exclude any model not included
111
+ return this.model.declarations
112
+ .filter((d) => (0, ast_1.isDataModel)(d) && !generateModels.includes(d.name))
113
+ .map((m) => m.name);
36
114
  }
37
115
  else {
38
- output = './generated/zod';
116
+ // calculate a transitive closure of models to be included
117
+ const todo = (0, sdk_1.getDataModels)(this.model).filter((dm) => generateModels.includes(dm.name));
118
+ const included = new Set();
119
+ while (todo.length > 0) {
120
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
121
+ const dm = todo.pop();
122
+ included.add(dm);
123
+ // add referenced models to the todo list
124
+ dm.fields
125
+ .map((f) => { var _a; return (_a = f.type.reference) === null || _a === void 0 ? void 0 : _a.ref; })
126
+ .filter((type) => (0, ast_1.isDataModel)(type))
127
+ .forEach((type) => {
128
+ if (!included.has(type)) {
129
+ todo.push(type);
130
+ }
131
+ });
132
+ }
133
+ // finally find the models to be excluded
134
+ return (0, sdk_1.getDataModels)(this.model)
135
+ .filter((dm) => !included.has(dm))
136
+ .map((m) => m.name);
39
137
  }
40
138
  }
41
- output = (0, sdk_1.resolvePath)(output, options);
42
- yield handleGeneratorOutputValue(output);
43
- // calculate the models to be excluded
44
- const excludeModels = getExcludedModels(model, options);
45
- const prismaClientDmmf = dmmf;
46
- const modelOperations = prismaClientDmmf.mappings.modelOperations.filter((o) => !excludeModels.find((e) => e === o.model));
47
- // TODO: better way of filtering than string startsWith?
48
- const inputObjectTypes = prismaClientDmmf.schema.inputObjectTypes.prisma.filter((type) => !excludeModels.find((e) => type.name.toLowerCase().startsWith(e.toLocaleLowerCase())));
49
- const outputObjectTypes = prismaClientDmmf.schema.outputObjectTypes.prisma.filter((type) => !excludeModels.find((e) => type.name.toLowerCase().startsWith(e.toLowerCase())));
50
- const models = prismaClientDmmf.datamodel.models.filter((m) => !excludeModels.find((e) => e === m.name));
51
- // whether Prisma's Unchecked* series of input types should be generated
52
- const generateUnchecked = options.noUncheckedInput !== true;
53
- const project = (0, sdk_1.createProject)();
54
- // common schemas
55
- yield generateCommonSchemas(project, output);
56
- // enums
57
- yield generateEnumSchemas(prismaClientDmmf.schema.enumTypes.prisma, (_a = prismaClientDmmf.schema.enumTypes.model) !== null && _a !== void 0 ? _a : [], project, model);
58
- const dataSource = model.declarations.find((d) => (0, ast_1.isDataSource)(d));
59
- const dataSourceProvider = (0, sdk_1.getLiteral)((_b = dataSource === null || dataSource === void 0 ? void 0 : dataSource.fields.find((f) => f.name === 'provider')) === null || _b === void 0 ? void 0 : _b.value);
60
- yield generateModelSchemas(project, model, output, excludeModels);
61
- if (options.modelOnly !== true) {
62
- // detailed object schemas referenced from input schemas
63
- transformer_1.default.provider = dataSourceProvider;
64
- (0, dmmf_helpers_1.addMissingInputObjectTypes)(inputObjectTypes, outputObjectTypes, models);
65
- const aggregateOperationSupport = (0, dmmf_helpers_1.resolveAggregateOperationSupport)(inputObjectTypes);
66
- yield generateObjectSchemas(inputObjectTypes, project, output, model, generateUnchecked);
67
- // input schemas
68
- const transformer = new transformer_1.default({
69
- models,
70
- modelOperations,
71
- aggregateOperationSupport,
72
- project,
73
- zmodel: model,
74
- inputObjectTypes,
75
- });
76
- yield transformer.generateInputSchemas(generateUnchecked);
77
- }
78
- // create barrel file
79
- const exports = [`export * as models from './models'`, `export * as enums from './enums'`];
80
- if (options.modelOnly !== true) {
81
- exports.push(`export * as input from './input'`, `export * as objects from './objects'`);
82
- }
83
- project.createSourceFile(path_1.default.join(output, 'index.ts'), exports.join(';\n'), { overwrite: true });
84
- // emit
85
- let shouldCompile = true;
86
- if (typeof options.compile === 'boolean') {
87
- // explicit override
88
- shouldCompile = options.compile;
89
- }
90
- else if (globalOptions) {
91
- // from CLI or config file
92
- shouldCompile = globalOptions.compile;
93
- }
94
- if (!shouldCompile || options.preserveTsFiles === true) {
95
- // save ts files
96
- yield (0, sdk_1.saveProject)(project);
97
- }
98
- if (shouldCompile) {
99
- yield (0, sdk_1.emitProject)(project);
100
- }
101
- });
102
- }
103
- exports.generate = generate;
104
- function getExcludedModels(model, options) {
105
- // resolve "generateModels" option
106
- const generateModels = (0, sdk_1.parseOptionAsStrings)(options, 'generateModels', _1.name);
107
- if (generateModels) {
108
- if (options.modelOnly === true) {
109
- // no model reference needs to be considered, directly exclude any model not included
110
- return model.declarations
111
- .filter((d) => (0, ast_1.isDataModel)(d) && !generateModels.includes(d.name))
112
- .map((m) => m.name);
113
- }
114
139
  else {
115
- // calculate a transitive closure of models to be included
116
- const todo = (0, sdk_1.getDataModels)(model).filter((dm) => generateModels.includes(dm.name));
117
- const included = new Set();
118
- while (todo.length > 0) {
119
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
120
- const dm = todo.pop();
121
- included.add(dm);
122
- // add referenced models to the todo list
123
- dm.fields
124
- .map((f) => { var _a; return (_a = f.type.reference) === null || _a === void 0 ? void 0 : _a.ref; })
125
- .filter((type) => (0, ast_1.isDataModel)(type))
126
- .forEach((type) => {
127
- if (!included.has(type)) {
128
- todo.push(type);
129
- }
130
- });
131
- }
132
- // finally find the models to be excluded
133
- return (0, sdk_1.getDataModels)(model)
134
- .filter((dm) => !included.has(dm))
135
- .map((m) => m.name);
140
+ return [];
136
141
  }
137
142
  }
138
- else {
139
- return [];
143
+ handleGeneratorOutputValue(output) {
144
+ return __awaiter(this, void 0, void 0, function* () {
145
+ // create the output directory and delete contents that might exist from a previous run
146
+ yield fs_1.promises.mkdir(output, { recursive: true });
147
+ const isRemoveContentsOnly = true;
148
+ yield (0, removeDir_1.default)(output, isRemoveContentsOnly);
149
+ transformer_1.default.setOutputPath(output);
150
+ });
140
151
  }
141
- }
142
- function handleGeneratorOutputValue(output) {
143
- return __awaiter(this, void 0, void 0, function* () {
144
- // create the output directory and delete contents that might exist from a previous run
145
- yield fs_1.promises.mkdir(output, { recursive: true });
146
- const isRemoveContentsOnly = true;
147
- yield (0, removeDir_1.default)(output, isRemoveContentsOnly);
148
- transformer_1.default.setOutputPath(output);
149
- });
150
- }
151
- function generateCommonSchemas(project, output) {
152
- return __awaiter(this, void 0, void 0, function* () {
153
- // Decimal
154
- project.createSourceFile(path_1.default.join(output, 'common', 'index.ts'), `
155
- import { z } from 'zod';
156
- export const DecimalSchema = z.union([z.number(), z.string(), z.object({d: z.number().array(), e: z.number(), s: z.number()}).passthrough()]);
157
- `, { overwrite: true });
158
- });
159
- }
160
- function generateEnumSchemas(prismaSchemaEnum, modelSchemaEnum, project, zmodel) {
161
- return __awaiter(this, void 0, void 0, function* () {
162
- const enumTypes = [...prismaSchemaEnum, ...modelSchemaEnum];
163
- const enumNames = enumTypes.map((enumItem) => (0, upper_case_first_1.upperCaseFirst)(enumItem.name));
164
- transformer_1.default.enumNames = enumNames !== null && enumNames !== void 0 ? enumNames : [];
165
- const transformer = new transformer_1.default({
166
- enumTypes,
167
- project,
168
- zmodel,
169
- inputObjectTypes: [],
152
+ generateCommonSchemas(output) {
153
+ return __awaiter(this, void 0, void 0, function* () {
154
+ // Decimal
155
+ this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'common', 'index.ts'), `
156
+ import { z } from 'zod';
157
+ export const DecimalSchema = z.union([z.number(), z.string(), z.object({d: z.number().array(), e: z.number(), s: z.number()}).passthrough()]);
158
+ `, { overwrite: true }));
170
159
  });
171
- yield transformer.generateEnumSchemas();
172
- });
173
- }
174
- function generateObjectSchemas(inputObjectTypes, project, output, zmodel, generateUnchecked) {
175
- var _a, _b;
176
- return __awaiter(this, void 0, void 0, function* () {
177
- const moduleNames = [];
178
- for (let i = 0; i < inputObjectTypes.length; i += 1) {
179
- const fields = (_a = inputObjectTypes[i]) === null || _a === void 0 ? void 0 : _a.fields;
180
- const name = (_b = inputObjectTypes[i]) === null || _b === void 0 ? void 0 : _b.name;
181
- if (!generateUnchecked && name.includes('Unchecked')) {
182
- continue;
160
+ }
161
+ generateEnumSchemas(prismaSchemaEnum, modelSchemaEnum) {
162
+ return __awaiter(this, void 0, void 0, function* () {
163
+ const enumTypes = [...prismaSchemaEnum, ...modelSchemaEnum];
164
+ const enumNames = enumTypes.map((enumItem) => (0, upper_case_first_1.upperCaseFirst)(enumItem.name));
165
+ transformer_1.default.enumNames = enumNames !== null && enumNames !== void 0 ? enumNames : [];
166
+ const transformer = new transformer_1.default({
167
+ enumTypes,
168
+ project: this.project,
169
+ inputObjectTypes: [],
170
+ });
171
+ yield transformer.generateEnumSchemas();
172
+ this.sourceFiles.push(...transformer.sourceFiles);
173
+ });
174
+ }
175
+ generateObjectSchemas(inputObjectTypes, output) {
176
+ var _a, _b;
177
+ return __awaiter(this, void 0, void 0, function* () {
178
+ // whether Prisma's Unchecked* series of input types should be generated
179
+ const generateUnchecked = this.options.noUncheckedInput !== true;
180
+ const moduleNames = [];
181
+ for (let i = 0; i < inputObjectTypes.length; i += 1) {
182
+ const fields = (_a = inputObjectTypes[i]) === null || _a === void 0 ? void 0 : _a.fields;
183
+ const name = (_b = inputObjectTypes[i]) === null || _b === void 0 ? void 0 : _b.name;
184
+ if (!generateUnchecked && name.includes('Unchecked')) {
185
+ continue;
186
+ }
187
+ const transformer = new transformer_1.default({
188
+ name,
189
+ fields,
190
+ project: this.project,
191
+ inputObjectTypes,
192
+ });
193
+ const moduleName = transformer.generateObjectSchema(generateUnchecked, this.options);
194
+ moduleNames.push(moduleName);
195
+ this.sourceFiles.push(...transformer.sourceFiles);
183
196
  }
184
- const transformer = new transformer_1.default({ name, fields, project, zmodel, inputObjectTypes });
185
- const moduleName = transformer.generateObjectSchema(generateUnchecked);
186
- moduleNames.push(moduleName);
187
- }
188
- project.createSourceFile(path_1.default.join(output, 'objects/index.ts'), moduleNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true });
189
- });
190
- }
191
- function generateModelSchemas(project, zmodel, output, excludedModels) {
192
- return __awaiter(this, void 0, void 0, function* () {
193
- const schemaNames = [];
194
- for (const dm of (0, sdk_1.getDataModels)(zmodel)) {
195
- if (!excludedModels.includes(dm.name)) {
196
- schemaNames.push(yield generateModelSchema(dm, project, output));
197
+ this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'objects/index.ts'), moduleNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true }));
198
+ });
199
+ }
200
+ generateModelSchemas(output, excludedModels) {
201
+ return __awaiter(this, void 0, void 0, function* () {
202
+ const schemaNames = [];
203
+ for (const dm of (0, sdk_1.getDataModels)(this.model)) {
204
+ if (!excludedModels.includes(dm.name)) {
205
+ schemaNames.push(yield this.generateModelSchema(dm, output));
206
+ }
197
207
  }
198
- }
199
- project.createSourceFile(path_1.default.join(output, 'models', 'index.ts'), schemaNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true });
200
- });
201
- }
202
- function generateModelSchema(model, project, output) {
203
- return __awaiter(this, void 0, void 0, function* () {
204
- const schemaName = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}.schema`;
205
- const sf = project.createSourceFile(path_1.default.join(output, 'models', `${schemaName}.ts`), undefined, {
206
- overwrite: true,
208
+ this.sourceFiles.push(this.project.createSourceFile(path_1.default.join(output, 'models', 'index.ts'), schemaNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true }));
207
209
  });
208
- sf.replaceWithText((writer) => {
209
- var _a, _b, _c;
210
- const scalarFields = model.fields.filter((field) => { var _a;
211
- // regular fields only
212
- return !(0, ast_1.isDataModel)((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref) && !(0, sdk_1.isForeignKeyField)(field); });
213
- 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); });
214
- const fkFields = model.fields.filter((field) => (0, sdk_1.isForeignKeyField)(field));
215
- writer.writeLine('/* eslint-disable */');
216
- writer.writeLine(`import { z } from 'zod';`);
217
- // import user-defined enums from Prisma as they might be referenced in the expressions
218
- const importEnums = new Set();
219
- for (const node of (0, langium_1.streamAllContents)(model)) {
220
- if ((0, sdk_1.isEnumFieldReference)(node)) {
221
- const field = node.target.ref;
222
- if (!(0, sdk_1.isFromStdlib)(field.$container)) {
223
- importEnums.add(field.$container.name);
210
+ }
211
+ generateModelSchema(model, output) {
212
+ return __awaiter(this, void 0, void 0, function* () {
213
+ const schemaName = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}.schema`;
214
+ const sf = this.project.createSourceFile(path_1.default.join(output, 'models', `${schemaName}.ts`), undefined, {
215
+ overwrite: true,
216
+ });
217
+ this.sourceFiles.push(sf);
218
+ sf.replaceWithText((writer) => {
219
+ var _a, _b, _c;
220
+ const scalarFields = model.fields.filter((field) => { var _a;
221
+ // regular fields only
222
+ return !(0, ast_1.isDataModel)((_a = field.type.reference) === null || _a === void 0 ? void 0 : _a.ref) && !(0, sdk_1.isForeignKeyField)(field); });
223
+ 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); });
224
+ const fkFields = model.fields.filter((field) => (0, sdk_1.isForeignKeyField)(field));
225
+ writer.writeLine('/* eslint-disable */');
226
+ writer.writeLine(`import { z } from 'zod';`);
227
+ // import user-defined enums from Prisma as they might be referenced in the expressions
228
+ const importEnums = new Set();
229
+ for (const node of (0, langium_1.streamAllContents)(model)) {
230
+ if ((0, sdk_1.isEnumFieldReference)(node)) {
231
+ const field = node.target.ref;
232
+ if (!(0, sdk_1.isFromStdlib)(field.$container)) {
233
+ importEnums.add(field.$container.name);
234
+ }
224
235
  }
225
236
  }
226
- }
227
- if (importEnums.size > 0) {
228
- const prismaImport = (0, sdk_1.getPrismaClientImportSpec)(model.$container, path_1.default.join(output, 'models'));
229
- writer.writeLine(`import { ${[...importEnums].join(', ')} } from '${prismaImport}';`);
230
- }
231
- // import enum schemas
232
- const importedEnumSchemas = new Set();
233
- for (const field of scalarFields) {
234
- 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)) {
235
- const name = (0, upper_case_first_1.upperCaseFirst)((_c = field.type.reference) === null || _c === void 0 ? void 0 : _c.ref.name);
236
- if (!importedEnumSchemas.has(name)) {
237
- writer.writeLine(`import { ${name}Schema } from '../enums/${name}.schema';`);
238
- importedEnumSchemas.add(name);
237
+ if (importEnums.size > 0) {
238
+ const prismaImport = (0, sdk_1.getPrismaClientImportSpec)(path_1.default.join(output, 'models'), this.options);
239
+ writer.writeLine(`import { ${[...importEnums].join(', ')} } from '${prismaImport}';`);
240
+ }
241
+ // import enum schemas
242
+ const importedEnumSchemas = new Set();
243
+ for (const field of scalarFields) {
244
+ 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)) {
245
+ const name = (0, upper_case_first_1.upperCaseFirst)((_c = field.type.reference) === null || _c === void 0 ? void 0 : _c.ref.name);
246
+ if (!importedEnumSchemas.has(name)) {
247
+ writer.writeLine(`import { ${name}Schema } from '../enums/${name}.schema';`);
248
+ importedEnumSchemas.add(name);
249
+ }
239
250
  }
240
251
  }
241
- }
242
- // import Decimal
243
- if (scalarFields.some((field) => field.type.type === 'Decimal')) {
244
- writer.writeLine(`import { DecimalSchema } from '../common';`);
245
- writer.writeLine(`import { Decimal } from 'decimal.js';`);
246
- }
247
- // base schema
248
- writer.write(`const baseSchema = z.object(`);
249
- writer.inlineBlock(() => {
250
- scalarFields.forEach((field) => {
251
- writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field, true)},`);
252
- });
253
- });
254
- writer.writeLine(');');
255
- // relation fields
256
- let relationSchema;
257
- let fkSchema;
258
- if (relations.length > 0 || fkFields.length > 0) {
259
- relationSchema = 'relationSchema';
260
- writer.write(`const ${relationSchema} = z.object(`);
252
+ // import Decimal
253
+ if (scalarFields.some((field) => field.type.type === 'Decimal')) {
254
+ writer.writeLine(`import { DecimalSchema } from '../common';`);
255
+ writer.writeLine(`import { Decimal } from 'decimal.js';`);
256
+ }
257
+ // base schema
258
+ writer.write(`const baseSchema = z.object(`);
261
259
  writer.inlineBlock(() => {
262
- [...relations, ...fkFields].forEach((field) => {
263
- writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
260
+ scalarFields.forEach((field) => {
261
+ writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field, true)},`);
264
262
  });
265
263
  });
266
264
  writer.writeLine(');');
267
- }
268
- if (fkFields.length > 0) {
269
- fkSchema = 'fkSchema';
270
- writer.write(`const ${fkSchema} = z.object(`);
271
- writer.inlineBlock(() => {
272
- fkFields.forEach((field) => {
273
- writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
265
+ // relation fields
266
+ let relationSchema;
267
+ let fkSchema;
268
+ if (relations.length > 0 || fkFields.length > 0) {
269
+ relationSchema = 'relationSchema';
270
+ writer.write(`const ${relationSchema} = z.object(`);
271
+ writer.inlineBlock(() => {
272
+ [...relations, ...fkFields].forEach((field) => {
273
+ writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
274
+ });
274
275
  });
275
- });
276
- writer.writeLine(');');
277
- }
278
- // compile "@@validate" to ".refine"
279
- const refinements = (0, schema_gen_1.makeValidationRefinements)(model);
280
- let refineFuncName;
281
- if (refinements.length > 0) {
282
- refineFuncName = `refine${(0, upper_case_first_1.upperCaseFirst)(model.name)}`;
283
- writer.writeLine(`export function ${refineFuncName}<T, D extends z.ZodTypeDef>(schema: z.ZodType<T, D, T>) { return schema${refinements.join('\n')}; }`);
284
- }
285
- ////////////////////////////////////////////////
286
- // 1. Model schema
287
- ////////////////////////////////////////////////
288
- const fieldsWithoutDefault = scalarFields.filter((f) => !(0, schema_gen_1.getFieldSchemaDefault)(f));
289
- // mark fields without default value as optional
290
- let modelSchema = makePartial('baseSchema', fieldsWithoutDefault.length < scalarFields.length ? fieldsWithoutDefault.map((f) => f.name) : undefined);
291
- // omit fields
292
- const fieldsToOmit = scalarFields.filter((field) => (0, sdk_1.hasAttribute)(field, '@omit'));
293
- if (fieldsToOmit.length > 0) {
294
- modelSchema = makeOmit(modelSchema, fieldsToOmit.map((f) => f.name));
295
- }
296
- if (relationSchema) {
297
- // export schema with only scalar fields
298
- const modelScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}ScalarSchema`;
299
- writer.writeLine(`export const ${modelScalarSchema} = ${modelSchema};`);
300
- modelSchema = modelScalarSchema;
301
- // merge relations
302
- modelSchema = makeMerge(modelSchema, makePartial(relationSchema));
303
- }
304
- // refine
305
- if (refineFuncName) {
306
- const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}WithoutRefineSchema`;
307
- writer.writeLine(`export const ${noRefineSchema} = ${modelSchema};`);
308
- modelSchema = `${refineFuncName}(${noRefineSchema})`;
309
- }
310
- writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}Schema = ${modelSchema};`);
311
- ////////////////////////////////////////////////
312
- // 2. Prisma create & update
313
- ////////////////////////////////////////////////
314
- // schema for validating prisma create input (all fields optional)
315
- let prismaCreateSchema = makePassthrough(makePartial('baseSchema'));
316
- if (refineFuncName) {
317
- prismaCreateSchema = `${refineFuncName}(${prismaCreateSchema})`;
318
- }
319
- writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}PrismaCreateSchema = ${prismaCreateSchema};`);
320
- // schema for validating prisma update input (all fields optional)
321
- // note numeric fields can be simple update or atomic operations
322
- let prismaUpdateSchema = `z.object({
323
- ${scalarFields
324
- .map((field) => {
325
- let fieldSchema = (0, schema_gen_1.makeFieldSchema)(field);
326
- if (field.type.type === 'Int' || field.type.type === 'Float') {
327
- fieldSchema = `z.union([${fieldSchema}, z.record(z.unknown())])`;
276
+ writer.writeLine(');');
328
277
  }
329
- return `\t${field.name}: ${fieldSchema}`;
330
- })
331
- .join(',\n')}
332
- })`;
333
- prismaUpdateSchema = makePartial(prismaUpdateSchema);
334
- if (refineFuncName) {
335
- prismaUpdateSchema = `${refineFuncName}(${prismaUpdateSchema})`;
336
- }
337
- writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}PrismaUpdateSchema = ${prismaUpdateSchema};`);
338
- ////////////////////////////////////////////////
339
- // 3. Create schema
340
- ////////////////////////////////////////////////
341
- let createSchema = 'baseSchema';
342
- const fieldsWithDefault = scalarFields.filter((field) => (0, sdk_1.hasAttribute)(field, '@default') || (0, sdk_1.hasAttribute)(field, '@updatedAt') || field.type.array);
343
- if (fieldsWithDefault.length > 0) {
344
- createSchema = makePartial(createSchema, fieldsWithDefault.map((f) => f.name));
345
- }
346
- if (fkSchema) {
347
- // export schema with only scalar fields
348
- const createScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateScalarSchema`;
349
- writer.writeLine(`export const ${createScalarSchema} = ${createSchema};`);
350
- // merge fk fields
351
- createSchema = makeMerge(createScalarSchema, fkSchema);
352
- }
353
- if (refineFuncName) {
354
- // export a schema without refinement for extensibility
355
- const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateWithoutRefineSchema`;
356
- writer.writeLine(`export const ${noRefineSchema} = ${createSchema};`);
357
- createSchema = `${refineFuncName}(${noRefineSchema})`;
358
- }
359
- writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateSchema = ${createSchema};`);
360
- ////////////////////////////////////////////////
361
- // 3. Update schema
362
- ////////////////////////////////////////////////
363
- let updateSchema = makePartial('baseSchema');
364
- if (fkSchema) {
365
- // export schema with only scalar fields
366
- const updateScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateScalarSchema`;
367
- writer.writeLine(`export const ${updateScalarSchema} = ${updateSchema};`);
368
- updateSchema = updateScalarSchema;
369
- // merge fk fields
370
- updateSchema = makeMerge(updateSchema, makePartial(fkSchema));
278
+ if (fkFields.length > 0) {
279
+ fkSchema = 'fkSchema';
280
+ writer.write(`const ${fkSchema} = z.object(`);
281
+ writer.inlineBlock(() => {
282
+ fkFields.forEach((field) => {
283
+ writer.writeLine(`${field.name}: ${(0, schema_gen_1.makeFieldSchema)(field)},`);
284
+ });
285
+ });
286
+ writer.writeLine(');');
287
+ }
288
+ // compile "@@validate" to ".refine"
289
+ const refinements = (0, schema_gen_1.makeValidationRefinements)(model);
290
+ let refineFuncName;
291
+ if (refinements.length > 0) {
292
+ refineFuncName = `refine${(0, upper_case_first_1.upperCaseFirst)(model.name)}`;
293
+ writer.writeLine(`export function ${refineFuncName}<T, D extends z.ZodTypeDef>(schema: z.ZodType<T, D, T>) { return schema${refinements.join('\n')}; }`);
294
+ }
295
+ ////////////////////////////////////////////////
296
+ // 1. Model schema
297
+ ////////////////////////////////////////////////
298
+ const fieldsWithoutDefault = scalarFields.filter((f) => !(0, schema_gen_1.getFieldSchemaDefault)(f));
299
+ // mark fields without default value as optional
300
+ let modelSchema = this.makePartial('baseSchema', fieldsWithoutDefault.length < scalarFields.length ? fieldsWithoutDefault.map((f) => f.name) : undefined);
301
+ // omit fields
302
+ const fieldsToOmit = scalarFields.filter((field) => (0, sdk_1.hasAttribute)(field, '@omit'));
303
+ if (fieldsToOmit.length > 0) {
304
+ modelSchema = this.makeOmit(modelSchema, fieldsToOmit.map((f) => f.name));
305
+ }
306
+ if (relationSchema) {
307
+ // export schema with only scalar fields
308
+ const modelScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}ScalarSchema`;
309
+ writer.writeLine(`export const ${modelScalarSchema} = ${modelSchema};`);
310
+ modelSchema = modelScalarSchema;
311
+ // merge relations
312
+ modelSchema = this.makeMerge(modelSchema, this.makePartial(relationSchema));
313
+ }
314
+ // refine
315
+ if (refineFuncName) {
316
+ const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}WithoutRefineSchema`;
317
+ writer.writeLine(`export const ${noRefineSchema} = ${modelSchema};`);
318
+ modelSchema = `${refineFuncName}(${noRefineSchema})`;
319
+ }
320
+ writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}Schema = ${modelSchema};`);
321
+ ////////////////////////////////////////////////
322
+ // 2. Prisma create & update
323
+ ////////////////////////////////////////////////
324
+ // schema for validating prisma create input (all fields optional)
325
+ let prismaCreateSchema = this.makePassthrough(this.makePartial('baseSchema'));
326
+ if (refineFuncName) {
327
+ prismaCreateSchema = `${refineFuncName}(${prismaCreateSchema})`;
328
+ }
329
+ writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}PrismaCreateSchema = ${prismaCreateSchema};`);
330
+ // schema for validating prisma update input (all fields optional)
331
+ // note numeric fields can be simple update or atomic operations
332
+ let prismaUpdateSchema = `z.object({
333
+ ${scalarFields
334
+ .map((field) => {
335
+ let fieldSchema = (0, schema_gen_1.makeFieldSchema)(field);
336
+ if (field.type.type === 'Int' || field.type.type === 'Float') {
337
+ fieldSchema = `z.union([${fieldSchema}, z.record(z.unknown())])`;
338
+ }
339
+ return `\t${field.name}: ${fieldSchema}`;
340
+ })
341
+ .join(',\n')}
342
+ })`;
343
+ prismaUpdateSchema = this.makePartial(prismaUpdateSchema);
344
+ if (refineFuncName) {
345
+ prismaUpdateSchema = `${refineFuncName}(${prismaUpdateSchema})`;
346
+ }
347
+ writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}PrismaUpdateSchema = ${prismaUpdateSchema};`);
348
+ ////////////////////////////////////////////////
349
+ // 3. Create schema
350
+ ////////////////////////////////////////////////
351
+ let createSchema = 'baseSchema';
352
+ const fieldsWithDefault = scalarFields.filter((field) => (0, sdk_1.hasAttribute)(field, '@default') || (0, sdk_1.hasAttribute)(field, '@updatedAt') || field.type.array);
353
+ if (fieldsWithDefault.length > 0) {
354
+ createSchema = this.makePartial(createSchema, fieldsWithDefault.map((f) => f.name));
355
+ }
356
+ if (fkSchema) {
357
+ // export schema with only scalar fields
358
+ const createScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateScalarSchema`;
359
+ writer.writeLine(`export const ${createScalarSchema} = ${createSchema};`);
360
+ // merge fk fields
361
+ createSchema = this.makeMerge(createScalarSchema, fkSchema);
362
+ }
363
+ if (refineFuncName) {
364
+ // export a schema without refinement for extensibility
365
+ const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateWithoutRefineSchema`;
366
+ writer.writeLine(`export const ${noRefineSchema} = ${createSchema};`);
367
+ createSchema = `${refineFuncName}(${noRefineSchema})`;
368
+ }
369
+ writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}CreateSchema = ${createSchema};`);
370
+ ////////////////////////////////////////////////
371
+ // 3. Update schema
372
+ ////////////////////////////////////////////////
373
+ let updateSchema = this.makePartial('baseSchema');
374
+ if (fkSchema) {
375
+ // export schema with only scalar fields
376
+ const updateScalarSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateScalarSchema`;
377
+ writer.writeLine(`export const ${updateScalarSchema} = ${updateSchema};`);
378
+ updateSchema = updateScalarSchema;
379
+ // merge fk fields
380
+ updateSchema = this.makeMerge(updateSchema, this.makePartial(fkSchema));
381
+ }
382
+ if (refineFuncName) {
383
+ // export a schema without refinement for extensibility
384
+ const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateWithoutRefineSchema`;
385
+ writer.writeLine(`export const ${noRefineSchema} = ${updateSchema};`);
386
+ updateSchema = `${refineFuncName}(${noRefineSchema})`;
387
+ }
388
+ writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateSchema = ${updateSchema};`);
389
+ });
390
+ return schemaName;
391
+ });
392
+ }
393
+ makePartial(schema, fields) {
394
+ if (fields) {
395
+ if (fields.length === 0) {
396
+ return schema;
371
397
  }
372
- if (refineFuncName) {
373
- // export a schema without refinement for extensibility
374
- const noRefineSchema = `${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateWithoutRefineSchema`;
375
- writer.writeLine(`export const ${noRefineSchema} = ${updateSchema};`);
376
- updateSchema = `${refineFuncName}(${noRefineSchema})`;
398
+ else {
399
+ return `${schema}.partial({
400
+ ${fields.map((f) => `${f}: true`).join(', ')}
401
+ })`;
377
402
  }
378
- writer.writeLine(`export const ${(0, upper_case_first_1.upperCaseFirst)(model.name)}UpdateSchema = ${updateSchema};`);
379
- });
380
- return schemaName;
381
- });
382
- }
383
- function makePartial(schema, fields) {
384
- if (fields) {
385
- if (fields.length === 0) {
386
- return schema;
387
403
  }
388
404
  else {
389
- return `${schema}.partial({
390
- ${fields.map((f) => `${f}: true`).join(', ')}
391
- })`;
405
+ return `${schema}.partial()`;
392
406
  }
393
407
  }
394
- else {
395
- return `${schema}.partial()`;
408
+ makeOmit(schema, fields) {
409
+ return `${schema}.omit({
410
+ ${fields.map((f) => `${f}: true`).join(', ')},
411
+ })`;
412
+ }
413
+ makeMerge(schema1, schema2) {
414
+ return `${schema1}.merge(${schema2})`;
415
+ }
416
+ makePassthrough(schema) {
417
+ return `${schema}.passthrough()`;
396
418
  }
397
419
  }
398
- function makeOmit(schema, fields) {
399
- return `${schema}.omit({
400
- ${fields.map((f) => `${f}: true`).join(', ')},
401
- })`;
402
- }
403
- function makeMerge(schema1, schema2) {
404
- return `${schema1}.merge(${schema2})`;
405
- }
406
- function makePassthrough(schema) {
407
- return `${schema}.passthrough()`;
408
- }
420
+ exports.ZodSchemaGenerator = ZodSchemaGenerator;
409
421
  //# sourceMappingURL=generator.js.map