zenstack 2.0.0-alpha.6 → 2.0.0-beta.1
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/README.md +5 -5
- package/language-server/validator/datamodel-validator.d.ts +1 -0
- package/language-server/validator/datamodel-validator.js +9 -0
- package/language-server/validator/datamodel-validator.js.map +1 -1
- package/package.json +4 -4
- package/plugins/enhancer/enhance/auth-type-generator.d.ts +6 -0
- package/plugins/enhancer/enhance/auth-type-generator.js +116 -0
- package/plugins/enhancer/enhance/auth-type-generator.js.map +1 -0
- package/plugins/enhancer/enhance/index.d.ts +34 -3
- package/plugins/enhancer/enhance/index.js +390 -278
- package/plugins/enhancer/enhance/index.js.map +1 -1
- package/plugins/enhancer/index.js +1 -1
- package/plugins/enhancer/index.js.map +1 -1
- package/plugins/prisma/schema-generator.d.ts +2 -0
- package/plugins/prisma/schema-generator.js +35 -10
- package/plugins/prisma/schema-generator.js.map +1 -1
- package/plugins/zod/generator.js +100 -29
- package/plugins/zod/generator.js.map +1 -1
|
@@ -12,326 +12,438 @@ 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.
|
|
15
|
+
exports.EnhancerGenerator = void 0;
|
|
16
16
|
const runtime_1 = require("@zenstackhq/runtime");
|
|
17
17
|
const sdk_1 = require("@zenstackhq/sdk");
|
|
18
18
|
const ast_1 = require("@zenstackhq/sdk/ast");
|
|
19
19
|
const fs_1 = __importDefault(require("fs"));
|
|
20
20
|
const path_1 = __importDefault(require("path"));
|
|
21
21
|
const ts_morph_1 = require("ts-morph");
|
|
22
|
+
const upper_case_first_1 = require("upper-case-first");
|
|
22
23
|
const __1 = require("..");
|
|
23
24
|
const exec_utils_1 = require("../../../utils/exec-utils");
|
|
24
25
|
const prisma_1 = require("../../prisma");
|
|
25
26
|
const schema_generator_1 = require("../../prisma/schema-generator");
|
|
26
27
|
const enhancer_utils_1 = require("../enhancer-utils");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
28
|
+
const auth_type_generator_1 = require("./auth-type-generator");
|
|
29
|
+
class EnhancerGenerator {
|
|
30
|
+
constructor(model, options, project, outDir) {
|
|
31
|
+
this.model = model;
|
|
32
|
+
this.options = options;
|
|
33
|
+
this.project = project;
|
|
34
|
+
this.outDir = outDir;
|
|
35
|
+
}
|
|
36
|
+
generate() {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
let logicalPrismaClientDir;
|
|
39
|
+
let dmmf;
|
|
40
|
+
const prismaImport = (0, sdk_1.getPrismaClientImportSpec)(this.outDir, this.options);
|
|
41
|
+
if (this.needsLogicalClient()) {
|
|
42
|
+
// schema contains delegate models, need to generate a logical prisma schema
|
|
43
|
+
const result = yield this.generateLogicalPrisma();
|
|
44
|
+
logicalPrismaClientDir = './.logical-prisma-client';
|
|
45
|
+
dmmf = result.dmmf;
|
|
46
|
+
// create a reexport of the logical prisma client
|
|
47
|
+
const prismaDts = this.project.createSourceFile(path_1.default.join(this.outDir, 'prisma.d.ts'), `export type * from '${logicalPrismaClientDir}/index-fixed';`, { overwrite: true });
|
|
48
|
+
yield prismaDts.save();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// just reexport the prisma client
|
|
52
|
+
const prismaDts = this.project.createSourceFile(path_1.default.join(this.outDir, 'prisma.d.ts'), `export type * from '${prismaImport}';`, { overwrite: true });
|
|
53
|
+
yield prismaDts.save();
|
|
54
|
+
}
|
|
55
|
+
const authModel = (0, sdk_1.getAuthModel)((0, sdk_1.getDataModels)(this.model));
|
|
56
|
+
const authTypes = authModel ? (0, auth_type_generator_1.generateAuthType)(this.model, authModel) : '';
|
|
57
|
+
const authTypeParam = authModel ? `auth.${authModel.name}` : 'AuthUser';
|
|
58
|
+
const enhanceTs = this.project.createSourceFile(path_1.default.join(this.outDir, 'enhance.ts'), `import { createEnhancement, type EnhancementContext, type EnhancementOptions, type ZodSchemas, type AuthUser } from '@zenstackhq/runtime';
|
|
47
59
|
import modelMeta from './model-meta';
|
|
48
60
|
import policy from './policy';
|
|
49
|
-
${options.withZodSchemas ? "import * as zodSchemas from './zod';" : 'const zodSchemas = undefined;'}
|
|
50
|
-
|
|
51
|
-
${
|
|
61
|
+
${this.options.withZodSchemas ? "import * as zodSchemas from './zod';" : 'const zodSchemas = undefined;'}
|
|
62
|
+
|
|
63
|
+
${logicalPrismaClientDir
|
|
64
|
+
? this.createLogicalPrismaImports(prismaImport, logicalPrismaClientDir)
|
|
65
|
+
: this.createSimplePrismaImports(prismaImport)}
|
|
52
66
|
|
|
53
|
-
|
|
67
|
+
${authTypes}
|
|
68
|
+
|
|
69
|
+
${logicalPrismaClientDir
|
|
70
|
+
? this.createLogicalPrismaEnhanceFunction(authTypeParam)
|
|
71
|
+
: this.createSimplePrismaEnhanceFunction(authTypeParam)}
|
|
72
|
+
`, { overwrite: true });
|
|
73
|
+
yield this.saveSourceFile(enhanceTs);
|
|
74
|
+
return { dmmf };
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
createSimplePrismaImports(prismaImport) {
|
|
78
|
+
return `import { Prisma } from '${prismaImport}';
|
|
79
|
+
import type * as _P from '${prismaImport}';
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
createSimplePrismaEnhanceFunction(authTypeParam) {
|
|
83
|
+
return `
|
|
84
|
+
export function enhance<DbClient extends object>(prisma: DbClient, context?: EnhancementContext<${authTypeParam}>, options?: EnhancementOptions) {
|
|
54
85
|
return createEnhancement(prisma, {
|
|
55
86
|
modelMeta,
|
|
56
87
|
policy,
|
|
57
88
|
zodSchemas: zodSchemas as unknown as (ZodSchemas | undefined),
|
|
58
89
|
prismaModule: Prisma,
|
|
59
90
|
...options
|
|
60
|
-
}, context)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
}, context);
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
}
|
|
95
|
+
createLogicalPrismaImports(prismaImport, logicalPrismaClientDir) {
|
|
96
|
+
return `import { Prisma as _Prisma, PrismaClient as _PrismaClient } from '${prismaImport}';
|
|
97
|
+
import type {
|
|
98
|
+
InternalArgs,
|
|
99
|
+
TypeMapDef,
|
|
100
|
+
TypeMapCbDef,
|
|
101
|
+
DynamicClientExtensionThis,
|
|
102
|
+
} from '${prismaImport}/runtime/library';
|
|
103
|
+
import type * as _P from '${logicalPrismaClientDir}/index-fixed';
|
|
104
|
+
import type { Prisma, PrismaClient } from '${logicalPrismaClientDir}/index-fixed';
|
|
105
|
+
`;
|
|
106
|
+
}
|
|
107
|
+
createLogicalPrismaEnhanceFunction(authTypeParam) {
|
|
108
|
+
return `
|
|
109
|
+
// overload for plain PrismaClient
|
|
110
|
+
export function enhance<ExtArgs extends Record<string, any> & InternalArgs>(
|
|
111
|
+
prisma: _PrismaClient<any, any, ExtArgs>,
|
|
112
|
+
context?: EnhancementContext<${authTypeParam}>, options?: EnhancementOptions): PrismaClient;
|
|
113
|
+
|
|
114
|
+
// overload for extended PrismaClient
|
|
115
|
+
export function enhance<TypeMap extends TypeMapDef, TypeMapCb extends TypeMapCbDef, ExtArgs extends Record<string, any> & InternalArgs>(
|
|
116
|
+
prisma: DynamicClientExtensionThis<TypeMap, TypeMapCb, ExtArgs>,
|
|
117
|
+
context?: EnhancementContext<${authTypeParam}>, options?: EnhancementOptions): DynamicClientExtensionThis<Prisma.TypeMap, Prisma.TypeMapCb, ExtArgs>;
|
|
118
|
+
|
|
119
|
+
export function enhance(prisma: any, context?: EnhancementContext<${authTypeParam}>, options?: EnhancementOptions): any {
|
|
120
|
+
return createEnhancement(prisma, {
|
|
121
|
+
modelMeta,
|
|
122
|
+
policy,
|
|
123
|
+
zodSchemas: zodSchemas as unknown as (ZodSchemas | undefined),
|
|
124
|
+
prismaModule: _Prisma,
|
|
125
|
+
...options
|
|
126
|
+
}, context);
|
|
77
127
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
130
|
+
needsLogicalClient() {
|
|
131
|
+
return this.hasDelegateModel(this.model) || this.hasAuthInDefault(this.model);
|
|
132
|
+
}
|
|
133
|
+
hasDelegateModel(model) {
|
|
134
|
+
const dataModels = (0, sdk_1.getDataModels)(model);
|
|
135
|
+
return dataModels.some((dm) => (0, sdk_1.isDelegateModel)(dm) && dataModels.some((sub) => sub.superTypes.some((base) => base.ref === dm)));
|
|
136
|
+
}
|
|
137
|
+
hasAuthInDefault(model) {
|
|
138
|
+
return (0, sdk_1.getDataModels)(model).some((dm) => dm.fields.some((f) => f.attributes.some((attr) => (0, enhancer_utils_1.isDefaultWithAuth)(attr))));
|
|
139
|
+
}
|
|
140
|
+
generateLogicalPrisma() {
|
|
141
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
142
|
+
const prismaGenerator = new schema_generator_1.PrismaSchemaGenerator(this.model);
|
|
143
|
+
const prismaClientOutDir = './.logical-prisma-client';
|
|
144
|
+
const logicalPrismaFile = path_1.default.join(this.outDir, 'logical.prisma');
|
|
145
|
+
yield prismaGenerator.generate({
|
|
146
|
+
provider: '@internal', // doesn't matter
|
|
147
|
+
schemaPath: this.options.schemaPath,
|
|
148
|
+
output: logicalPrismaFile,
|
|
149
|
+
overrideClientGenerationPath: prismaClientOutDir,
|
|
150
|
+
mode: 'logical',
|
|
151
|
+
});
|
|
152
|
+
// generate the prisma client
|
|
153
|
+
const generateCmd = `prisma generate --schema "${logicalPrismaFile}" --no-engine`;
|
|
98
154
|
try {
|
|
99
|
-
// run 'prisma generate'
|
|
100
|
-
yield (0, exec_utils_1.execPackage)(generateCmd);
|
|
155
|
+
// run 'prisma generate'
|
|
156
|
+
yield (0, exec_utils_1.execPackage)(generateCmd, { stdio: 'ignore' });
|
|
101
157
|
}
|
|
102
|
-
catch (
|
|
103
|
-
|
|
158
|
+
catch (_a) {
|
|
159
|
+
yield (0, prisma_1.trackPrismaSchemaError)(logicalPrismaFile);
|
|
160
|
+
try {
|
|
161
|
+
// run 'prisma generate' again with output to the console
|
|
162
|
+
yield (0, exec_utils_1.execPackage)(generateCmd);
|
|
163
|
+
}
|
|
164
|
+
catch (_b) {
|
|
165
|
+
// noop
|
|
166
|
+
}
|
|
167
|
+
throw new sdk_1.PluginError(__1.name, `Failed to run "prisma generate" on logical schema: ${logicalPrismaFile}`);
|
|
104
168
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
dmmf: yield (0, sdk_1.getDMMF)({ datamodel: fs_1.default.readFileSync(logicalPrismaFile, { encoding: 'utf-8' }) }),
|
|
113
|
-
};
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
function processClientTypes(model, prismaClientDir) {
|
|
117
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
// make necessary updates to the generated `index.d.ts` file and save it as `index-fixed.d.ts`
|
|
119
|
-
const project = new ts_morph_1.Project();
|
|
120
|
-
const sf = project.addSourceFileAtPath(path_1.default.join(prismaClientDir, 'index.d.ts'));
|
|
121
|
-
// build a map of delegate models and their sub models
|
|
122
|
-
const delegateInfo = [];
|
|
123
|
-
model.declarations
|
|
124
|
-
.filter((d) => (0, sdk_1.isDelegateModel)(d))
|
|
125
|
-
.forEach((dm) => {
|
|
126
|
-
delegateInfo.push([
|
|
127
|
-
dm,
|
|
128
|
-
model.declarations.filter((d) => (0, ast_1.isDataModel)(d) && d.superTypes.some((s) => s.ref === dm)),
|
|
129
|
-
]);
|
|
169
|
+
// make a bunch of typing fixes to the generated prisma client
|
|
170
|
+
yield this.processClientTypes(path_1.default.join(this.outDir, prismaClientOutDir));
|
|
171
|
+
return {
|
|
172
|
+
prismaSchema: logicalPrismaFile,
|
|
173
|
+
// load the dmmf of the logical prisma schema
|
|
174
|
+
dmmf: yield (0, sdk_1.getDMMF)({ datamodel: fs_1.default.readFileSync(logicalPrismaFile, { encoding: 'utf-8' }) }),
|
|
175
|
+
};
|
|
130
176
|
});
|
|
131
|
-
|
|
132
|
-
|
|
177
|
+
}
|
|
178
|
+
processClientTypes(prismaClientDir) {
|
|
179
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
+
// make necessary updates to the generated `index.d.ts` file and save it as `index-fixed.d.ts`
|
|
181
|
+
const project = new ts_morph_1.Project();
|
|
182
|
+
const sf = project.addSourceFileAtPath(path_1.default.join(prismaClientDir, 'index.d.ts'));
|
|
183
|
+
// build a map of delegate models and their sub models
|
|
184
|
+
const delegateInfo = [];
|
|
185
|
+
this.model.declarations
|
|
186
|
+
.filter((d) => (0, sdk_1.isDelegateModel)(d))
|
|
187
|
+
.forEach((dm) => {
|
|
188
|
+
delegateInfo.push([
|
|
189
|
+
dm,
|
|
190
|
+
this.model.declarations.filter((d) => (0, ast_1.isDataModel)(d) && d.superTypes.some((s) => s.ref === dm)),
|
|
191
|
+
]);
|
|
192
|
+
});
|
|
193
|
+
const sfNew = project.createSourceFile(path_1.default.join(prismaClientDir, 'index-fixed.d.ts'), undefined, {
|
|
194
|
+
overwrite: true,
|
|
195
|
+
});
|
|
196
|
+
if (delegateInfo.length > 0) {
|
|
197
|
+
// transform types for delegated models
|
|
198
|
+
this.transformDelegate(sf, sfNew, delegateInfo);
|
|
199
|
+
sfNew.formatText();
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// just copy
|
|
203
|
+
sfNew.replaceWithText(sf.getFullText());
|
|
204
|
+
}
|
|
205
|
+
yield sfNew.save();
|
|
133
206
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
207
|
+
}
|
|
208
|
+
transformDelegate(sf, sfNew, delegateInfo) {
|
|
209
|
+
// copy toplevel imports
|
|
210
|
+
sfNew.addImportDeclarations(sf.getImportDeclarations().map((n) => n.getStructure()));
|
|
211
|
+
// copy toplevel import equals
|
|
212
|
+
sfNew.addStatements(sf.getChildrenOfKind(ts_morph_1.SyntaxKind.ImportEqualsDeclaration).map((n) => n.getFullText()));
|
|
213
|
+
// copy toplevel exports
|
|
214
|
+
sfNew.addExportAssignments(sf.getExportAssignments().map((n) => n.getStructure()));
|
|
215
|
+
// copy toplevel type aliases
|
|
216
|
+
sfNew.addTypeAliases(sf.getTypeAliases().map((n) => n.getStructure()));
|
|
217
|
+
// copy toplevel classes
|
|
218
|
+
sfNew.addClasses(sf.getClasses().map((n) => n.getStructure()));
|
|
219
|
+
// copy toplevel variables
|
|
220
|
+
sfNew.addVariableStatements(sf.getVariableStatements().map((n) => n.getStructure()));
|
|
221
|
+
// copy toplevel namespaces except for `Prisma`
|
|
222
|
+
sfNew.addModules(sf
|
|
223
|
+
.getModules()
|
|
224
|
+
.filter((n) => n.getName() !== 'Prisma')
|
|
225
|
+
.map((n) => n.getStructure()));
|
|
226
|
+
// transform the `Prisma` namespace
|
|
227
|
+
const prismaModule = sf.getModuleOrThrow('Prisma');
|
|
228
|
+
const newPrismaModule = sfNew.addModule({ name: 'Prisma', isExported: true });
|
|
229
|
+
this.transformPrismaModule(prismaModule, newPrismaModule, delegateInfo);
|
|
230
|
+
}
|
|
231
|
+
transformPrismaModule(prismaModule, newPrismaModule, delegateInfo) {
|
|
232
|
+
// module block is the direct container of declarations inside a namespace
|
|
233
|
+
const moduleBlock = prismaModule.getFirstChildByKindOrThrow(ts_morph_1.SyntaxKind.ModuleBlock);
|
|
234
|
+
// most of the toplevel constructs should be copied over
|
|
235
|
+
// here we use ts-morph batch operations for optimal performance
|
|
236
|
+
// copy imports
|
|
237
|
+
newPrismaModule.addStatements(moduleBlock.getChildrenOfKind(ts_morph_1.SyntaxKind.ImportEqualsDeclaration).map((n) => n.getFullText()));
|
|
238
|
+
// copy classes
|
|
239
|
+
newPrismaModule.addClasses(moduleBlock.getClasses().map((n) => n.getStructure()));
|
|
240
|
+
// copy functions
|
|
241
|
+
newPrismaModule.addFunctions(moduleBlock.getFunctions().map((n) => n.getStructure()));
|
|
242
|
+
// copy nested namespaces
|
|
243
|
+
newPrismaModule.addModules(moduleBlock.getModules().map((n) => n.getStructure()));
|
|
244
|
+
// transform variables
|
|
245
|
+
const newVariables = moduleBlock
|
|
246
|
+
.getVariableStatements()
|
|
247
|
+
.map((variable) => this.transformVariableStatement(variable));
|
|
248
|
+
newPrismaModule.addVariableStatements(newVariables);
|
|
249
|
+
// transform interfaces
|
|
250
|
+
const newInterfaces = moduleBlock.getInterfaces().map((iface) => this.transformInterface(iface, delegateInfo));
|
|
251
|
+
newPrismaModule.addInterfaces(newInterfaces);
|
|
252
|
+
// transform type aliases
|
|
253
|
+
const newTypeAliases = moduleBlock
|
|
254
|
+
.getTypeAliases()
|
|
255
|
+
.map((typeAlias) => this.transformTypeAlias(typeAlias, delegateInfo));
|
|
256
|
+
newPrismaModule.addTypeAliases(newTypeAliases);
|
|
257
|
+
}
|
|
258
|
+
transformVariableStatement(variable) {
|
|
259
|
+
const structure = variable.getStructure();
|
|
260
|
+
// remove `delegate_aux_*` fields from the variable's typing
|
|
261
|
+
const auxFields = this.findAuxDecls(variable);
|
|
262
|
+
if (auxFields.length > 0) {
|
|
263
|
+
structure.declarations.forEach((variable) => {
|
|
264
|
+
var _a;
|
|
265
|
+
let source = (_a = variable.type) === null || _a === void 0 ? void 0 : _a.toString();
|
|
266
|
+
auxFields.forEach((f) => {
|
|
267
|
+
source = source === null || source === void 0 ? void 0 : source.replace(f.getText(), '');
|
|
268
|
+
});
|
|
269
|
+
variable.type = source;
|
|
270
|
+
});
|
|
138
271
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
272
|
+
return structure;
|
|
273
|
+
}
|
|
274
|
+
transformInterface(iface, delegateInfo) {
|
|
275
|
+
var _a, _b, _c;
|
|
276
|
+
const structure = iface.getStructure();
|
|
277
|
+
// filter out aux fields
|
|
278
|
+
structure.properties = (_a = structure.properties) === null || _a === void 0 ? void 0 : _a.filter((p) => !p.name.startsWith(runtime_1.DELEGATE_AUX_RELATION_PREFIX));
|
|
279
|
+
// filter out aux methods
|
|
280
|
+
structure.methods = (_b = structure.methods) === null || _b === void 0 ? void 0 : _b.filter((m) => !m.name.startsWith(runtime_1.DELEGATE_AUX_RELATION_PREFIX));
|
|
281
|
+
if (delegateInfo.some(([delegate]) => `${delegate.name}Delegate` === iface.getName())) {
|
|
282
|
+
// delegate models cannot be created directly, remove create/createMany/upsert
|
|
283
|
+
structure.methods = (_c = structure.methods) === null || _c === void 0 ? void 0 : _c.filter((m) => !['create', 'createMany', 'upsert'].includes(m.name));
|
|
142
284
|
}
|
|
143
|
-
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
function transformDelegate(sf, sfNew, delegateModels) {
|
|
147
|
-
// copy toplevel imports
|
|
148
|
-
sfNew.addImportDeclarations(sf.getImportDeclarations().map((n) => n.getStructure()));
|
|
149
|
-
// copy toplevel import equals
|
|
150
|
-
sfNew.addStatements(sf.getChildrenOfKind(ts_morph_1.SyntaxKind.ImportEqualsDeclaration).map((n) => n.getFullText()));
|
|
151
|
-
// copy toplevel exports
|
|
152
|
-
sfNew.addExportAssignments(sf.getExportAssignments().map((n) => n.getStructure()));
|
|
153
|
-
// copy toplevel type aliases
|
|
154
|
-
sfNew.addTypeAliases(sf.getTypeAliases().map((n) => n.getStructure()));
|
|
155
|
-
// copy toplevel classes
|
|
156
|
-
sfNew.addClasses(sf.getClasses().map((n) => n.getStructure()));
|
|
157
|
-
// copy toplevel variables
|
|
158
|
-
sfNew.addVariableStatements(sf.getVariableStatements().map((n) => n.getStructure()));
|
|
159
|
-
// copy toplevel namespaces except for `Prisma`
|
|
160
|
-
sfNew.addModules(sf
|
|
161
|
-
.getModules()
|
|
162
|
-
.filter((n) => n.getName() !== 'Prisma')
|
|
163
|
-
.map((n) => n.getStructure()));
|
|
164
|
-
// transform the `Prisma` namespace
|
|
165
|
-
const prismaModule = sf.getModuleOrThrow('Prisma');
|
|
166
|
-
const newPrismaModule = sfNew.addModule({ name: 'Prisma', isExported: true });
|
|
167
|
-
transformPrismaModule(prismaModule, newPrismaModule, delegateModels);
|
|
168
|
-
}
|
|
169
|
-
function transformPrismaModule(prismaModule, newPrismaModule, delegateInfo) {
|
|
170
|
-
// module block is the direct container of declarations inside a namespace
|
|
171
|
-
const moduleBlock = prismaModule.getFirstChildByKindOrThrow(ts_morph_1.SyntaxKind.ModuleBlock);
|
|
172
|
-
// most of the toplevel constructs should be copied over
|
|
173
|
-
// here we use ts-morph batch operations for optimal performance
|
|
174
|
-
// copy imports
|
|
175
|
-
newPrismaModule.addStatements(moduleBlock.getChildrenOfKind(ts_morph_1.SyntaxKind.ImportEqualsDeclaration).map((n) => n.getFullText()));
|
|
176
|
-
// copy classes
|
|
177
|
-
newPrismaModule.addClasses(moduleBlock.getClasses().map((n) => n.getStructure()));
|
|
178
|
-
// copy functions
|
|
179
|
-
newPrismaModule.addFunctions(moduleBlock.getFunctions().map((n) => n.getStructure()));
|
|
180
|
-
// copy nested namespaces
|
|
181
|
-
newPrismaModule.addModules(moduleBlock.getModules().map((n) => n.getStructure()));
|
|
182
|
-
// transform variables
|
|
183
|
-
const newVariables = moduleBlock.getVariableStatements().map((variable) => transformVariableStatement(variable));
|
|
184
|
-
newPrismaModule.addVariableStatements(newVariables);
|
|
185
|
-
// transform interfaces
|
|
186
|
-
const newInterfaces = moduleBlock.getInterfaces().map((iface) => transformInterface(iface, delegateInfo));
|
|
187
|
-
newPrismaModule.addInterfaces(newInterfaces);
|
|
188
|
-
// transform type aliases
|
|
189
|
-
const newTypeAliases = moduleBlock.getTypeAliases().map((typeAlias) => transformTypeAlias(typeAlias, delegateInfo));
|
|
190
|
-
newPrismaModule.addTypeAliases(newTypeAliases);
|
|
191
|
-
}
|
|
192
|
-
function transformVariableStatement(variable) {
|
|
193
|
-
const structure = variable.getStructure();
|
|
194
|
-
// remove `delegate_aux_*` fields from the variable's typing
|
|
195
|
-
const auxFields = findAuxDecls(variable);
|
|
196
|
-
if (auxFields.length > 0) {
|
|
197
|
-
structure.declarations.forEach((variable) => {
|
|
198
|
-
var _a;
|
|
199
|
-
let source = (_a = variable.type) === null || _a === void 0 ? void 0 : _a.toString();
|
|
200
|
-
auxFields.forEach((f) => {
|
|
201
|
-
source = source === null || source === void 0 ? void 0 : source.replace(f.getText(), '');
|
|
202
|
-
});
|
|
203
|
-
variable.type = source;
|
|
204
|
-
});
|
|
285
|
+
return structure;
|
|
205
286
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
287
|
+
transformTypeAlias(typeAlias, delegateInfo) {
|
|
288
|
+
const structure = typeAlias.getStructure();
|
|
289
|
+
let source = structure.type;
|
|
290
|
+
// remove aux fields
|
|
291
|
+
source = this.removeAuxFieldsFromTypeAlias(typeAlias, source);
|
|
292
|
+
// remove discriminator field from concrete input types
|
|
293
|
+
source = this.removeDiscriminatorFromConcreteInput(typeAlias, delegateInfo, source);
|
|
294
|
+
// remove create/connectOrCreate/upsert fields from delegate's input types
|
|
295
|
+
source = this.removeCreateFromDelegateInput(typeAlias, delegateInfo, source);
|
|
296
|
+
// remove delegate fields from nested mutation input types
|
|
297
|
+
source = this.removeDelegateFieldsFromNestedMutationInput(typeAlias, delegateInfo, source);
|
|
298
|
+
// fix delegate payload union type
|
|
299
|
+
source = this.fixDelegatePayloadType(typeAlias, delegateInfo, source);
|
|
300
|
+
structure.type = source;
|
|
301
|
+
return structure;
|
|
218
302
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// fix delegate payload union type
|
|
231
|
-
source = fixDelegatePayloadType(typeAlias, delegateInfo, source);
|
|
232
|
-
structure.type = source;
|
|
233
|
-
return structure;
|
|
234
|
-
}
|
|
235
|
-
function fixDelegatePayloadType(typeAlias, delegateInfo, source) {
|
|
236
|
-
// change the type of `$<DelegateModel>Payload` type of delegate model to a union of concrete types
|
|
237
|
-
const typeName = typeAlias.getName();
|
|
238
|
-
const payloadRecord = delegateInfo.find(([delegate]) => `$${delegate.name}Payload` === typeName);
|
|
239
|
-
if (payloadRecord) {
|
|
240
|
-
const discriminatorDecl = getDiscriminatorField(payloadRecord[0]);
|
|
241
|
-
if (discriminatorDecl) {
|
|
242
|
-
source = `${payloadRecord[1]
|
|
243
|
-
.map((concrete) => `($${concrete.name}Payload<ExtArgs> & { scalars: { ${discriminatorDecl.name}: '${concrete.name}' } })`)
|
|
244
|
-
.join(' | ')}`;
|
|
303
|
+
fixDelegatePayloadType(typeAlias, delegateInfo, source) {
|
|
304
|
+
// change the type of `$<DelegateModel>Payload` type of delegate model to a union of concrete types
|
|
305
|
+
const typeName = typeAlias.getName();
|
|
306
|
+
const payloadRecord = delegateInfo.find(([delegate]) => `$${delegate.name}Payload` === typeName);
|
|
307
|
+
if (payloadRecord) {
|
|
308
|
+
const discriminatorDecl = this.getDiscriminatorField(payloadRecord[0]);
|
|
309
|
+
if (discriminatorDecl) {
|
|
310
|
+
source = `${payloadRecord[1]
|
|
311
|
+
.map((concrete) => `($${concrete.name}Payload<ExtArgs> & { scalars: { ${discriminatorDecl.name}: '${concrete.name}' } })`)
|
|
312
|
+
.join(' | ')}`;
|
|
313
|
+
}
|
|
245
314
|
}
|
|
315
|
+
return source;
|
|
246
316
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
317
|
+
removeCreateFromDelegateInput(typeAlias, delegateModels, source) {
|
|
318
|
+
// remove create/connectOrCreate/upsert fields from delegate's input types because
|
|
319
|
+
// delegate models cannot be created directly
|
|
320
|
+
const typeName = typeAlias.getName();
|
|
321
|
+
const delegateModelNames = delegateModels.map(([delegate]) => delegate.name);
|
|
322
|
+
const delegateCreateUpdateInputRegex = new RegExp(`\\${delegateModelNames.join('|')}(Unchecked)?(Create|Update).*Input`);
|
|
323
|
+
if (delegateCreateUpdateInputRegex.test(typeName)) {
|
|
324
|
+
const toRemove = typeAlias
|
|
325
|
+
.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertySignature)
|
|
326
|
+
.filter((p) => ['create', 'connectOrCreate', 'upsert'].includes(p.getName()));
|
|
327
|
+
toRemove.forEach((r) => {
|
|
328
|
+
source = source.replace(r.getText(), '');
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
return source;
|
|
262
332
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
333
|
+
removeDiscriminatorFromConcreteInput(typeAlias, delegateInfo, source) {
|
|
334
|
+
// remove discriminator field from the create/update input of concrete models because
|
|
335
|
+
// discriminator cannot be set directly
|
|
336
|
+
const typeName = typeAlias.getName();
|
|
337
|
+
const concreteModelNames = delegateInfo.map(([, concretes]) => concretes.map((c) => c.name)).flatMap((c) => c);
|
|
338
|
+
const concreteCreateUpdateInputRegex = new RegExp(`(${concreteModelNames.join('|')})(Unchecked)?(Create|Update).*Input`);
|
|
339
|
+
const match = typeName.match(concreteCreateUpdateInputRegex);
|
|
340
|
+
if (match) {
|
|
341
|
+
const modelName = match[1];
|
|
342
|
+
const record = delegateInfo.find(([, concretes]) => concretes.some((c) => c.name === modelName));
|
|
343
|
+
if (record) {
|
|
344
|
+
// remove all discriminator fields recursively
|
|
345
|
+
const delegateOfConcrete = record[0];
|
|
346
|
+
const discriminators = this.getDiscriminatorFieldsRecursively(delegateOfConcrete);
|
|
347
|
+
discriminators.forEach((discriminatorDecl) => {
|
|
348
|
+
const discriminatorNode = this.findNamedProperty(typeAlias, discriminatorDecl.name);
|
|
349
|
+
if (discriminatorNode) {
|
|
350
|
+
source = source.replace(discriminatorNode.getText(), '');
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return source;
|
|
356
|
+
}
|
|
357
|
+
removeAuxFieldsFromTypeAlias(typeAlias, source) {
|
|
358
|
+
// remove `delegate_aux_*` fields from the type alias
|
|
359
|
+
const auxDecls = this.findAuxDecls(typeAlias);
|
|
360
|
+
if (auxDecls.length > 0) {
|
|
361
|
+
auxDecls.forEach((d) => {
|
|
362
|
+
source = source.replace(d.getText(), '');
|
|
284
363
|
});
|
|
285
364
|
}
|
|
365
|
+
return source;
|
|
286
366
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
367
|
+
removeDelegateFieldsFromNestedMutationInput(typeAlias, _delegateInfo, source) {
|
|
368
|
+
const name = typeAlias.getName();
|
|
369
|
+
// remove delegate model fields (and corresponding fk fields) from
|
|
370
|
+
// create/update input types nested inside concrete models
|
|
371
|
+
const regex = new RegExp(`(.+)(Create|Update)Without${(0, upper_case_first_1.upperCaseFirst)(runtime_1.DELEGATE_AUX_RELATION_PREFIX)}_(.+)Input`);
|
|
372
|
+
const match = name.match(regex);
|
|
373
|
+
if (!match) {
|
|
374
|
+
return source;
|
|
375
|
+
}
|
|
376
|
+
const nameTuple = match[3]; // [modelName]_[relationFieldName]_[concreteModelName]
|
|
377
|
+
const [modelName, relationFieldName, _] = nameTuple.split('_');
|
|
378
|
+
const fieldDef = this.findNamedProperty(typeAlias, relationFieldName);
|
|
379
|
+
if (fieldDef) {
|
|
380
|
+
// remove relation field of delegate type, e.g., `asset`
|
|
381
|
+
source = source.replace(fieldDef.getText(), '');
|
|
382
|
+
}
|
|
383
|
+
// remove fk fields related to the delegate type relation, e.g., `assetId`
|
|
384
|
+
const relationModel = this.model.declarations.find((d) => (0, ast_1.isDataModel)(d) && d.name === modelName);
|
|
385
|
+
if (!relationModel) {
|
|
386
|
+
return source;
|
|
387
|
+
}
|
|
388
|
+
const relationField = relationModel.fields.find((f) => f.name === relationFieldName);
|
|
389
|
+
if (!relationField) {
|
|
390
|
+
return source;
|
|
391
|
+
}
|
|
392
|
+
const relAttr = (0, sdk_1.getAttribute)(relationField, '@relation');
|
|
393
|
+
if (!relAttr) {
|
|
394
|
+
return source;
|
|
395
|
+
}
|
|
396
|
+
const fieldsArg = (0, sdk_1.getAttributeArg)(relAttr, 'fields');
|
|
397
|
+
let fkFields = [];
|
|
398
|
+
if ((0, ast_1.isArrayExpr)(fieldsArg)) {
|
|
399
|
+
fkFields = fieldsArg.items.map((e) => e.target.$refText);
|
|
400
|
+
}
|
|
401
|
+
fkFields.forEach((fkField) => {
|
|
402
|
+
const fieldDef = this.findNamedProperty(typeAlias, fkField);
|
|
403
|
+
if (fieldDef) {
|
|
404
|
+
source = source.replace(fieldDef.getText(), '');
|
|
405
|
+
}
|
|
295
406
|
});
|
|
407
|
+
return source;
|
|
296
408
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
function findNamedProperty(typeAlias, name) {
|
|
300
|
-
return typeAlias.getFirstDescendant((d) => d.isKind(ts_morph_1.SyntaxKind.PropertySignature) && d.getName() === name);
|
|
301
|
-
}
|
|
302
|
-
function findAuxDecls(node) {
|
|
303
|
-
return node
|
|
304
|
-
.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertySignature)
|
|
305
|
-
.filter((n) => n.getName().startsWith(runtime_1.DELEGATE_AUX_RELATION_PREFIX));
|
|
306
|
-
}
|
|
307
|
-
function getDiscriminatorField(delegate) {
|
|
308
|
-
var _a;
|
|
309
|
-
const delegateAttr = (0, sdk_1.getAttribute)(delegate, '@@delegate');
|
|
310
|
-
if (!delegateAttr) {
|
|
311
|
-
return undefined;
|
|
409
|
+
findNamedProperty(typeAlias, name) {
|
|
410
|
+
return typeAlias.getFirstDescendant((d) => d.isKind(ts_morph_1.SyntaxKind.PropertySignature) && d.getName() === name);
|
|
312
411
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
412
|
+
findAuxDecls(node) {
|
|
413
|
+
return node
|
|
414
|
+
.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertySignature)
|
|
415
|
+
.filter((n) => n.getName().startsWith(runtime_1.DELEGATE_AUX_RELATION_PREFIX));
|
|
416
|
+
}
|
|
417
|
+
getDiscriminatorField(delegate) {
|
|
418
|
+
var _a;
|
|
419
|
+
const delegateAttr = (0, sdk_1.getAttribute)(delegate, '@@delegate');
|
|
420
|
+
if (!delegateAttr) {
|
|
421
|
+
return undefined;
|
|
321
422
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
423
|
+
const arg = (_a = delegateAttr.args[0]) === null || _a === void 0 ? void 0 : _a.value;
|
|
424
|
+
return (0, ast_1.isReferenceExpr)(arg) ? arg.target.ref : undefined;
|
|
425
|
+
}
|
|
426
|
+
getDiscriminatorFieldsRecursively(delegate, result = []) {
|
|
427
|
+
if ((0, sdk_1.isDelegateModel)(delegate)) {
|
|
428
|
+
const discriminator = this.getDiscriminatorField(delegate);
|
|
429
|
+
if (discriminator) {
|
|
430
|
+
result.push(discriminator);
|
|
431
|
+
}
|
|
432
|
+
for (const superType of delegate.superTypes) {
|
|
433
|
+
if (superType.ref) {
|
|
434
|
+
result.push(...this.getDiscriminatorFieldsRecursively(superType.ref, result));
|
|
435
|
+
}
|
|
325
436
|
}
|
|
326
437
|
}
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
440
|
+
saveSourceFile(sf) {
|
|
441
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
442
|
+
if (this.options.preserveTsFiles) {
|
|
443
|
+
yield sf.save();
|
|
444
|
+
}
|
|
445
|
+
});
|
|
327
446
|
}
|
|
328
|
-
return result;
|
|
329
|
-
}
|
|
330
|
-
function saveSourceFile(sf, options) {
|
|
331
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
332
|
-
if (options.preserveTsFiles) {
|
|
333
|
-
yield sf.save();
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
447
|
}
|
|
448
|
+
exports.EnhancerGenerator = EnhancerGenerator;
|
|
337
449
|
//# sourceMappingURL=index.js.map
|