prisma-guard 1.23.0 → 1.25.0

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.
@@ -2,8 +2,34 @@
2
2
 
3
3
  // src/generator/index.ts
4
4
  import pkg from "@prisma/generator-helper";
5
- import { writeFileSync, mkdirSync } from "fs";
6
- import { join } from "path";
5
+ import { mkdirSync, writeFileSync } from "fs";
6
+ import { relative } from "path";
7
+
8
+ // src/generator/emit-client.ts
9
+ function emitClient(_dmmf, prismaClientImport) {
10
+ return `import type { PrismaClient } from '${prismaClientImport}'
11
+ import type { GuardInput, GuardedModel } from 'prisma-guard'
12
+ import { createGuard } from 'prisma-guard'
13
+ import { SCOPE_MAP, TYPE_MAP, ENUM_MAP, ZOD_CHAINS, GUARD_CONFIG, UNIQUE_MAP, ZOD_DEFAULTS } from './index'
14
+ import type { ScopeRoot } from './index'
15
+
16
+ interface GuardModelExtension {
17
+ $allModels: {
18
+ guard<TDelegate>(this: TDelegate, input: GuardInput, caller?: string): GuardedModel<TDelegate>
19
+ }
20
+ }
21
+
22
+ export const guard = createGuard<typeof TYPE_MAP, ScopeRoot, GuardModelExtension>({
23
+ scopeMap: SCOPE_MAP,
24
+ typeMap: TYPE_MAP,
25
+ enumMap: ENUM_MAP,
26
+ zodChains: ZOD_CHAINS,
27
+ guardConfig: GUARD_CONFIG,
28
+ uniqueMap: UNIQUE_MAP,
29
+ zodDefaults: ZOD_DEFAULTS,
30
+ })
31
+ `;
32
+ }
7
33
 
8
34
  // src/generator/emit-scope-map.ts
9
35
  function isScopeRoot(documentation) {
@@ -94,6 +120,212 @@ export type ScopeRoot = ${scopeRootType}
94
120
  return { source };
95
121
  }
96
122
 
123
+ // src/generator/emit-type-map.ts
124
+ function uniqueSelector(fields, name) {
125
+ if (typeof name === "string" && name.trim().length > 0)
126
+ return name;
127
+ return fields.join("_");
128
+ }
129
+ function collectUniqueConstraints(model) {
130
+ const fieldSetSeen = /* @__PURE__ */ new Set();
131
+ const selectorToFields = /* @__PURE__ */ new Map();
132
+ const constraints = [];
133
+ function fieldsKey(fields) {
134
+ return fields.join("\0");
135
+ }
136
+ function add(fields, selector) {
137
+ if (fields.length === 0)
138
+ return;
139
+ const normalizedSelector = fields.length === 1 ? fields[0] : uniqueSelector(fields, selector);
140
+ const key = fieldsKey(fields);
141
+ const existingFieldsForSelector = selectorToFields.get(normalizedSelector);
142
+ if (existingFieldsForSelector && existingFieldsForSelector !== key) {
143
+ throw new Error(
144
+ `prisma-guard: Unique selector "${normalizedSelector}" on model "${model.name}" maps to multiple field sets.`
145
+ );
146
+ }
147
+ if (fieldSetSeen.has(key))
148
+ return;
149
+ fieldSetSeen.add(key);
150
+ selectorToFields.set(normalizedSelector, key);
151
+ constraints.push({
152
+ selector: normalizedSelector,
153
+ fields: [...fields]
154
+ });
155
+ }
156
+ for (const field of model.fields) {
157
+ if (field.isId)
158
+ add([field.name], field.name);
159
+ }
160
+ if (model.primaryKey) {
161
+ add([...model.primaryKey.fields], model.primaryKey.name);
162
+ }
163
+ for (const field of model.fields) {
164
+ if (field.isUnique)
165
+ add([field.name], field.name);
166
+ }
167
+ const uniqueIndexes = model.uniqueIndexes ?? [];
168
+ for (const index of uniqueIndexes) {
169
+ add([...index.fields], index.name);
170
+ }
171
+ for (const fields of model.uniqueFields) {
172
+ add([...fields], fields.length === 1 ? fields[0] : fields.join("_"));
173
+ }
174
+ return constraints;
175
+ }
176
+ function emitTypeMap(dmmf) {
177
+ const enumNames = new Set(dmmf.datamodel.enums.map((e) => e.name));
178
+ for (const e of dmmf.datamodel.enums) {
179
+ if (e.values.length === 0) {
180
+ throw new Error(`prisma-guard: Enum "${e.name}" has zero values.`);
181
+ }
182
+ }
183
+ const modelEntries = dmmf.datamodel.models.map((model) => {
184
+ const fieldEntries = model.fields.map((field) => {
185
+ const isRelation = field.kind === "object" || field.relationName != null;
186
+ const isEnum = enumNames.has(field.type);
187
+ const isUnsupported = field.kind === "unsupported";
188
+ const meta = [
189
+ `type: ${JSON.stringify(field.type)}`,
190
+ `isList: ${field.isList}`,
191
+ `isRequired: ${field.isRequired}`,
192
+ `isId: ${field.isId}`,
193
+ `isRelation: ${isRelation}`,
194
+ `hasDefault: ${field.hasDefaultValue}`,
195
+ `isUpdatedAt: ${field.isUpdatedAt}`
196
+ ];
197
+ if (isEnum)
198
+ meta.push(`isEnum: true`);
199
+ if (isUnsupported)
200
+ meta.push(`isUnsupported: true`);
201
+ if (field.isUnique)
202
+ meta.push(`isUnique: true`);
203
+ return ` ${JSON.stringify(field.name)}: { ${meta.join(", ")} },`;
204
+ }).join("\n");
205
+ return ` ${JSON.stringify(model.name)}: {
206
+ ${fieldEntries}
207
+ },`;
208
+ }).join("\n");
209
+ const enumEntries = dmmf.datamodel.enums.map((e) => {
210
+ const values = e.values.map((v) => JSON.stringify(v.name)).join(", ");
211
+ return ` ${JSON.stringify(e.name)}: [${values}],`;
212
+ }).join("\n");
213
+ const uniqueMapEntries = dmmf.datamodel.models.map((model) => {
214
+ const constraints = collectUniqueConstraints(model);
215
+ if (constraints.length === 0)
216
+ return null;
217
+ const constraintsStr = constraints.map((c) => {
218
+ const fields = c.fields.map((f) => JSON.stringify(f)).join(", ");
219
+ return `{ selector: ${JSON.stringify(c.selector)}, fields: [${fields}] }`;
220
+ }).join(", ");
221
+ return ` ${JSON.stringify(model.name)}: [${constraintsStr}],`;
222
+ }).filter(Boolean).join("\n");
223
+ const typeMapSource = `export const TYPE_MAP = {
224
+ ${modelEntries}
225
+ } as const
226
+ `;
227
+ const enumMapSource = `export const ENUM_MAP = {
228
+ ${enumEntries}
229
+ } as const
230
+ `;
231
+ const uniqueMapSource = `export const UNIQUE_MAP = {
232
+ ${uniqueMapEntries}
233
+ } as const
234
+ `;
235
+ const typesSource = [
236
+ `export type ModelName = keyof typeof TYPE_MAP`,
237
+ `export type FieldName<M extends ModelName> = keyof (typeof TYPE_MAP)[M]`
238
+ ].join("\n");
239
+ return `${typeMapSource}
240
+ ${enumMapSource}
241
+ ${uniqueMapSource}
242
+ ${typesSource}
243
+ `;
244
+ }
245
+
246
+ // src/shared/operation-shape-keys.ts
247
+ var OPERATION_SHAPE_KEYS = {
248
+ findMany: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
249
+ findFirst: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
250
+ findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
251
+ findUnique: ["where", "include", "select"],
252
+ findUniqueOrThrow: ["where", "include", "select"],
253
+ findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
254
+ count: ["where", "select", "cursor", "orderBy", "skip", "take"],
255
+ aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
256
+ groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
257
+ create: ["data", "select", "include"],
258
+ createMany: ["data"],
259
+ createManyAndReturn: ["data", "select", "include"],
260
+ update: ["data", "where", "select", "include"],
261
+ updateMany: ["data", "where"],
262
+ updateManyAndReturn: ["data", "where", "select", "include"],
263
+ upsert: ["where", "create", "update", "select", "include"],
264
+ delete: ["where", "select", "include"],
265
+ deleteMany: ["where"]
266
+ };
267
+ var READ_METHOD_ALLOWED_ARGS = {
268
+ findMany: new Set(OPERATION_SHAPE_KEYS.findMany),
269
+ findFirst: new Set(OPERATION_SHAPE_KEYS.findFirst),
270
+ findFirstOrThrow: new Set(OPERATION_SHAPE_KEYS.findFirstOrThrow),
271
+ findUnique: new Set(OPERATION_SHAPE_KEYS.findUnique),
272
+ findUniqueOrThrow: new Set(OPERATION_SHAPE_KEYS.findUniqueOrThrow),
273
+ count: new Set(OPERATION_SHAPE_KEYS.count),
274
+ aggregate: new Set(OPERATION_SHAPE_KEYS.aggregate),
275
+ groupBy: new Set(OPERATION_SHAPE_KEYS.groupBy)
276
+ };
277
+ var MUTATION_SHAPE_KEYS = {
278
+ create: new Set(OPERATION_SHAPE_KEYS.create),
279
+ createMany: new Set(OPERATION_SHAPE_KEYS.createMany),
280
+ createManyAndReturn: new Set(OPERATION_SHAPE_KEYS.createManyAndReturn),
281
+ update: new Set(OPERATION_SHAPE_KEYS.update),
282
+ updateMany: new Set(OPERATION_SHAPE_KEYS.updateMany),
283
+ updateManyAndReturn: new Set(OPERATION_SHAPE_KEYS.updateManyAndReturn),
284
+ upsert: new Set(OPERATION_SHAPE_KEYS.upsert),
285
+ delete: new Set(OPERATION_SHAPE_KEYS.delete),
286
+ deleteMany: new Set(OPERATION_SHAPE_KEYS.deleteMany)
287
+ };
288
+
289
+ // src/generator/emit-typed-shapes.ts
290
+ var OPERATIONS = Object.keys(OPERATION_SHAPE_KEYS);
291
+ function cap(s) {
292
+ return s.charAt(0).toUpperCase() + s.slice(1);
293
+ }
294
+ function emitTypedShapes(dmmf, depth) {
295
+ const header = `import type { TYPE_MAP, UNIQUE_MAP } from './index'
296
+ import type {
297
+ TypedGuardShape,
298
+ OperationShape,
299
+ ShapeInput,
300
+ TypedProjection,
301
+ TypedInclude,
302
+ TypedCountSelect,
303
+ } from 'prisma-guard'
304
+
305
+ type TM = typeof TYPE_MAP
306
+ type UM = typeof UNIQUE_MAP
307
+
308
+ `;
309
+ const blocks = dmmf.datamodel.models.map((model) => {
310
+ const m = model.name;
311
+ const projAlias = `export type ${m}Select = TypedProjection<TM, '${m}', ${depth}, UM>
312
+ export type ${m}Projection = ${m}Select
313
+ export type ${m}Include = TypedInclude<TM, '${m}', ${depth}, UM>
314
+ export type ${m}CountSelect = TypedCountSelect<TM, '${m}'>
315
+ `;
316
+ const guardAlias = `export type ${m}GuardShape = TypedGuardShape<TM, '${m}', ${depth}, UM>
317
+ `;
318
+ const opAliases = OPERATIONS.map((op) => {
319
+ const c = cap(op);
320
+ return `export type ${m}${c}Shape = OperationShape<TM, '${m}', '${op}', ${depth}, UM>
321
+ export type ${m}${c}ShapeInput<TCtx = unknown> = ShapeInput<${m}${c}Shape, TCtx>
322
+ `;
323
+ }).join("");
324
+ return projAlias + guardAlias + opAliases;
325
+ }).join("\n");
326
+ return header + blocks;
327
+ }
328
+
97
329
  // src/generator/emit-zod-chains.ts
98
330
  import { z as z2 } from "zod";
99
331
 
@@ -790,247 +1022,6 @@ ${entries}
790
1022
  };
791
1023
  }
792
1024
 
793
- // src/generator/emit-type-map.ts
794
- function collectUniqueConstraints(model) {
795
- const seen = /* @__PURE__ */ new Set();
796
- const constraints = [];
797
- function add(fields) {
798
- const key = fields.join("\0");
799
- if (seen.has(key))
800
- return;
801
- seen.add(key);
802
- constraints.push(fields);
803
- }
804
- for (const field of model.fields) {
805
- if (field.isId)
806
- add([field.name]);
807
- }
808
- if (model.primaryKey) {
809
- add([...model.primaryKey.fields]);
810
- }
811
- for (const field of model.fields) {
812
- if (field.isUnique)
813
- add([field.name]);
814
- }
815
- for (const fields of model.uniqueFields) {
816
- add([...fields]);
817
- }
818
- return constraints;
819
- }
820
- function emitTypeMap(dmmf) {
821
- const enumNames = new Set(dmmf.datamodel.enums.map((e) => e.name));
822
- for (const e of dmmf.datamodel.enums) {
823
- if (e.values.length === 0) {
824
- throw new Error(`prisma-guard: Enum "${e.name}" has zero values.`);
825
- }
826
- }
827
- const modelEntries = dmmf.datamodel.models.map((model) => {
828
- const fieldEntries = model.fields.map((field) => {
829
- const isRelation = field.kind === "object" || field.relationName != null;
830
- const isEnum = enumNames.has(field.type);
831
- const isUnsupported = field.kind === "unsupported";
832
- const meta = [
833
- `type: ${JSON.stringify(field.type)}`,
834
- `isList: ${field.isList}`,
835
- `isRequired: ${field.isRequired}`,
836
- `isId: ${field.isId}`,
837
- `isRelation: ${isRelation}`,
838
- `hasDefault: ${field.hasDefaultValue}`,
839
- `isUpdatedAt: ${field.isUpdatedAt}`
840
- ];
841
- if (isEnum)
842
- meta.push(`isEnum: true`);
843
- if (isUnsupported)
844
- meta.push(`isUnsupported: true`);
845
- if (field.isUnique)
846
- meta.push(`isUnique: true`);
847
- return ` ${JSON.stringify(field.name)}: { ${meta.join(", ")} },`;
848
- }).join("\n");
849
- return ` ${JSON.stringify(model.name)}: {
850
- ${fieldEntries}
851
- },`;
852
- }).join("\n");
853
- const enumEntries = dmmf.datamodel.enums.map((e) => {
854
- const values = e.values.map((v) => JSON.stringify(v.name)).join(", ");
855
- return ` ${JSON.stringify(e.name)}: [${values}],`;
856
- }).join("\n");
857
- const uniqueMapEntries = dmmf.datamodel.models.map((model) => {
858
- const constraints = collectUniqueConstraints(model);
859
- if (constraints.length === 0)
860
- return null;
861
- const constraintsStr = constraints.map((c) => `[${c.map((f) => JSON.stringify(f)).join(", ")}]`).join(", ");
862
- return ` ${JSON.stringify(model.name)}: [${constraintsStr}],`;
863
- }).filter(Boolean).join("\n");
864
- const typeMapSource = `export const TYPE_MAP = {
865
- ${modelEntries}
866
- } as const
867
- `;
868
- const enumMapSource = `export const ENUM_MAP = {
869
- ${enumEntries}
870
- } as const
871
- `;
872
- const uniqueMapSource = `export const UNIQUE_MAP = {
873
- ${uniqueMapEntries}
874
- } as const
875
- `;
876
- const typesSource = [
877
- `export type ModelName = keyof typeof TYPE_MAP`,
878
- `export type FieldName<M extends ModelName> = keyof (typeof TYPE_MAP)[M]`
879
- ].join("\n");
880
- return `${typeMapSource}
881
- ${enumMapSource}
882
- ${uniqueMapSource}
883
- ${typesSource}
884
- `;
885
- }
886
-
887
- // src/shared/constants.ts
888
- var SHAPE_CONFIG_KEY_LIST = [
889
- "where",
890
- "include",
891
- "select",
892
- "orderBy",
893
- "cursor",
894
- "take",
895
- "skip",
896
- "distinct",
897
- "having",
898
- "_count",
899
- "_avg",
900
- "_sum",
901
- "_min",
902
- "_max",
903
- "by"
904
- ];
905
- var SHAPE_CONFIG_KEYS = new Set(SHAPE_CONFIG_KEY_LIST);
906
- var GUARD_SHAPE_KEY_LIST = [
907
- "data",
908
- "create",
909
- "update",
910
- ...SHAPE_CONFIG_KEY_LIST
911
- ];
912
- var GUARD_SHAPE_KEYS = new Set(GUARD_SHAPE_KEY_LIST);
913
- var TO_MANY_RELATION_OPS = /* @__PURE__ */ new Set(["some", "every", "none"]);
914
- var TO_ONE_RELATION_OPS = /* @__PURE__ */ new Set(["is", "isNot"]);
915
- var ALL_RELATION_OPS = /* @__PURE__ */ new Set([...TO_MANY_RELATION_OPS, ...TO_ONE_RELATION_OPS]);
916
- function toDelegateKey(modelName) {
917
- return modelName[0].toLowerCase() + modelName.slice(1);
918
- }
919
- var FORCED_MARKER = Symbol.for("prisma-guard.forced");
920
- var UNSUPPORTED_MARKER = Symbol.for("prisma-guard.unsupported");
921
-
922
- // src/generator/emit-client.ts
923
- function emitClient(dmmf) {
924
- const modelEntries = dmmf.datamodel.models.map((model) => {
925
- const key = toDelegateKey(model.name);
926
- return ` ${key}: {
927
- guard(input: GuardInput, caller?: string): GuardedModel<PrismaClient['${key}']>
928
- }`;
929
- }).join("\n");
930
- return `import type { PrismaClient } from '@prisma/client'
931
- import type { GuardInput, GuardedModel } from 'prisma-guard'
932
- import { createGuard } from 'prisma-guard'
933
- import { SCOPE_MAP, TYPE_MAP, ENUM_MAP, ZOD_CHAINS, GUARD_CONFIG, UNIQUE_MAP, ZOD_DEFAULTS } from './index'
934
- import type { ScopeRoot } from './index'
935
-
936
- interface GuardModelExtension {
937
- ${modelEntries}
938
- }
939
-
940
- export const guard = createGuard<typeof TYPE_MAP, ScopeRoot, GuardModelExtension>({
941
- scopeMap: SCOPE_MAP,
942
- typeMap: TYPE_MAP,
943
- enumMap: ENUM_MAP,
944
- zodChains: ZOD_CHAINS,
945
- guardConfig: GUARD_CONFIG,
946
- uniqueMap: UNIQUE_MAP,
947
- zodDefaults: ZOD_DEFAULTS,
948
- })
949
- `;
950
- }
951
-
952
- // src/shared/operation-shape-keys.ts
953
- var OPERATION_SHAPE_KEYS = {
954
- findMany: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
955
- findFirst: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
956
- findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
957
- findUnique: ["where", "include", "select"],
958
- findUniqueOrThrow: ["where", "include", "select"],
959
- findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
960
- count: ["where", "select", "cursor", "orderBy", "skip", "take"],
961
- aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
962
- groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
963
- create: ["data", "select", "include"],
964
- createMany: ["data"],
965
- createManyAndReturn: ["data", "select", "include"],
966
- update: ["data", "where", "select", "include"],
967
- updateMany: ["data", "where"],
968
- updateManyAndReturn: ["data", "where", "select", "include"],
969
- upsert: ["where", "create", "update", "select", "include"],
970
- delete: ["where", "select", "include"],
971
- deleteMany: ["where"]
972
- };
973
- var READ_METHOD_ALLOWED_ARGS = {
974
- findMany: new Set(OPERATION_SHAPE_KEYS.findMany),
975
- findFirst: new Set(OPERATION_SHAPE_KEYS.findFirst),
976
- findFirstOrThrow: new Set(OPERATION_SHAPE_KEYS.findFirstOrThrow),
977
- findUnique: new Set(OPERATION_SHAPE_KEYS.findUnique),
978
- findUniqueOrThrow: new Set(OPERATION_SHAPE_KEYS.findUniqueOrThrow),
979
- count: new Set(OPERATION_SHAPE_KEYS.count),
980
- aggregate: new Set(OPERATION_SHAPE_KEYS.aggregate),
981
- groupBy: new Set(OPERATION_SHAPE_KEYS.groupBy)
982
- };
983
- var MUTATION_SHAPE_KEYS = {
984
- create: new Set(OPERATION_SHAPE_KEYS.create),
985
- createMany: new Set(OPERATION_SHAPE_KEYS.createMany),
986
- createManyAndReturn: new Set(OPERATION_SHAPE_KEYS.createManyAndReturn),
987
- update: new Set(OPERATION_SHAPE_KEYS.update),
988
- updateMany: new Set(OPERATION_SHAPE_KEYS.updateMany),
989
- updateManyAndReturn: new Set(OPERATION_SHAPE_KEYS.updateManyAndReturn),
990
- upsert: new Set(OPERATION_SHAPE_KEYS.upsert),
991
- delete: new Set(OPERATION_SHAPE_KEYS.delete),
992
- deleteMany: new Set(OPERATION_SHAPE_KEYS.deleteMany)
993
- };
994
-
995
- // src/generator/emit-typed-shapes.ts
996
- var OPERATIONS = Object.keys(OPERATION_SHAPE_KEYS);
997
- function cap(s) {
998
- return s.charAt(0).toUpperCase() + s.slice(1);
999
- }
1000
- function emitTypedShapes(dmmf, depth) {
1001
- const header = `import type { TYPE_MAP } from './index'
1002
- import type {
1003
- TypedGuardShape,
1004
- OperationShape,
1005
- ShapeInput,
1006
- TypedProjection,
1007
- TypedInclude,
1008
- TypedCountSelect,
1009
- } from 'prisma-guard'
1010
-
1011
- type TM = typeof TYPE_MAP
1012
-
1013
- `;
1014
- const blocks = dmmf.datamodel.models.map((model) => {
1015
- const m = model.name;
1016
- const projAlias = `export type ${m}Select = TypedProjection<TM, '${m}', ${depth}>
1017
- export type ${m}Projection = ${m}Select
1018
- export type ${m}Include = TypedInclude<TM, '${m}', ${depth}>
1019
- export type ${m}CountSelect = TypedCountSelect<TM, '${m}'>
1020
- `;
1021
- const guardAlias = `export type ${m}GuardShape = TypedGuardShape<TM, '${m}', ${depth}>
1022
- `;
1023
- const opAliases = OPERATIONS.map((op) => {
1024
- const c = cap(op);
1025
- return `export type ${m}${c}Shape = OperationShape<TM, '${m}', '${op}', ${depth}>
1026
- export type ${m}${c}ShapeInput<TCtx = unknown> = ShapeInput<${m}${c}Shape, TCtx>
1027
- `;
1028
- }).join("");
1029
- return projAlias + guardAlias + opAliases;
1030
- }).join("\n");
1031
- return header + blocks;
1032
- }
1033
-
1034
1025
  // src/generator/index.ts
1035
1026
  var { generatorHandler } = pkg;
1036
1027
  var VALID_ON_INVALID_ZOD = /* @__PURE__ */ new Set(["error", "warn"]);
@@ -1073,7 +1064,7 @@ function emitZodDefaults(defaults) {
1073
1064
  `;
1074
1065
  }
1075
1066
  const mapEntries = entries.map(([model, fields]) => {
1076
- const fieldsStr = fields.map((f) => JSON.stringify(f)).join(", ");
1067
+ const fieldsStr = fields.map((field) => JSON.stringify(field)).join(", ");
1077
1068
  return ` ${JSON.stringify(model)}: [${fieldsStr}],`;
1078
1069
  }).join("\n");
1079
1070
  return `export const ZOD_DEFAULTS: Record<string, readonly string[]> = {
@@ -1081,6 +1072,35 @@ ${mapEntries}
1081
1072
  }
1082
1073
  `;
1083
1074
  }
1075
+ function getProviderValue(provider) {
1076
+ if (typeof provider === "string")
1077
+ return provider;
1078
+ if (provider && typeof provider === "object" && "value" in provider) {
1079
+ const value = provider.value;
1080
+ if (typeof value === "string")
1081
+ return value;
1082
+ }
1083
+ return "";
1084
+ }
1085
+ function isPrismaClientProvider(provider) {
1086
+ const value = getProviderValue(provider);
1087
+ return value === "prisma-client-js" || value.endsWith("/prisma-client-js");
1088
+ }
1089
+ function normalizeImportPath(path) {
1090
+ const normalized = path.replace(/\\/g, "/");
1091
+ if (normalized.startsWith("."))
1092
+ return normalized;
1093
+ return `./${normalized}`;
1094
+ }
1095
+ function resolvePrismaClientImport(options, guardOutput) {
1096
+ const prismaClientGenerator = options.otherGenerators.find(
1097
+ (generator) => isPrismaClientProvider(generator.provider)
1098
+ );
1099
+ const clientOutput = prismaClientGenerator?.output?.value;
1100
+ if (!clientOutput)
1101
+ return "@prisma/client";
1102
+ return normalizeImportPath(relative(guardOutput, clientOutput));
1103
+ }
1084
1104
  generatorHandler({
1085
1105
  onManifest() {
1086
1106
  return {
@@ -1093,15 +1113,49 @@ generatorHandler({
1093
1113
  if (!output)
1094
1114
  throw new Error("prisma-guard: No output directory specified");
1095
1115
  const config = options.generator.config ?? {};
1096
- const onInvalidZod = validateConfigEnum("onInvalidZod", config.onInvalidZod ?? "error", VALID_ON_INVALID_ZOD);
1097
- const onAmbiguousScope = validateConfigEnum("onAmbiguousScope", config.onAmbiguousScope ?? "error", VALID_ON_AMBIGUOUS_SCOPE);
1098
- const onMissingScopeContext = validateConfigEnum("onMissingScopeContext", config.onMissingScopeContext ?? "error", VALID_ON_MISSING_SCOPE_CONTEXT);
1099
- const findUniqueMode = validateConfigEnum("findUniqueMode", config.findUniqueMode ?? "reject", VALID_FIND_UNIQUE_MODE);
1100
- const onScopeRelationWrite = validateConfigEnum("onScopeRelationWrite", config.onScopeRelationWrite ?? "error", VALID_ON_SCOPE_RELATION_WRITE);
1101
- const strictDecimal = validateBooleanConfig("strictDecimal", config.strictDecimal, false);
1102
- const enforceProjection = validateBooleanConfig("enforceProjection", config.enforceProjection, false);
1103
- const typedGuardShapes = validateBooleanConfig("typedGuardShapes", config.typedGuardShapes, true);
1104
- const typedGuardRelationDepth = validateDepthConfig(config.typedGuardRelationDepth);
1116
+ const onInvalidZod = validateConfigEnum(
1117
+ "onInvalidZod",
1118
+ config.onInvalidZod ?? "error",
1119
+ VALID_ON_INVALID_ZOD
1120
+ );
1121
+ const onAmbiguousScope = validateConfigEnum(
1122
+ "onAmbiguousScope",
1123
+ config.onAmbiguousScope ?? "error",
1124
+ VALID_ON_AMBIGUOUS_SCOPE
1125
+ );
1126
+ const onMissingScopeContext = validateConfigEnum(
1127
+ "onMissingScopeContext",
1128
+ config.onMissingScopeContext ?? "error",
1129
+ VALID_ON_MISSING_SCOPE_CONTEXT
1130
+ );
1131
+ const findUniqueMode = validateConfigEnum(
1132
+ "findUniqueMode",
1133
+ config.findUniqueMode ?? "reject",
1134
+ VALID_FIND_UNIQUE_MODE
1135
+ );
1136
+ const onScopeRelationWrite = validateConfigEnum(
1137
+ "onScopeRelationWrite",
1138
+ config.onScopeRelationWrite ?? "error",
1139
+ VALID_ON_SCOPE_RELATION_WRITE
1140
+ );
1141
+ const strictDecimal = validateBooleanConfig(
1142
+ "strictDecimal",
1143
+ config.strictDecimal,
1144
+ false
1145
+ );
1146
+ const enforceProjection = validateBooleanConfig(
1147
+ "enforceProjection",
1148
+ config.enforceProjection,
1149
+ false
1150
+ );
1151
+ const typedGuardShapes = validateBooleanConfig(
1152
+ "typedGuardShapes",
1153
+ config.typedGuardShapes,
1154
+ true
1155
+ );
1156
+ const typedGuardRelationDepth = validateDepthConfig(
1157
+ config.typedGuardRelationDepth
1158
+ );
1105
1159
  const dmmf = options.dmmf;
1106
1160
  const parts = [];
1107
1161
  parts.push(
@@ -1122,12 +1176,13 @@ generatorHandler({
1122
1176
  parts.push(zodChainsSource);
1123
1177
  parts.push(emitZodDefaults(defaults));
1124
1178
  mkdirSync(output, { recursive: true });
1125
- writeFileSync(join(output, "index.ts"), parts.join("\n"), "utf-8");
1126
- const clientSource = emitClient(dmmf);
1127
- writeFileSync(join(output, "client.ts"), clientSource, "utf-8");
1179
+ writeFileSync(`${output}/index.ts`, parts.join("\n"), "utf-8");
1180
+ const prismaClientImport = resolvePrismaClientImport(options, output);
1181
+ const clientSource = emitClient(dmmf, prismaClientImport);
1182
+ writeFileSync(`${output}/client.ts`, clientSource, "utf-8");
1128
1183
  if (typedGuardShapes) {
1129
1184
  writeFileSync(
1130
- join(output, "shapes.ts"),
1185
+ `${output}/shapes.ts`,
1131
1186
  emitTypedShapes(dmmf, typedGuardRelationDepth),
1132
1187
  "utf-8"
1133
1188
  );