@stryke/prisma-trpc-generator 0.13.48 → 0.13.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/rolldown_runtime.cjs +31 -1
- package/dist/_virtual/rolldown_runtime.mjs +32 -1
- package/dist/config.cjs +50 -1
- package/dist/config.mjs +49 -1
- package/dist/config.mjs.map +1 -1
- package/dist/generator.cjs +1 -1
- package/dist/generator.mjs +3 -1
- package/dist/helpers.cjs +281 -32
- package/dist/helpers.mjs +271 -32
- package/dist/helpers.mjs.map +1 -1
- package/dist/index.cjs +26 -1
- package/dist/index.mjs +27 -1
- package/dist/index.mjs.map +1 -1
- package/dist/packages/env/src/get-env-paths.cjs +87 -1
- package/dist/packages/env/src/get-env-paths.mjs +84 -1
- package/dist/packages/env/src/get-env-paths.mjs.map +1 -1
- package/dist/packages/string-format/src/acronyms.cjs +408 -1
- package/dist/packages/string-format/src/acronyms.mjs +407 -1
- package/dist/packages/string-format/src/acronyms.mjs.map +1 -1
- package/dist/packages/string-format/src/articles.cjs +10 -1
- package/dist/packages/string-format/src/articles.mjs +9 -1
- package/dist/packages/string-format/src/articles.mjs.map +1 -1
- package/dist/packages/string-format/src/combine.cjs +15 -1
- package/dist/packages/string-format/src/combine.mjs +14 -1
- package/dist/packages/string-format/src/combine.mjs.map +1 -1
- package/dist/packages/string-format/src/conjunctions.cjs +32 -1
- package/dist/packages/string-format/src/conjunctions.mjs +31 -1
- package/dist/packages/string-format/src/conjunctions.mjs.map +1 -1
- package/dist/packages/string-format/src/decamelize.cjs +14 -1
- package/dist/packages/string-format/src/decamelize.mjs +13 -1
- package/dist/packages/string-format/src/decamelize.mjs.map +1 -1
- package/dist/packages/string-format/src/format-special-cases.cjs +33 -1
- package/dist/packages/string-format/src/format-special-cases.mjs +33 -1
- package/dist/packages/string-format/src/format-special-cases.mjs.map +1 -1
- package/dist/packages/string-format/src/lower-case-first.cjs +17 -1
- package/dist/packages/string-format/src/lower-case-first.mjs +16 -1
- package/dist/packages/string-format/src/lower-case-first.mjs.map +1 -1
- package/dist/packages/string-format/src/prepositions.cjs +68 -1
- package/dist/packages/string-format/src/prepositions.mjs +67 -1
- package/dist/packages/string-format/src/prepositions.mjs.map +1 -1
- package/dist/packages/string-format/src/special-cases.cjs +53 -1
- package/dist/packages/string-format/src/special-cases.mjs +52 -1
- package/dist/packages/string-format/src/special-cases.mjs.map +1 -1
- package/dist/packages/string-format/src/title-case.cjs +19 -1
- package/dist/packages/string-format/src/title-case.mjs +19 -1
- package/dist/packages/string-format/src/title-case.mjs.map +1 -1
- package/dist/packages/string-format/src/upper-case-first.cjs +17 -1
- package/dist/packages/string-format/src/upper-case-first.mjs +16 -1
- package/dist/packages/string-format/src/upper-case-first.mjs.map +1 -1
- package/dist/prisma-generator.cjs +185 -8
- package/dist/prisma-generator.mjs +184 -8
- package/dist/prisma-generator.mjs.map +1 -1
- package/dist/project.cjs +15 -1
- package/dist/project.mjs +14 -1
- package/dist/project.mjs.map +1 -1
- package/dist/utils/format-file.cjs +25 -1
- package/dist/utils/format-file.mjs +23 -1
- package/dist/utils/format-file.mjs.map +1 -1
- package/dist/utils/get-jiti.cjs +21 -1
- package/dist/utils/get-jiti.mjs +20 -1
- package/dist/utils/get-jiti.mjs.map +1 -1
- package/dist/utils/get-prisma-internals.cjs +13 -1
- package/dist/utils/get-prisma-internals.mjs +12 -1
- package/dist/utils/get-prisma-internals.mjs.map +1 -1
- package/dist/utils/write-file-safely.cjs +32 -2
- package/dist/utils/write-file-safely.mjs +29 -2
- package/dist/utils/write-file-safely.mjs.map +1 -1
- package/dist/zod/aggregate-helpers.cjs +70 -1
- package/dist/zod/aggregate-helpers.mjs +67 -1
- package/dist/zod/aggregate-helpers.mjs.map +1 -1
- package/dist/zod/comments-helpers.cjs +77 -1
- package/dist/zod/comments-helpers.mjs +75 -1
- package/dist/zod/comments-helpers.mjs.map +1 -1
- package/dist/zod/docs-helpers.cjs +23 -3
- package/dist/zod/docs-helpers.mjs +20 -3
- package/dist/zod/docs-helpers.mjs.map +1 -1
- package/dist/zod/generator-helpers.cjs +34 -1
- package/dist/zod/generator-helpers.mjs +31 -1
- package/dist/zod/generator-helpers.mjs.map +1 -1
- package/dist/zod/helpers.cjs +26 -1
- package/dist/zod/helpers.mjs +26 -1
- package/dist/zod/helpers.mjs.map +1 -1
- package/dist/zod/include-helpers.cjs +69 -1
- package/dist/zod/include-helpers.mjs +69 -1
- package/dist/zod/include-helpers.mjs.map +1 -1
- package/dist/zod/model-helpers.cjs +244 -1
- package/dist/zod/model-helpers.mjs +236 -1
- package/dist/zod/model-helpers.mjs.map +1 -1
- package/dist/zod/modelArgs-helpers.cjs +56 -1
- package/dist/zod/modelArgs-helpers.mjs +56 -1
- package/dist/zod/modelArgs-helpers.mjs.map +1 -1
- package/dist/zod/mongodb-helpers.cjs +49 -1
- package/dist/zod/mongodb-helpers.mjs +48 -1
- package/dist/zod/mongodb-helpers.mjs.map +1 -1
- package/dist/zod/select-helpers.cjs +128 -1
- package/dist/zod/select-helpers.mjs +128 -1
- package/dist/zod/select-helpers.mjs.map +1 -1
- package/dist/zod/transformer.cjs +434 -19
- package/dist/zod/transformer.mjs +432 -19
- package/dist/zod/transformer.mjs.map +1 -1
- package/dist/zod/whereUniqueInput-helpers.cjs +17 -1
- package/dist/zod/whereUniqueInput-helpers.mjs +16 -1
- package/dist/zod/whereUniqueInput-helpers.mjs.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1,244 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_lower_case_first = require('../packages/string-format/src/lower-case-first.cjs');
|
|
3
|
+
const require_get_prisma_internals = require('../utils/get-prisma-internals.cjs');
|
|
4
|
+
const require_docs_helpers = require('./docs-helpers.cjs');
|
|
5
|
+
let node_path = require("node:path");
|
|
6
|
+
node_path = require_rolldown_runtime.__toESM(node_path);
|
|
7
|
+
let ts_morph = require("ts-morph");
|
|
8
|
+
|
|
9
|
+
//#region src/zod/model-helpers.ts
|
|
10
|
+
function checkModelHasModelRelation(model) {
|
|
11
|
+
const { fields: modelFields } = model;
|
|
12
|
+
for (const modelField of modelFields) if (checkIsModelRelationField(modelField)) return true;
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
function checkModelHasManyModelRelation(model) {
|
|
16
|
+
const { fields: modelFields } = model;
|
|
17
|
+
for (const modelField of modelFields) if (checkIsManyModelRelationField(modelField)) return true;
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
function checkIsModelRelationField(modelField) {
|
|
21
|
+
const { kind, relationName } = modelField;
|
|
22
|
+
return kind === "object" && !!relationName;
|
|
23
|
+
}
|
|
24
|
+
function checkIsManyModelRelationField(modelField) {
|
|
25
|
+
return checkIsModelRelationField(modelField) && modelField.isList;
|
|
26
|
+
}
|
|
27
|
+
function findModelByName(models, modelName) {
|
|
28
|
+
return models.find(({ name }) => name === modelName);
|
|
29
|
+
}
|
|
30
|
+
const writeArray = (writer, array, newLine = true) => array.forEach((line) => writer.write(line).conditionalNewLine(newLine));
|
|
31
|
+
const useModelNames = ({ modelCase, modelSuffix, relationModel }) => {
|
|
32
|
+
const formatModelName = (name, prefix = "") => {
|
|
33
|
+
if (modelCase === "camelCase") name = name.slice(0, 1).toLowerCase() + name.slice(1);
|
|
34
|
+
return `${prefix}${name}${modelSuffix}`;
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
modelName: (name) => formatModelName(name, relationModel === "default" ? "_" : ""),
|
|
38
|
+
relatedModelName: (name) => formatModelName(relationModel === "default" ? name.toString() : `Related${name.toString()}`)
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const dotSlash = (input) => {
|
|
42
|
+
const converted = input.replace(/^\\\\\?\\/, "").replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
43
|
+
if (converted.includes(`/node_modules/`)) return converted.split(`/node_modules/`).slice(-1)[0];
|
|
44
|
+
if (converted.startsWith(`../`)) return converted;
|
|
45
|
+
return `./${converted}`;
|
|
46
|
+
};
|
|
47
|
+
const chunk = (input, size) => {
|
|
48
|
+
return input.reduce((arr, item, idx) => {
|
|
49
|
+
return idx % size === 0 ? [...arr, [item]] : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];
|
|
50
|
+
}, []);
|
|
51
|
+
};
|
|
52
|
+
const needsRelatedModel = (model, config) => model.fields.some((field) => field.kind === "object") && config.relationModel !== false;
|
|
53
|
+
const writeImportsForModel = async (model, sourceFile, config, options) => {
|
|
54
|
+
const outputPath = (await require_get_prisma_internals.getPrismaInternals()).parseEnvValue(options.generator.output);
|
|
55
|
+
const { relatedModelName } = useModelNames(config);
|
|
56
|
+
const importList = [{
|
|
57
|
+
kind: ts_morph.StructureKind.ImportDeclaration,
|
|
58
|
+
namespaceImport: "z",
|
|
59
|
+
moduleSpecifier: "zod"
|
|
60
|
+
}];
|
|
61
|
+
if (config.imports) importList.push({
|
|
62
|
+
kind: ts_morph.StructureKind.ImportDeclaration,
|
|
63
|
+
namespaceImport: "imports",
|
|
64
|
+
moduleSpecifier: dotSlash(node_path.default.relative(outputPath, node_path.default.resolve(node_path.default.dirname(options.schemaPath), config.imports)))
|
|
65
|
+
});
|
|
66
|
+
if (config.useDecimalJs && model.fields.some((f) => f.type === "Decimal")) importList.push({
|
|
67
|
+
kind: ts_morph.StructureKind.ImportDeclaration,
|
|
68
|
+
namedImports: ["Decimal"],
|
|
69
|
+
moduleSpecifier: "decimal.js"
|
|
70
|
+
});
|
|
71
|
+
const enumFields = model.fields.filter((f) => f.kind === "enum");
|
|
72
|
+
const relationFields = model.fields.filter((f) => f.kind === "object");
|
|
73
|
+
const clientPath = options.otherGenerators.find((each) => each.provider.value === "prisma-client-js").output.value;
|
|
74
|
+
const relativePath = node_path.default.relative(outputPath, clientPath);
|
|
75
|
+
if (enumFields.length > 0) importList.push({
|
|
76
|
+
kind: ts_morph.StructureKind.ImportDeclaration,
|
|
77
|
+
isTypeOnly: enumFields.length === 0,
|
|
78
|
+
moduleSpecifier: dotSlash(relativePath),
|
|
79
|
+
namedImports: enumFields.map((f) => f.type)
|
|
80
|
+
});
|
|
81
|
+
if (config.relationModel !== false && relationFields.length > 0) {
|
|
82
|
+
const filteredFields = relationFields.filter((f) => f.type !== model.name);
|
|
83
|
+
if (filteredFields.length > 0) importList.push({
|
|
84
|
+
kind: ts_morph.StructureKind.ImportDeclaration,
|
|
85
|
+
moduleSpecifier: "./index",
|
|
86
|
+
namedImports: Array.from(new Set(filteredFields.flatMap((f) => [`${f.type}`, relatedModelName(f.type)])))
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
sourceFile.addImportDeclarations(importList);
|
|
90
|
+
};
|
|
91
|
+
const computeCustomSchema = (docString) => {
|
|
92
|
+
return require_docs_helpers.getZodDocElements(docString).find((modifier) => modifier.startsWith("custom("))?.slice(7).slice(0, -1);
|
|
93
|
+
};
|
|
94
|
+
const computeModifiers = (docString) => {
|
|
95
|
+
return require_docs_helpers.getZodDocElements(docString).filter((each) => !each.startsWith("custom("));
|
|
96
|
+
};
|
|
97
|
+
const getZodConstructor = (field, getRelatedModelName = (name) => name.toString()) => {
|
|
98
|
+
let zodType = "z.unknown()";
|
|
99
|
+
const extraModifiers = [""];
|
|
100
|
+
if (field.kind === "scalar") switch (field.type) {
|
|
101
|
+
case "String":
|
|
102
|
+
zodType = "z.string()";
|
|
103
|
+
break;
|
|
104
|
+
case "Int":
|
|
105
|
+
zodType = "z.number()";
|
|
106
|
+
extraModifiers.push("int()");
|
|
107
|
+
break;
|
|
108
|
+
case "BigInt":
|
|
109
|
+
zodType = "z.bigint()";
|
|
110
|
+
break;
|
|
111
|
+
case "DateTime":
|
|
112
|
+
zodType = "z.date()";
|
|
113
|
+
break;
|
|
114
|
+
case "Float":
|
|
115
|
+
zodType = "z.number()";
|
|
116
|
+
break;
|
|
117
|
+
case "Decimal":
|
|
118
|
+
zodType = "z.number()";
|
|
119
|
+
break;
|
|
120
|
+
case "Json":
|
|
121
|
+
zodType = "jsonSchema";
|
|
122
|
+
break;
|
|
123
|
+
case "Boolean":
|
|
124
|
+
zodType = "z.boolean()";
|
|
125
|
+
break;
|
|
126
|
+
case "Bytes":
|
|
127
|
+
zodType = "z.unknown()";
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
else if (field.kind === "enum") zodType = `z.nativeEnum(${field.type})`;
|
|
131
|
+
else if (field.kind === "object") zodType = getRelatedModelName(field.type);
|
|
132
|
+
if (field.isList) extraModifiers.push("array()");
|
|
133
|
+
if (field.documentation) {
|
|
134
|
+
zodType = computeCustomSchema(field.documentation) ?? zodType;
|
|
135
|
+
extraModifiers.push(...computeModifiers(field.documentation));
|
|
136
|
+
}
|
|
137
|
+
if (!field.isRequired && field.type !== "Json") extraModifiers.push("nullish()");
|
|
138
|
+
return `${zodType}${extraModifiers.join(".")}`;
|
|
139
|
+
};
|
|
140
|
+
const writeTypeSpecificSchemas = (model, sourceFile, config) => {
|
|
141
|
+
if (model.fields.some((f) => f.type === "Json")) sourceFile.addStatements((writer) => {
|
|
142
|
+
writer.newLine();
|
|
143
|
+
writeArray(writer, [
|
|
144
|
+
"// Helper schema for JSON fields",
|
|
145
|
+
`type Literal = boolean | number | string${config.prismaJsonNullability ? "" : "| null"}`,
|
|
146
|
+
"type Json = Literal | { [key: string]: Json } | Json[]",
|
|
147
|
+
`const literalSchema = z.union([z.string(), z.number(), z.boolean()${config.prismaJsonNullability ? "" : ", z.null()"}])`,
|
|
148
|
+
"const jsonSchema: z.ZodSchema<Json> = z.lazy(() => z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]))"
|
|
149
|
+
]);
|
|
150
|
+
});
|
|
151
|
+
if (config.useDecimalJs && model.fields.some((f) => f.type === "Decimal")) sourceFile.addStatements((writer) => {
|
|
152
|
+
writer.newLine();
|
|
153
|
+
writeArray(writer, [
|
|
154
|
+
"// Helper schema for Decimal fields",
|
|
155
|
+
"z",
|
|
156
|
+
".instanceof(Decimal)",
|
|
157
|
+
".or(z.string())",
|
|
158
|
+
".or(z.number())",
|
|
159
|
+
".refine((value) => {",
|
|
160
|
+
" try {",
|
|
161
|
+
" return new Decimal(value);",
|
|
162
|
+
" } catch (error) {",
|
|
163
|
+
" return false;",
|
|
164
|
+
" }",
|
|
165
|
+
"})",
|
|
166
|
+
".transform((value) => new Decimal(value));"
|
|
167
|
+
]);
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
const generateSchemaForModel = (model, sourceFile, config) => {
|
|
171
|
+
const { modelName } = useModelNames(config);
|
|
172
|
+
sourceFile.addVariableStatement({
|
|
173
|
+
declarationKind: ts_morph.VariableDeclarationKind.Const,
|
|
174
|
+
isExported: true,
|
|
175
|
+
leadingTrivia: (writer) => writer.blankLineIfLastNot(),
|
|
176
|
+
declarations: [{
|
|
177
|
+
name: modelName(model.name),
|
|
178
|
+
initializer(writer) {
|
|
179
|
+
writer.write("z.object(").inlineBlock(() => {
|
|
180
|
+
model.fields.filter((f) => f.kind !== "object").forEach((field) => {
|
|
181
|
+
writeArray(writer, require_docs_helpers.getJSDocs(field.documentation));
|
|
182
|
+
writer.write(`${field.name}: ${getZodConstructor(field)}`).write(",").newLine();
|
|
183
|
+
});
|
|
184
|
+
}).write(")");
|
|
185
|
+
}
|
|
186
|
+
}]
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
const generateRelatedSchemaForModel = (model, sourceFile, config) => {
|
|
190
|
+
const { modelName, relatedModelName } = useModelNames(config);
|
|
191
|
+
const relationFields = model.fields.filter((f) => f.kind === "object");
|
|
192
|
+
sourceFile.addInterface({
|
|
193
|
+
name: `${model.name}`,
|
|
194
|
+
isExported: true,
|
|
195
|
+
extends: [`z.infer<typeof ${modelName(model.name)}>`],
|
|
196
|
+
properties: relationFields.map((f) => ({
|
|
197
|
+
hasQuestionToken: !f.isRequired,
|
|
198
|
+
name: f.name,
|
|
199
|
+
type: `${f.type}${f.isList ? "[]" : ""}${!f.isRequired ? " | null" : ""}`
|
|
200
|
+
}))
|
|
201
|
+
});
|
|
202
|
+
sourceFile.addStatements((writer) => writeArray(writer, [
|
|
203
|
+
"",
|
|
204
|
+
"/**",
|
|
205
|
+
` * ${relatedModelName(model.name)} contains all relations on your model in addition to the scalars`,
|
|
206
|
+
" *",
|
|
207
|
+
" * NOTE: Lazy required in case of potential circular dependencies within schema",
|
|
208
|
+
" */"
|
|
209
|
+
]));
|
|
210
|
+
sourceFile.addVariableStatement({
|
|
211
|
+
declarationKind: ts_morph.VariableDeclarationKind.Const,
|
|
212
|
+
isExported: true,
|
|
213
|
+
declarations: [{
|
|
214
|
+
name: relatedModelName(model.name),
|
|
215
|
+
type: `z.ZodSchema<${model.name}>`,
|
|
216
|
+
initializer(writer) {
|
|
217
|
+
writer.write(`z.lazy(() => ${modelName(model.name)}.extend(`).inlineBlock(() => {
|
|
218
|
+
relationFields.forEach((field) => {
|
|
219
|
+
writeArray(writer, require_docs_helpers.getJSDocs(field.documentation));
|
|
220
|
+
writer.write(`${field.name}: ${getZodConstructor(field, relatedModelName)}`).write(",").newLine();
|
|
221
|
+
});
|
|
222
|
+
}).write("))");
|
|
223
|
+
}
|
|
224
|
+
}]
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
const populateModelFile = async (model, sourceFile, config, options) => {
|
|
228
|
+
await writeImportsForModel(model, sourceFile, config, options);
|
|
229
|
+
writeTypeSpecificSchemas(model, sourceFile, config);
|
|
230
|
+
generateSchemaForModel(model, sourceFile, config);
|
|
231
|
+
if (needsRelatedModel(model, config)) generateRelatedSchemaForModel(model, sourceFile, config);
|
|
232
|
+
};
|
|
233
|
+
const generateBarrelFile = (models, indexFile) => {
|
|
234
|
+
models.forEach((model) => indexFile.addExportDeclaration({ moduleSpecifier: `./${require_lower_case_first.lowerCaseFirst(model.name)}.schema` }));
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
//#endregion
|
|
238
|
+
exports.checkIsModelRelationField = checkIsModelRelationField;
|
|
239
|
+
exports.checkModelHasManyModelRelation = checkModelHasManyModelRelation;
|
|
240
|
+
exports.checkModelHasModelRelation = checkModelHasModelRelation;
|
|
241
|
+
exports.chunk = chunk;
|
|
242
|
+
exports.findModelByName = findModelByName;
|
|
243
|
+
exports.generateBarrelFile = generateBarrelFile;
|
|
244
|
+
exports.populateModelFile = populateModelFile;
|
|
@@ -1,2 +1,237 @@
|
|
|
1
|
-
import{lowerCaseFirst
|
|
1
|
+
import { lowerCaseFirst } from "../packages/string-format/src/lower-case-first.mjs";
|
|
2
|
+
import { getPrismaInternals } from "../utils/get-prisma-internals.mjs";
|
|
3
|
+
import { getJSDocs, getZodDocElements } from "./docs-helpers.mjs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { StructureKind, VariableDeclarationKind } from "ts-morph";
|
|
6
|
+
|
|
7
|
+
//#region src/zod/model-helpers.ts
|
|
8
|
+
function checkModelHasModelRelation(model) {
|
|
9
|
+
const { fields: modelFields } = model;
|
|
10
|
+
for (const modelField of modelFields) if (checkIsModelRelationField(modelField)) return true;
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
function checkModelHasManyModelRelation(model) {
|
|
14
|
+
const { fields: modelFields } = model;
|
|
15
|
+
for (const modelField of modelFields) if (checkIsManyModelRelationField(modelField)) return true;
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
function checkIsModelRelationField(modelField) {
|
|
19
|
+
const { kind, relationName } = modelField;
|
|
20
|
+
return kind === "object" && !!relationName;
|
|
21
|
+
}
|
|
22
|
+
function checkIsManyModelRelationField(modelField) {
|
|
23
|
+
return checkIsModelRelationField(modelField) && modelField.isList;
|
|
24
|
+
}
|
|
25
|
+
function findModelByName(models, modelName) {
|
|
26
|
+
return models.find(({ name }) => name === modelName);
|
|
27
|
+
}
|
|
28
|
+
const writeArray = (writer, array, newLine = true) => array.forEach((line) => writer.write(line).conditionalNewLine(newLine));
|
|
29
|
+
const useModelNames = ({ modelCase, modelSuffix, relationModel }) => {
|
|
30
|
+
const formatModelName = (name, prefix = "") => {
|
|
31
|
+
if (modelCase === "camelCase") name = name.slice(0, 1).toLowerCase() + name.slice(1);
|
|
32
|
+
return `${prefix}${name}${modelSuffix}`;
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
modelName: (name) => formatModelName(name, relationModel === "default" ? "_" : ""),
|
|
36
|
+
relatedModelName: (name) => formatModelName(relationModel === "default" ? name.toString() : `Related${name.toString()}`)
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const dotSlash = (input) => {
|
|
40
|
+
const converted = input.replace(/^\\\\\?\\/, "").replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
41
|
+
if (converted.includes(`/node_modules/`)) return converted.split(`/node_modules/`).slice(-1)[0];
|
|
42
|
+
if (converted.startsWith(`../`)) return converted;
|
|
43
|
+
return `./${converted}`;
|
|
44
|
+
};
|
|
45
|
+
const chunk = (input, size) => {
|
|
46
|
+
return input.reduce((arr, item, idx) => {
|
|
47
|
+
return idx % size === 0 ? [...arr, [item]] : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];
|
|
48
|
+
}, []);
|
|
49
|
+
};
|
|
50
|
+
const needsRelatedModel = (model, config) => model.fields.some((field) => field.kind === "object") && config.relationModel !== false;
|
|
51
|
+
const writeImportsForModel = async (model, sourceFile, config, options) => {
|
|
52
|
+
const outputPath = (await getPrismaInternals()).parseEnvValue(options.generator.output);
|
|
53
|
+
const { relatedModelName } = useModelNames(config);
|
|
54
|
+
const importList = [{
|
|
55
|
+
kind: StructureKind.ImportDeclaration,
|
|
56
|
+
namespaceImport: "z",
|
|
57
|
+
moduleSpecifier: "zod"
|
|
58
|
+
}];
|
|
59
|
+
if (config.imports) importList.push({
|
|
60
|
+
kind: StructureKind.ImportDeclaration,
|
|
61
|
+
namespaceImport: "imports",
|
|
62
|
+
moduleSpecifier: dotSlash(path.relative(outputPath, path.resolve(path.dirname(options.schemaPath), config.imports)))
|
|
63
|
+
});
|
|
64
|
+
if (config.useDecimalJs && model.fields.some((f) => f.type === "Decimal")) importList.push({
|
|
65
|
+
kind: StructureKind.ImportDeclaration,
|
|
66
|
+
namedImports: ["Decimal"],
|
|
67
|
+
moduleSpecifier: "decimal.js"
|
|
68
|
+
});
|
|
69
|
+
const enumFields = model.fields.filter((f) => f.kind === "enum");
|
|
70
|
+
const relationFields = model.fields.filter((f) => f.kind === "object");
|
|
71
|
+
const clientPath = options.otherGenerators.find((each) => each.provider.value === "prisma-client-js").output.value;
|
|
72
|
+
const relativePath = path.relative(outputPath, clientPath);
|
|
73
|
+
if (enumFields.length > 0) importList.push({
|
|
74
|
+
kind: StructureKind.ImportDeclaration,
|
|
75
|
+
isTypeOnly: enumFields.length === 0,
|
|
76
|
+
moduleSpecifier: dotSlash(relativePath),
|
|
77
|
+
namedImports: enumFields.map((f) => f.type)
|
|
78
|
+
});
|
|
79
|
+
if (config.relationModel !== false && relationFields.length > 0) {
|
|
80
|
+
const filteredFields = relationFields.filter((f) => f.type !== model.name);
|
|
81
|
+
if (filteredFields.length > 0) importList.push({
|
|
82
|
+
kind: StructureKind.ImportDeclaration,
|
|
83
|
+
moduleSpecifier: "./index",
|
|
84
|
+
namedImports: Array.from(new Set(filteredFields.flatMap((f) => [`${f.type}`, relatedModelName(f.type)])))
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
sourceFile.addImportDeclarations(importList);
|
|
88
|
+
};
|
|
89
|
+
const computeCustomSchema = (docString) => {
|
|
90
|
+
return getZodDocElements(docString).find((modifier) => modifier.startsWith("custom("))?.slice(7).slice(0, -1);
|
|
91
|
+
};
|
|
92
|
+
const computeModifiers = (docString) => {
|
|
93
|
+
return getZodDocElements(docString).filter((each) => !each.startsWith("custom("));
|
|
94
|
+
};
|
|
95
|
+
const getZodConstructor = (field, getRelatedModelName = (name) => name.toString()) => {
|
|
96
|
+
let zodType = "z.unknown()";
|
|
97
|
+
const extraModifiers = [""];
|
|
98
|
+
if (field.kind === "scalar") switch (field.type) {
|
|
99
|
+
case "String":
|
|
100
|
+
zodType = "z.string()";
|
|
101
|
+
break;
|
|
102
|
+
case "Int":
|
|
103
|
+
zodType = "z.number()";
|
|
104
|
+
extraModifiers.push("int()");
|
|
105
|
+
break;
|
|
106
|
+
case "BigInt":
|
|
107
|
+
zodType = "z.bigint()";
|
|
108
|
+
break;
|
|
109
|
+
case "DateTime":
|
|
110
|
+
zodType = "z.date()";
|
|
111
|
+
break;
|
|
112
|
+
case "Float":
|
|
113
|
+
zodType = "z.number()";
|
|
114
|
+
break;
|
|
115
|
+
case "Decimal":
|
|
116
|
+
zodType = "z.number()";
|
|
117
|
+
break;
|
|
118
|
+
case "Json":
|
|
119
|
+
zodType = "jsonSchema";
|
|
120
|
+
break;
|
|
121
|
+
case "Boolean":
|
|
122
|
+
zodType = "z.boolean()";
|
|
123
|
+
break;
|
|
124
|
+
case "Bytes":
|
|
125
|
+
zodType = "z.unknown()";
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
else if (field.kind === "enum") zodType = `z.nativeEnum(${field.type})`;
|
|
129
|
+
else if (field.kind === "object") zodType = getRelatedModelName(field.type);
|
|
130
|
+
if (field.isList) extraModifiers.push("array()");
|
|
131
|
+
if (field.documentation) {
|
|
132
|
+
zodType = computeCustomSchema(field.documentation) ?? zodType;
|
|
133
|
+
extraModifiers.push(...computeModifiers(field.documentation));
|
|
134
|
+
}
|
|
135
|
+
if (!field.isRequired && field.type !== "Json") extraModifiers.push("nullish()");
|
|
136
|
+
return `${zodType}${extraModifiers.join(".")}`;
|
|
137
|
+
};
|
|
138
|
+
const writeTypeSpecificSchemas = (model, sourceFile, config) => {
|
|
139
|
+
if (model.fields.some((f) => f.type === "Json")) sourceFile.addStatements((writer) => {
|
|
140
|
+
writer.newLine();
|
|
141
|
+
writeArray(writer, [
|
|
142
|
+
"// Helper schema for JSON fields",
|
|
143
|
+
`type Literal = boolean | number | string${config.prismaJsonNullability ? "" : "| null"}`,
|
|
144
|
+
"type Json = Literal | { [key: string]: Json } | Json[]",
|
|
145
|
+
`const literalSchema = z.union([z.string(), z.number(), z.boolean()${config.prismaJsonNullability ? "" : ", z.null()"}])`,
|
|
146
|
+
"const jsonSchema: z.ZodSchema<Json> = z.lazy(() => z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]))"
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
if (config.useDecimalJs && model.fields.some((f) => f.type === "Decimal")) sourceFile.addStatements((writer) => {
|
|
150
|
+
writer.newLine();
|
|
151
|
+
writeArray(writer, [
|
|
152
|
+
"// Helper schema for Decimal fields",
|
|
153
|
+
"z",
|
|
154
|
+
".instanceof(Decimal)",
|
|
155
|
+
".or(z.string())",
|
|
156
|
+
".or(z.number())",
|
|
157
|
+
".refine((value) => {",
|
|
158
|
+
" try {",
|
|
159
|
+
" return new Decimal(value);",
|
|
160
|
+
" } catch (error) {",
|
|
161
|
+
" return false;",
|
|
162
|
+
" }",
|
|
163
|
+
"})",
|
|
164
|
+
".transform((value) => new Decimal(value));"
|
|
165
|
+
]);
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
const generateSchemaForModel = (model, sourceFile, config) => {
|
|
169
|
+
const { modelName } = useModelNames(config);
|
|
170
|
+
sourceFile.addVariableStatement({
|
|
171
|
+
declarationKind: VariableDeclarationKind.Const,
|
|
172
|
+
isExported: true,
|
|
173
|
+
leadingTrivia: (writer) => writer.blankLineIfLastNot(),
|
|
174
|
+
declarations: [{
|
|
175
|
+
name: modelName(model.name),
|
|
176
|
+
initializer(writer) {
|
|
177
|
+
writer.write("z.object(").inlineBlock(() => {
|
|
178
|
+
model.fields.filter((f) => f.kind !== "object").forEach((field) => {
|
|
179
|
+
writeArray(writer, getJSDocs(field.documentation));
|
|
180
|
+
writer.write(`${field.name}: ${getZodConstructor(field)}`).write(",").newLine();
|
|
181
|
+
});
|
|
182
|
+
}).write(")");
|
|
183
|
+
}
|
|
184
|
+
}]
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
const generateRelatedSchemaForModel = (model, sourceFile, config) => {
|
|
188
|
+
const { modelName, relatedModelName } = useModelNames(config);
|
|
189
|
+
const relationFields = model.fields.filter((f) => f.kind === "object");
|
|
190
|
+
sourceFile.addInterface({
|
|
191
|
+
name: `${model.name}`,
|
|
192
|
+
isExported: true,
|
|
193
|
+
extends: [`z.infer<typeof ${modelName(model.name)}>`],
|
|
194
|
+
properties: relationFields.map((f) => ({
|
|
195
|
+
hasQuestionToken: !f.isRequired,
|
|
196
|
+
name: f.name,
|
|
197
|
+
type: `${f.type}${f.isList ? "[]" : ""}${!f.isRequired ? " | null" : ""}`
|
|
198
|
+
}))
|
|
199
|
+
});
|
|
200
|
+
sourceFile.addStatements((writer) => writeArray(writer, [
|
|
201
|
+
"",
|
|
202
|
+
"/**",
|
|
203
|
+
` * ${relatedModelName(model.name)} contains all relations on your model in addition to the scalars`,
|
|
204
|
+
" *",
|
|
205
|
+
" * NOTE: Lazy required in case of potential circular dependencies within schema",
|
|
206
|
+
" */"
|
|
207
|
+
]));
|
|
208
|
+
sourceFile.addVariableStatement({
|
|
209
|
+
declarationKind: VariableDeclarationKind.Const,
|
|
210
|
+
isExported: true,
|
|
211
|
+
declarations: [{
|
|
212
|
+
name: relatedModelName(model.name),
|
|
213
|
+
type: `z.ZodSchema<${model.name}>`,
|
|
214
|
+
initializer(writer) {
|
|
215
|
+
writer.write(`z.lazy(() => ${modelName(model.name)}.extend(`).inlineBlock(() => {
|
|
216
|
+
relationFields.forEach((field) => {
|
|
217
|
+
writeArray(writer, getJSDocs(field.documentation));
|
|
218
|
+
writer.write(`${field.name}: ${getZodConstructor(field, relatedModelName)}`).write(",").newLine();
|
|
219
|
+
});
|
|
220
|
+
}).write("))");
|
|
221
|
+
}
|
|
222
|
+
}]
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
const populateModelFile = async (model, sourceFile, config, options) => {
|
|
226
|
+
await writeImportsForModel(model, sourceFile, config, options);
|
|
227
|
+
writeTypeSpecificSchemas(model, sourceFile, config);
|
|
228
|
+
generateSchemaForModel(model, sourceFile, config);
|
|
229
|
+
if (needsRelatedModel(model, config)) generateRelatedSchemaForModel(model, sourceFile, config);
|
|
230
|
+
};
|
|
231
|
+
const generateBarrelFile = (models, indexFile) => {
|
|
232
|
+
models.forEach((model) => indexFile.addExportDeclaration({ moduleSpecifier: `./${lowerCaseFirst(model.name)}.schema` }));
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
//#endregion
|
|
236
|
+
export { checkIsModelRelationField, checkModelHasManyModelRelation, checkModelHasModelRelation, chunk, findModelByName, generateBarrelFile, populateModelFile };
|
|
2
237
|
//# sourceMappingURL=model-helpers.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-helpers.mjs","names":["importList: ImportDeclarationStructure[]","extraModifiers: string[]"],"sources":["../../src/zod/model-helpers.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 License, and is\n free for commercial and private use. For more information, please visit\n our licensing page.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://stormsoftware.com/projects/stryke/docs\n Contact: https://stormsoftware.com/contact\n License: https://stormsoftware.com/projects/stryke/license\n\n ------------------------------------------------------------------- */\n\nimport type {\n DMMF,\n EnvValue,\n GeneratorOptions\n} from \"@prisma/generator-helper\";\nimport { lowerCaseFirst } from \"@stryke/string-format/lower-case-first\";\nimport path from \"node:path\";\nimport type {\n CodeBlockWriter,\n ImportDeclarationStructure,\n SourceFile\n} from \"ts-morph\";\nimport { StructureKind, VariableDeclarationKind } from \"ts-morph\";\nimport type { Config } from \"../config\";\nimport { getPrismaInternals } from \"../utils/get-prisma-internals\";\nimport { getJSDocs, getZodDocElements } from \"./docs-helpers\";\n\nexport function checkModelHasModelRelation(model: DMMF.Model) {\n const { fields: modelFields } = model;\n for (const modelField of modelFields) {\n const isRelationField = checkIsModelRelationField(modelField);\n if (isRelationField) {\n return true;\n }\n }\n return false;\n}\n\nexport function checkModelHasManyModelRelation(model: DMMF.Model) {\n const { fields: modelFields } = model;\n for (const modelField of modelFields) {\n const isManyRelationField = checkIsManyModelRelationField(modelField);\n if (isManyRelationField) {\n return true;\n }\n }\n return false;\n}\n\nexport function checkIsModelRelationField(modelField: DMMF.Field) {\n const { kind, relationName } = modelField;\n\n return kind === \"object\" && !!relationName;\n}\n\nexport function checkIsManyModelRelationField(modelField: DMMF.Field) {\n return checkIsModelRelationField(modelField) && modelField.isList;\n}\n\nexport function findModelByName(models: DMMF.Model[], modelName: string) {\n return models.find(({ name }) => name === modelName);\n}\n\nexport const writeArray = (\n writer: CodeBlockWriter,\n array: string[],\n newLine = true\n) => array.forEach(line => writer.write(line).conditionalNewLine(newLine));\n\nexport const useModelNames = ({\n modelCase,\n modelSuffix,\n relationModel\n}: Config) => {\n const formatModelName = (name: string, prefix = \"\") => {\n if (modelCase === \"camelCase\") {\n name = name.slice(0, 1).toLowerCase() + name.slice(1);\n }\n return `${prefix}${name}${modelSuffix}`;\n };\n\n return {\n modelName: (name: string) =>\n formatModelName(name, relationModel === \"default\" ? \"_\" : \"\"),\n relatedModelName: (\n name: string | DMMF.SchemaEnum | DMMF.OutputType | DMMF.SchemaArg\n ) =>\n formatModelName(\n relationModel === \"default\"\n ? name.toString()\n : `Related${name.toString()}`\n )\n };\n};\n\nexport const dotSlash = (input: string) => {\n const converted = input\n .replace(/^\\\\\\\\\\?\\\\/, \"\")\n .replace(/\\\\/g, \"/\")\n .replace(/\\/{2,}/g, \"/\");\n\n if (converted.includes(`/node_modules/`))\n return converted.split(`/node_modules/`).slice(-1)[0];\n\n if (converted.startsWith(`../`)) return converted;\n\n return `./${converted}`;\n};\n\nexport const chunk = <T extends any[]>(input: T, size: number): T[] => {\n return input.reduce((arr, item, idx) => {\n return idx % size === 0\n ? [...arr, [item]]\n : [...(arr as T).slice(0, -1), [...(arr as T).slice(-1)[0], item]];\n }, []);\n};\n\nexport const needsRelatedModel = (model: DMMF.Model, config: Config) =>\n model.fields.some(field => field.kind === \"object\") &&\n config.relationModel !== false;\n\nexport const writeImportsForModel = async (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config,\n options: GeneratorOptions\n) => {\n const internals = await getPrismaInternals();\n\n const outputPath = internals.parseEnvValue(\n options.generator.output as EnvValue\n );\n\n const { relatedModelName } = useModelNames(config);\n const importList: ImportDeclarationStructure[] = [\n {\n kind: StructureKind.ImportDeclaration,\n namespaceImport: \"z\",\n moduleSpecifier: \"zod\"\n }\n ];\n\n if (config.imports) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n namespaceImport: \"imports\",\n moduleSpecifier: dotSlash(\n path.relative(\n outputPath,\n path.resolve(path.dirname(options.schemaPath), config.imports)\n )\n )!\n });\n }\n\n if (config.useDecimalJs && model.fields.some(f => f.type === \"Decimal\")) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n namedImports: [\"Decimal\"],\n moduleSpecifier: \"decimal.js\"\n });\n }\n\n const enumFields = model.fields.filter(f => f.kind === \"enum\");\n const relationFields = model.fields.filter(f => f.kind === \"object\");\n\n const clientPath = options.otherGenerators.find(\n each => each.provider.value === \"prisma-client-js\"\n )!.output!.value!;\n\n const relativePath = path.relative(outputPath, clientPath);\n\n if (enumFields.length > 0) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n isTypeOnly: enumFields.length === 0,\n moduleSpecifier: dotSlash(relativePath)!,\n namedImports: enumFields.map(f => f.type)\n });\n }\n\n if (config.relationModel !== false && relationFields.length > 0) {\n const filteredFields = relationFields.filter(f => f.type !== model.name);\n\n if (filteredFields.length > 0) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n moduleSpecifier: \"./index\",\n namedImports: Array.from(\n new Set(\n filteredFields.flatMap(f => [`${f.type}`, relatedModelName(f.type)])\n )\n )\n });\n }\n }\n\n sourceFile.addImportDeclarations(importList);\n};\n\nexport const computeCustomSchema = (docString: string) => {\n return getZodDocElements(docString)\n .find(modifier => modifier.startsWith(\"custom(\"))\n ?.slice(7)\n .slice(0, -1);\n};\n\nexport const computeModifiers = (docString: string) => {\n return getZodDocElements(docString).filter(\n each => !each.startsWith(\"custom(\")\n );\n};\n\nexport const getZodConstructor = (\n field: DMMF.Field,\n getRelatedModelName = (\n name: string | DMMF.SchemaEnum | DMMF.OutputType | DMMF.SchemaArg\n ) => name.toString()\n) => {\n let zodType = \"z.unknown()\";\n const extraModifiers: string[] = [\"\"];\n if (field.kind === \"scalar\") {\n switch (field.type) {\n case \"String\":\n zodType = \"z.string()\";\n break;\n case \"Int\":\n zodType = \"z.number()\";\n extraModifiers.push(\"int()\");\n break;\n case \"BigInt\":\n zodType = \"z.bigint()\";\n break;\n case \"DateTime\":\n zodType = \"z.date()\";\n break;\n case \"Float\":\n zodType = \"z.number()\";\n break;\n case \"Decimal\":\n zodType = \"z.number()\";\n break;\n case \"Json\":\n zodType = \"jsonSchema\";\n break;\n case \"Boolean\":\n zodType = \"z.boolean()\";\n break;\n // TODO: Proper type for bytes fields\n case \"Bytes\":\n zodType = \"z.unknown()\";\n break;\n }\n } else if (field.kind === \"enum\") {\n zodType = `z.nativeEnum(${field.type})`;\n } else if (field.kind === \"object\") {\n zodType = getRelatedModelName(field.type);\n }\n\n if (field.isList) extraModifiers.push(\"array()\");\n if (field.documentation) {\n zodType = computeCustomSchema(field.documentation) ?? zodType;\n extraModifiers.push(...computeModifiers(field.documentation));\n }\n if (!field.isRequired && field.type !== \"Json\")\n extraModifiers.push(\"nullish()\");\n // if (field.hasDefaultValue) extraModifiers.push('optional()')\n\n return `${zodType}${extraModifiers.join(\".\")}`;\n};\n\nexport const writeTypeSpecificSchemas = (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config\n) => {\n if (model.fields.some(f => f.type === \"Json\")) {\n sourceFile.addStatements(writer => {\n writer.newLine();\n writeArray(writer, [\n \"// Helper schema for JSON fields\",\n `type Literal = boolean | number | string${\n config.prismaJsonNullability ? \"\" : \"| null\"\n }`,\n \"type Json = Literal | { [key: string]: Json } | Json[]\",\n `const literalSchema = z.union([z.string(), z.number(), z.boolean()${\n config.prismaJsonNullability ? \"\" : \", z.null()\"\n }])`,\n \"const jsonSchema: z.ZodSchema<Json> = z.lazy(() => z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]))\"\n ]);\n });\n }\n\n if (config.useDecimalJs && model.fields.some(f => f.type === \"Decimal\")) {\n sourceFile.addStatements(writer => {\n writer.newLine();\n writeArray(writer, [\n \"// Helper schema for Decimal fields\",\n \"z\",\n \".instanceof(Decimal)\",\n \".or(z.string())\",\n \".or(z.number())\",\n \".refine((value) => {\",\n \" try {\",\n \" return new Decimal(value);\",\n \" } catch (error) {\",\n \" return false;\",\n \" }\",\n \"})\",\n \".transform((value) => new Decimal(value));\"\n ]);\n });\n }\n};\n\nexport const generateSchemaForModel = (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config\n) => {\n const { modelName } = useModelNames(config);\n\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n isExported: true,\n leadingTrivia: writer => writer.blankLineIfLastNot(),\n declarations: [\n {\n name: modelName(model.name),\n initializer(writer) {\n writer\n .write(\"z.object(\")\n .inlineBlock(() => {\n model.fields\n .filter(f => f.kind !== \"object\")\n .forEach(field => {\n writeArray(writer, getJSDocs(field.documentation));\n writer\n .write(`${field.name}: ${getZodConstructor(field)}`)\n .write(\",\")\n .newLine();\n });\n })\n .write(\")\");\n }\n }\n ]\n });\n};\n\nexport const generateRelatedSchemaForModel = (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config\n) => {\n const { modelName, relatedModelName } = useModelNames(config);\n\n const relationFields = model.fields.filter(f => f.kind === \"object\");\n\n sourceFile.addInterface({\n name: `${model.name}`,\n isExported: true,\n extends: [`z.infer<typeof ${modelName(model.name)}>`],\n properties: relationFields.map(f => ({\n hasQuestionToken: !f.isRequired,\n name: f.name,\n type: `${f.type}${f.isList ? \"[]\" : \"\"}${!f.isRequired ? \" | null\" : \"\"}`\n }))\n });\n\n sourceFile.addStatements(writer =>\n writeArray(writer, [\n \"\",\n \"/**\",\n ` * ${relatedModelName(\n model.name\n )} contains all relations on your model in addition to the scalars`,\n \" *\",\n \" * NOTE: Lazy required in case of potential circular dependencies within schema\",\n \" */\"\n ])\n );\n\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n isExported: true,\n declarations: [\n {\n name: relatedModelName(model.name),\n type: `z.ZodSchema<${model.name}>`,\n initializer(writer) {\n writer\n .write(`z.lazy(() => ${modelName(model.name)}.extend(`)\n .inlineBlock(() => {\n relationFields.forEach(field => {\n writeArray(writer, getJSDocs(field.documentation));\n\n writer\n .write(\n `${field.name}: ${getZodConstructor(\n field,\n relatedModelName\n )}`\n )\n .write(\",\")\n .newLine();\n });\n })\n .write(\"))\");\n }\n }\n ]\n });\n};\n\nexport const populateModelFile = async (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config,\n options: GeneratorOptions\n) => {\n await writeImportsForModel(model, sourceFile, config, options);\n writeTypeSpecificSchemas(model, sourceFile, config);\n generateSchemaForModel(model, sourceFile, config);\n if (needsRelatedModel(model, config))\n generateRelatedSchemaForModel(model, sourceFile, config);\n};\n\nexport const generateBarrelFile = (\n models: DMMF.Model[],\n indexFile: SourceFile\n) => {\n models.forEach(model =>\n indexFile.addExportDeclaration({\n moduleSpecifier: `./${lowerCaseFirst(model.name)}.schema`\n })\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model-helpers.mjs","names":["importList: ImportDeclarationStructure[]","extraModifiers: string[]"],"sources":["../../src/zod/model-helpers.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 License, and is\n free for commercial and private use. For more information, please visit\n our licensing page.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/stryke\n Documentation: https://stormsoftware.com/projects/stryke/docs\n Contact: https://stormsoftware.com/contact\n License: https://stormsoftware.com/projects/stryke/license\n\n ------------------------------------------------------------------- */\n\nimport type {\n DMMF,\n EnvValue,\n GeneratorOptions\n} from \"@prisma/generator-helper\";\nimport { lowerCaseFirst } from \"@stryke/string-format/lower-case-first\";\nimport path from \"node:path\";\nimport type {\n CodeBlockWriter,\n ImportDeclarationStructure,\n SourceFile\n} from \"ts-morph\";\nimport { StructureKind, VariableDeclarationKind } from \"ts-morph\";\nimport type { Config } from \"../config\";\nimport { getPrismaInternals } from \"../utils/get-prisma-internals\";\nimport { getJSDocs, getZodDocElements } from \"./docs-helpers\";\n\nexport function checkModelHasModelRelation(model: DMMF.Model) {\n const { fields: modelFields } = model;\n for (const modelField of modelFields) {\n const isRelationField = checkIsModelRelationField(modelField);\n if (isRelationField) {\n return true;\n }\n }\n return false;\n}\n\nexport function checkModelHasManyModelRelation(model: DMMF.Model) {\n const { fields: modelFields } = model;\n for (const modelField of modelFields) {\n const isManyRelationField = checkIsManyModelRelationField(modelField);\n if (isManyRelationField) {\n return true;\n }\n }\n return false;\n}\n\nexport function checkIsModelRelationField(modelField: DMMF.Field) {\n const { kind, relationName } = modelField;\n\n return kind === \"object\" && !!relationName;\n}\n\nexport function checkIsManyModelRelationField(modelField: DMMF.Field) {\n return checkIsModelRelationField(modelField) && modelField.isList;\n}\n\nexport function findModelByName(models: DMMF.Model[], modelName: string) {\n return models.find(({ name }) => name === modelName);\n}\n\nexport const writeArray = (\n writer: CodeBlockWriter,\n array: string[],\n newLine = true\n) => array.forEach(line => writer.write(line).conditionalNewLine(newLine));\n\nexport const useModelNames = ({\n modelCase,\n modelSuffix,\n relationModel\n}: Config) => {\n const formatModelName = (name: string, prefix = \"\") => {\n if (modelCase === \"camelCase\") {\n name = name.slice(0, 1).toLowerCase() + name.slice(1);\n }\n return `${prefix}${name}${modelSuffix}`;\n };\n\n return {\n modelName: (name: string) =>\n formatModelName(name, relationModel === \"default\" ? \"_\" : \"\"),\n relatedModelName: (\n name: string | DMMF.SchemaEnum | DMMF.OutputType | DMMF.SchemaArg\n ) =>\n formatModelName(\n relationModel === \"default\"\n ? name.toString()\n : `Related${name.toString()}`\n )\n };\n};\n\nexport const dotSlash = (input: string) => {\n const converted = input\n .replace(/^\\\\\\\\\\?\\\\/, \"\")\n .replace(/\\\\/g, \"/\")\n .replace(/\\/{2,}/g, \"/\");\n\n if (converted.includes(`/node_modules/`))\n return converted.split(`/node_modules/`).slice(-1)[0];\n\n if (converted.startsWith(`../`)) return converted;\n\n return `./${converted}`;\n};\n\nexport const chunk = <T extends any[]>(input: T, size: number): T[] => {\n return input.reduce((arr, item, idx) => {\n return idx % size === 0\n ? [...arr, [item]]\n : [...(arr as T).slice(0, -1), [...(arr as T).slice(-1)[0], item]];\n }, []);\n};\n\nexport const needsRelatedModel = (model: DMMF.Model, config: Config) =>\n model.fields.some(field => field.kind === \"object\") &&\n config.relationModel !== false;\n\nexport const writeImportsForModel = async (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config,\n options: GeneratorOptions\n) => {\n const internals = await getPrismaInternals();\n\n const outputPath = internals.parseEnvValue(\n options.generator.output as EnvValue\n );\n\n const { relatedModelName } = useModelNames(config);\n const importList: ImportDeclarationStructure[] = [\n {\n kind: StructureKind.ImportDeclaration,\n namespaceImport: \"z\",\n moduleSpecifier: \"zod\"\n }\n ];\n\n if (config.imports) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n namespaceImport: \"imports\",\n moduleSpecifier: dotSlash(\n path.relative(\n outputPath,\n path.resolve(path.dirname(options.schemaPath), config.imports)\n )\n )!\n });\n }\n\n if (config.useDecimalJs && model.fields.some(f => f.type === \"Decimal\")) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n namedImports: [\"Decimal\"],\n moduleSpecifier: \"decimal.js\"\n });\n }\n\n const enumFields = model.fields.filter(f => f.kind === \"enum\");\n const relationFields = model.fields.filter(f => f.kind === \"object\");\n\n const clientPath = options.otherGenerators.find(\n each => each.provider.value === \"prisma-client-js\"\n )!.output!.value!;\n\n const relativePath = path.relative(outputPath, clientPath);\n\n if (enumFields.length > 0) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n isTypeOnly: enumFields.length === 0,\n moduleSpecifier: dotSlash(relativePath)!,\n namedImports: enumFields.map(f => f.type)\n });\n }\n\n if (config.relationModel !== false && relationFields.length > 0) {\n const filteredFields = relationFields.filter(f => f.type !== model.name);\n\n if (filteredFields.length > 0) {\n importList.push({\n kind: StructureKind.ImportDeclaration,\n moduleSpecifier: \"./index\",\n namedImports: Array.from(\n new Set(\n filteredFields.flatMap(f => [`${f.type}`, relatedModelName(f.type)])\n )\n )\n });\n }\n }\n\n sourceFile.addImportDeclarations(importList);\n};\n\nexport const computeCustomSchema = (docString: string) => {\n return getZodDocElements(docString)\n .find(modifier => modifier.startsWith(\"custom(\"))\n ?.slice(7)\n .slice(0, -1);\n};\n\nexport const computeModifiers = (docString: string) => {\n return getZodDocElements(docString).filter(\n each => !each.startsWith(\"custom(\")\n );\n};\n\nexport const getZodConstructor = (\n field: DMMF.Field,\n getRelatedModelName = (\n name: string | DMMF.SchemaEnum | DMMF.OutputType | DMMF.SchemaArg\n ) => name.toString()\n) => {\n let zodType = \"z.unknown()\";\n const extraModifiers: string[] = [\"\"];\n if (field.kind === \"scalar\") {\n switch (field.type) {\n case \"String\":\n zodType = \"z.string()\";\n break;\n case \"Int\":\n zodType = \"z.number()\";\n extraModifiers.push(\"int()\");\n break;\n case \"BigInt\":\n zodType = \"z.bigint()\";\n break;\n case \"DateTime\":\n zodType = \"z.date()\";\n break;\n case \"Float\":\n zodType = \"z.number()\";\n break;\n case \"Decimal\":\n zodType = \"z.number()\";\n break;\n case \"Json\":\n zodType = \"jsonSchema\";\n break;\n case \"Boolean\":\n zodType = \"z.boolean()\";\n break;\n // TODO: Proper type for bytes fields\n case \"Bytes\":\n zodType = \"z.unknown()\";\n break;\n }\n } else if (field.kind === \"enum\") {\n zodType = `z.nativeEnum(${field.type})`;\n } else if (field.kind === \"object\") {\n zodType = getRelatedModelName(field.type);\n }\n\n if (field.isList) extraModifiers.push(\"array()\");\n if (field.documentation) {\n zodType = computeCustomSchema(field.documentation) ?? zodType;\n extraModifiers.push(...computeModifiers(field.documentation));\n }\n if (!field.isRequired && field.type !== \"Json\")\n extraModifiers.push(\"nullish()\");\n // if (field.hasDefaultValue) extraModifiers.push('optional()')\n\n return `${zodType}${extraModifiers.join(\".\")}`;\n};\n\nexport const writeTypeSpecificSchemas = (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config\n) => {\n if (model.fields.some(f => f.type === \"Json\")) {\n sourceFile.addStatements(writer => {\n writer.newLine();\n writeArray(writer, [\n \"// Helper schema for JSON fields\",\n `type Literal = boolean | number | string${\n config.prismaJsonNullability ? \"\" : \"| null\"\n }`,\n \"type Json = Literal | { [key: string]: Json } | Json[]\",\n `const literalSchema = z.union([z.string(), z.number(), z.boolean()${\n config.prismaJsonNullability ? \"\" : \", z.null()\"\n }])`,\n \"const jsonSchema: z.ZodSchema<Json> = z.lazy(() => z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]))\"\n ]);\n });\n }\n\n if (config.useDecimalJs && model.fields.some(f => f.type === \"Decimal\")) {\n sourceFile.addStatements(writer => {\n writer.newLine();\n writeArray(writer, [\n \"// Helper schema for Decimal fields\",\n \"z\",\n \".instanceof(Decimal)\",\n \".or(z.string())\",\n \".or(z.number())\",\n \".refine((value) => {\",\n \" try {\",\n \" return new Decimal(value);\",\n \" } catch (error) {\",\n \" return false;\",\n \" }\",\n \"})\",\n \".transform((value) => new Decimal(value));\"\n ]);\n });\n }\n};\n\nexport const generateSchemaForModel = (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config\n) => {\n const { modelName } = useModelNames(config);\n\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n isExported: true,\n leadingTrivia: writer => writer.blankLineIfLastNot(),\n declarations: [\n {\n name: modelName(model.name),\n initializer(writer) {\n writer\n .write(\"z.object(\")\n .inlineBlock(() => {\n model.fields\n .filter(f => f.kind !== \"object\")\n .forEach(field => {\n writeArray(writer, getJSDocs(field.documentation));\n writer\n .write(`${field.name}: ${getZodConstructor(field)}`)\n .write(\",\")\n .newLine();\n });\n })\n .write(\")\");\n }\n }\n ]\n });\n};\n\nexport const generateRelatedSchemaForModel = (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config\n) => {\n const { modelName, relatedModelName } = useModelNames(config);\n\n const relationFields = model.fields.filter(f => f.kind === \"object\");\n\n sourceFile.addInterface({\n name: `${model.name}`,\n isExported: true,\n extends: [`z.infer<typeof ${modelName(model.name)}>`],\n properties: relationFields.map(f => ({\n hasQuestionToken: !f.isRequired,\n name: f.name,\n type: `${f.type}${f.isList ? \"[]\" : \"\"}${!f.isRequired ? \" | null\" : \"\"}`\n }))\n });\n\n sourceFile.addStatements(writer =>\n writeArray(writer, [\n \"\",\n \"/**\",\n ` * ${relatedModelName(\n model.name\n )} contains all relations on your model in addition to the scalars`,\n \" *\",\n \" * NOTE: Lazy required in case of potential circular dependencies within schema\",\n \" */\"\n ])\n );\n\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n isExported: true,\n declarations: [\n {\n name: relatedModelName(model.name),\n type: `z.ZodSchema<${model.name}>`,\n initializer(writer) {\n writer\n .write(`z.lazy(() => ${modelName(model.name)}.extend(`)\n .inlineBlock(() => {\n relationFields.forEach(field => {\n writeArray(writer, getJSDocs(field.documentation));\n\n writer\n .write(\n `${field.name}: ${getZodConstructor(\n field,\n relatedModelName\n )}`\n )\n .write(\",\")\n .newLine();\n });\n })\n .write(\"))\");\n }\n }\n ]\n });\n};\n\nexport const populateModelFile = async (\n model: DMMF.Model,\n sourceFile: SourceFile,\n config: Config,\n options: GeneratorOptions\n) => {\n await writeImportsForModel(model, sourceFile, config, options);\n writeTypeSpecificSchemas(model, sourceFile, config);\n generateSchemaForModel(model, sourceFile, config);\n if (needsRelatedModel(model, config))\n generateRelatedSchemaForModel(model, sourceFile, config);\n};\n\nexport const generateBarrelFile = (\n models: DMMF.Model[],\n indexFile: SourceFile\n) => {\n models.forEach(model =>\n indexFile.addExportDeclaration({\n moduleSpecifier: `./${lowerCaseFirst(model.name)}.schema`\n })\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1,56 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_model_helpers = require('./model-helpers.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/zod/modelArgs-helpers.ts
|
|
4
|
+
function addMissingInputObjectTypesForModelArgs(inputObjectTypes, models, isGenerateSelect, isGenerateInclude) {
|
|
5
|
+
const modelArgsInputObjectTypes = generateModelArgsInputObjectTypes(models, isGenerateSelect, isGenerateInclude);
|
|
6
|
+
for (const modelArgsInputObjectType of modelArgsInputObjectTypes) inputObjectTypes.push(modelArgsInputObjectType);
|
|
7
|
+
}
|
|
8
|
+
function generateModelArgsInputObjectTypes(models, isGenerateSelect, isGenerateInclude) {
|
|
9
|
+
const modelArgsInputObjectTypes = [];
|
|
10
|
+
for (const model of models) {
|
|
11
|
+
const { name: modelName } = model;
|
|
12
|
+
const fields = [];
|
|
13
|
+
if (isGenerateSelect) {
|
|
14
|
+
const selectField = {
|
|
15
|
+
name: "select",
|
|
16
|
+
isRequired: false,
|
|
17
|
+
isNullable: false,
|
|
18
|
+
inputTypes: [{
|
|
19
|
+
isList: false,
|
|
20
|
+
type: `${modelName}Select`,
|
|
21
|
+
location: "inputObjectTypes",
|
|
22
|
+
namespace: "prisma"
|
|
23
|
+
}]
|
|
24
|
+
};
|
|
25
|
+
fields.push(selectField);
|
|
26
|
+
}
|
|
27
|
+
const hasRelationToAnotherModel = require_model_helpers.checkModelHasModelRelation(model);
|
|
28
|
+
if (isGenerateInclude && hasRelationToAnotherModel) {
|
|
29
|
+
const includeField = {
|
|
30
|
+
name: "include",
|
|
31
|
+
isRequired: false,
|
|
32
|
+
isNullable: false,
|
|
33
|
+
inputTypes: [{
|
|
34
|
+
isList: false,
|
|
35
|
+
type: `${modelName}Include`,
|
|
36
|
+
location: "inputObjectTypes",
|
|
37
|
+
namespace: "prisma"
|
|
38
|
+
}]
|
|
39
|
+
};
|
|
40
|
+
fields.push(includeField);
|
|
41
|
+
}
|
|
42
|
+
const modelArgsInputObjectType = {
|
|
43
|
+
name: `${modelName}DefaultArgs`,
|
|
44
|
+
constraints: {
|
|
45
|
+
maxNumFields: null,
|
|
46
|
+
minNumFields: null
|
|
47
|
+
},
|
|
48
|
+
fields
|
|
49
|
+
};
|
|
50
|
+
modelArgsInputObjectTypes.push(modelArgsInputObjectType);
|
|
51
|
+
}
|
|
52
|
+
return modelArgsInputObjectTypes;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
exports.addMissingInputObjectTypesForModelArgs = addMissingInputObjectTypesForModelArgs;
|