prisma-arktype 2.2.0 → 2.4.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.
Files changed (3) hide show
  1. package/README.md +155 -14
  2. package/dist/index.js +229 -43
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -86,16 +86,18 @@ generator prisma-arktype {
86
86
 
87
87
  For each model, the generator creates multiple schema types:
88
88
 
89
- - **`ModelPlain`** - Fields without relationships
90
- - **`ModelRelations`** - Relationship definitions only
91
- - **`Model`** - Complete composite schema (Plain & Relations)
92
- - **`ModelWhere`** - Where clause schema
93
- - **`ModelWhereUnique`** - Unique where clause schema
94
- - **`ModelCreate`** - Create input schema
95
- - **`ModelUpdate`** - Update input schema
96
- - **`ModelSelect`** - Select schema
97
- - **`ModelInclude`** - Include schema
98
- - **`ModelOrderBy`** - OrderBy schema
89
+ - **`ModelPlain`** - Scalar fields only (strings, numbers, dates, enums) - no relations
90
+ - **`ModelRelations`** - Relationship fields only, referencing related model Plain types
91
+ - **`Model`** - Complete composite schema combining Plain & Relations
92
+ - **`ModelWhere`** - Where clause schema for filtering
93
+ - **`ModelWhereUnique`** - Unique where clause schema for finding specific records
94
+ - **`ModelCreate`** - Input schema for creating records
95
+ - **`ModelUpdate`** - Input schema for updating records
96
+ - **`ModelSelect`** - Schema for selecting specific fields
97
+ - **`ModelInclude`** - Schema for including relations
98
+ - **`ModelOrderBy`** - Schema for ordering results
99
+
100
+ **Enums** are generated as separate reusable types that are imported and referenced by models that use them.
99
101
 
100
102
  ### Using Generated Schemas
101
103
 
@@ -130,6 +132,101 @@ const whereResult = UserWhere(whereClause);
130
132
  // ...
131
133
  ```
132
134
 
135
+ ### Generated Code Examples
136
+
137
+ #### Enum Generation
138
+
139
+ For a Prisma enum like:
140
+ ```prisma
141
+ enum Currency {
142
+ USD
143
+ EUR
144
+ GBP
145
+ }
146
+ ```
147
+
148
+ The generator creates a separate reusable type:
149
+ ```typescript
150
+ // Currency.ts
151
+ import { type } from "arktype";
152
+
153
+ export const Currency = type("'USD' | 'EUR' | 'GBP'");
154
+ ```
155
+
156
+ Which is then imported and used in models:
157
+ ```typescript
158
+ // PaymentPlain.ts
159
+ import { type } from "arktype";
160
+ import { Currency } from "./Currency";
161
+
162
+ export const PaymentPlain = type({
163
+ "id": "string",
164
+ "amount": "number",
165
+ "currency": Currency, // Required enum
166
+ "status?": Currency.or("null") // Optional enum
167
+ });
168
+ ```
169
+
170
+ #### Relation Generation
171
+
172
+ For Prisma models with relations like:
173
+ ```prisma
174
+ model User {
175
+ id String @id
176
+ email String
177
+ posts Post[]
178
+ }
179
+
180
+ model Post {
181
+ id String @id
182
+ title String
183
+ author User @relation(fields: [authorId], references: [id])
184
+ authorId String
185
+ }
186
+ ```
187
+
188
+ The generator creates Plain types (without relations):
189
+ ```typescript
190
+ // UserPlain.ts
191
+ export const UserPlain = type({
192
+ "id": "string",
193
+ "email": "string"
194
+ });
195
+
196
+ // PostPlain.ts
197
+ export const PostPlain = type({
198
+ "id": "string",
199
+ "title": "string",
200
+ "authorId": "string"
201
+ });
202
+ ```
203
+
204
+ And Relations types that reference the Plain types:
205
+ ```typescript
206
+ // UserRelations.ts
207
+ import { PostPlain } from "./PostPlain";
208
+
209
+ export const UserRelations = type({
210
+ "posts": PostPlain.array() // Array of Post objects
211
+ });
212
+
213
+ // PostRelations.ts
214
+ import { UserPlain } from "./UserPlain";
215
+
216
+ export const PostRelations = type({
217
+ "author": UserPlain // Single User object
218
+ });
219
+ ```
220
+
221
+ The combined model merges both:
222
+ ```typescript
223
+ // User.ts
224
+ import { UserPlain } from "./UserPlain";
225
+ import { UserRelations } from "./UserRelations";
226
+
227
+ export const User = type(() => UserPlain.and(UserRelations));
228
+ ```
229
+
133
230
  ## Annotations
134
231
 
135
232
  Control schema generation using annotations in your Prisma schema. All annotations are added as documentation comments (`///`).
@@ -142,6 +239,7 @@ Control schema generation using annotations in your Prisma schema. All annotatio
142
239
  | `@prisma-arktype.input.hide` | Field | Hide from Create and Update input schemas |
143
240
  | `@prisma-arktype.create.input.hide` | Field | Hide from Create input schema only |
144
241
  | `@prisma-arktype.update.input.hide` | Field | Hide from Update input schema only |
242
+ | `@prisma-arktype.schema="<schema>"` | Field | Custom ArkType schema (inline or external) |
145
243
  | `@prisma-arktype.typeOverwrite="<type>"` | Field | Override the generated ArkType type |
146
244
 
147
245
  ### Hide Fields/Models
@@ -204,6 +302,48 @@ model User {
204
302
 
205
303
  This allows you to use any ArkType type definition, including built-in refinements like `string.email`, `string.url`, `number.integer`, etc.
206
304
 
305
+ ### Custom Schemas
306
+
307
+ Bring your own ArkType schemas for any field using `@prisma-arktype.schema`:
308
+
309
+ ```prisma
310
+ model User {
311
+ id String @id
312
+
313
+ /// Inline schema for structured JSON
314
+ /// @prisma-arktype.schema="{ name: 'string', age: 'number' }"
315
+ profile Json
316
+
317
+ /// External schema from a file (named export)
318
+ /// @prisma-arktype.schema="../schemas/address:AddressSchema"
319
+ address Json
320
+
321
+ /// External schema (default export)
322
+ /// @prisma-arktype.schema="../schemas/config"
323
+ settings Json
324
+ }
325
+ ```
326
+
327
+ **Import Path Rules:**
328
+ - Paths are relative to the generated validators directory
329
+ - Named exports use colon syntax: `"path:ExportName"`
330
+ - Default exports omit the colon: `"path"`
331
+ - Works with ANY field type (not just Json)
332
+
333
+ **Priority:** `schema` > `typeOverwrite` > default type mapping
334
+
335
+ **Example external schema file** (`schemas/address.ts`):
336
+ ```typescript
337
+ import { type } from "arktype";
338
+
339
+ export const AddressSchema = type({
340
+ street: "string",
341
+ city: "string",
342
+ zipCode: "string",
343
+ country: "string",
344
+ });
345
+ ```
346
+
207
347
  ## Type Mapping
208
348
 
209
349
  Prisma types are mapped to ArkType as follows:
@@ -219,15 +359,16 @@ Prisma types are mapped to ArkType as follows:
219
359
  | `DateTime` | `"Date"` | `"Date"` |
220
360
  | `Json` | `"unknown"` | `"unknown"` |
221
361
  | `Bytes` | `"instanceof Buffer"` | `"instanceof Buffer"` |
222
- | Enums | Union of literal values | `type("'USD' \| 'EUR' \| 'GBP'")` |
223
- | Relations | `"unknown"` | `type("unknown").array()` for lists |
362
+ | Enums | Reference to enum type | `Currency` (imported from `./Currency`) |
363
+ | Relations | Reference to related Plain type | `PostPlain` or `PostPlain.array()` |
224
364
 
225
365
  ### Special Handling
226
366
 
227
367
  - **Optional fields**: Use `?` on the key name (`"name?": "string"`)
228
368
  - **Nullable fields**: Add `| null` to the type (`"string | null"`)
229
- - **Arrays**: Use `.array()` syntax for lists (`type("string").array()`)
230
- - **Enums**: Generated as string literal unions wrapped in `type()`
369
+ - **Arrays**: Use `.array()` syntax for lists (`type("string").array()` or `Currency.array()`)
370
+ - **Enums**: Generated as separate reusable type definitions and imported where used
371
+ - **Relations**: Reference the Plain type of the related model, imported automatically
231
372
 
232
373
  ## Differences from prismabox
233
374
 
package/dist/index.js CHANGED
@@ -43,6 +43,9 @@ function isHiddenInputUpdate(annotation) {
43
43
  function isTypeOverwrite(annotation) {
44
44
  return annotation.type === "TYPE_OVERWRITE";
45
45
  }
46
+ function isSchema(annotation) {
47
+ return annotation.type === "SCHEMA";
48
+ }
46
49
  const annotationKeys = [
47
50
  {
48
51
  keys: ["@prisma-arktype.hide", "@prisma-arktype.hidden"],
@@ -66,9 +69,11 @@ const annotationKeys = [
66
69
  ],
67
70
  type: "HIDDEN_INPUT_UPDATE"
68
71
  },
69
- { keys: ["@prisma-arktype.typeOverwrite"], type: "TYPE_OVERWRITE" }
72
+ { keys: ["@prisma-arktype.typeOverwrite"], type: "TYPE_OVERWRITE" },
73
+ { keys: ["@prisma-arktype.schema"], type: "SCHEMA" }
70
74
  ];
71
75
  const prismaArktypeTypeOverwriteRegex = /@prisma-arktype\.typeOverwrite=(.+)/;
76
+ const prismaArktypeSchemaRegex = /@prisma-arktype\.schema="([^"]+)"/;
72
77
  function extractAnnotations(documentation) {
73
78
  const annotations = [];
74
79
  const descriptionLines = [];
@@ -78,18 +83,52 @@ function extractAnnotations(documentation) {
78
83
  for (const { keys, type } of annotationKeys) {
79
84
  for (const key of keys) {
80
85
  if (line.includes(key)) {
81
- isAnnotation = true;
82
86
  if (type === "TYPE_OVERWRITE") {
83
87
  const match = line.match(prismaArktypeTypeOverwriteRegex);
84
88
  if (match && match[1]) {
89
+ isAnnotation = true;
85
90
  annotations.push({
86
91
  type: "TYPE_OVERWRITE",
87
92
  value: match[1].trim()
88
93
  });
89
- } else {
90
- throw new Error(`Invalid TYPE_OVERWRITE annotation: ${line}`);
94
+ }
95
+ } else if (type === "SCHEMA") {
96
+ const match = line.match(prismaArktypeSchemaRegex);
97
+ if (match && match[1]) {
98
+ isAnnotation = true;
99
+ const schemaValue = match[1].trim();
100
+ const isExternal = schemaValue.includes("/") || !(schemaValue.startsWith("{") || schemaValue.startsWith('"') || schemaValue.startsWith("'")) && schemaValue.includes(":") && // Ensure it's a module:export pattern, not object syntax like { key: value }
101
+ !schemaValue.includes(" ") && !schemaValue.includes(",");
102
+ if (isExternal) {
103
+ const colonIndex = schemaValue.indexOf(":");
104
+ if (colonIndex > 0) {
105
+ const path = schemaValue.substring(0, colonIndex).trim();
106
+ const exportName = schemaValue.substring(colonIndex + 1).trim();
107
+ annotations.push({
108
+ type: "SCHEMA",
109
+ value: schemaValue,
110
+ isExternal: true,
111
+ importPath: path,
112
+ exportName
113
+ });
114
+ } else {
115
+ annotations.push({
116
+ type: "SCHEMA",
117
+ value: schemaValue,
118
+ isExternal: true,
119
+ importPath: schemaValue
120
+ });
121
+ }
122
+ } else {
123
+ annotations.push({
124
+ type: "SCHEMA",
125
+ value: schemaValue,
126
+ isExternal: false
127
+ });
128
+ }
91
129
  }
92
130
  } else {
131
+ isAnnotation = true;
93
132
  annotations.push({ type });
94
133
  }
95
134
  break;
@@ -186,7 +225,8 @@ function processPlain(models) {
186
225
  processedPlain.push({
187
226
  name: model.name,
188
227
  stringified: result.stringified,
189
- enumDependencies: result.enumDependencies
228
+ enumDependencies: result.enumDependencies,
229
+ externalSchemaDependencies: result.externalSchemaDependencies
190
230
  });
191
231
  }
192
232
  }
@@ -202,6 +242,12 @@ function stringifyPlain(model, isInputCreate = false, isInputUpdate = false) {
202
242
  }
203
243
  const fields = [];
204
244
  const enumDependencies = [];
245
+ const externalSchemaDependencies = [];
246
+ function generateUniqueAlias(path, exportName, fieldName) {
247
+ const baseName = exportName || path.split("/").pop()?.replace(/\.(ts|js)$/, "") || "Schema";
248
+ const suffix = fieldName ? `_${fieldName}` : "";
249
+ return `${baseName}${suffix}`;
250
+ }
205
251
  for (const field of model.fields) {
206
252
  const {
207
253
  annotations: fieldAnnotations,
@@ -218,10 +264,36 @@ function stringifyPlain(model, isInputCreate = false, isInputUpdate = false) {
218
264
  if (config.ignoredKeysOnInputModels.includes(field.name)) continue;
219
265
  if (field.name.endsWith("Id") && field.relationName) continue;
220
266
  }
267
+ const schemaAnnotation = fieldAnnotations.find(isSchema);
221
268
  const typeOverwrite = fieldAnnotations.find(isTypeOverwrite);
222
269
  let fieldType;
223
270
  let fieldName = field.name;
224
- if (typeOverwrite) {
271
+ if (schemaAnnotation) {
272
+ if (schemaAnnotation.isExternal) {
273
+ const alias = generateUniqueAlias(
274
+ schemaAnnotation.importPath,
275
+ schemaAnnotation.exportName,
276
+ field.name
277
+ );
278
+ if (!externalSchemaDependencies.some((d) => d.localAlias === alias)) {
279
+ const dependency = {
280
+ importPath: schemaAnnotation.importPath,
281
+ localAlias: alias
282
+ };
283
+ if (schemaAnnotation.exportName) {
284
+ dependency.exportName = schemaAnnotation.exportName;
285
+ }
286
+ externalSchemaDependencies.push(dependency);
287
+ }
288
+ fieldType = alias;
289
+ } else {
290
+ if (schemaAnnotation.value.trim().startsWith("{")) {
291
+ fieldType = schemaAnnotation.value;
292
+ } else {
293
+ fieldType = `"${schemaAnnotation.value}"`;
294
+ }
295
+ }
296
+ } else if (typeOverwrite) {
225
297
  fieldType = typeOverwrite.value;
226
298
  } else if (isPrimitivePrismaFieldType(field.type)) {
227
299
  fieldType = stringifyPrimitiveType(field.type);
@@ -235,16 +307,17 @@ function stringifyPlain(model, isInputCreate = false, isInputUpdate = false) {
235
307
  } else {
236
308
  continue;
237
309
  }
238
- const isEnumType = field.kind === "enum" && !typeOverwrite;
310
+ const isEnumType = field.kind === "enum" && !typeOverwrite && !schemaAnnotation;
311
+ const isExternalSchema = schemaAnnotation?.isExternal === true;
239
312
  if (field.isList) {
240
- if (isEnumType) {
313
+ if (isExternalSchema || isEnumType) {
241
314
  fieldType = `${fieldType}.array()`;
242
315
  } else {
243
316
  fieldType = `"${wrapPrimitiveWithArray(fieldType.slice(1, -1))}"`;
244
317
  }
245
318
  }
246
319
  if (!field.isRequired) {
247
- if (isEnumType) {
320
+ if (isExternalSchema || isEnumType) {
248
321
  fieldType = `${fieldType}.or("null")`;
249
322
  } else {
250
323
  const inner = fieldType.slice(1, -1);
@@ -263,7 +336,8 @@ function stringifyPlain(model, isInputCreate = false, isInputUpdate = false) {
263
336
  stringified: `{
264
337
  ${fields.join(",\n ")}
265
338
  }`,
266
- enumDependencies
339
+ enumDependencies,
340
+ externalSchemaDependencies
267
341
  };
268
342
  }
269
343
  function stringifyPlainInputCreate(model) {
@@ -283,7 +357,8 @@ function processCreate(models) {
283
357
  processedCreate.push({
284
358
  name: model.name,
285
359
  stringified: result.stringified,
286
- enumDependencies: result.enumDependencies
360
+ enumDependencies: result.enumDependencies,
361
+ externalSchemaDependencies: result.externalSchemaDependencies
287
362
  });
288
363
  }
289
364
  }
@@ -364,11 +439,12 @@ const processedRelationsCreate = [];
364
439
  const processedRelationsUpdate = [];
365
440
  function processRelations(models) {
366
441
  for (const model of models) {
367
- const stringified = stringifyRelations(model);
368
- if (stringified) {
442
+ const result = stringifyRelations(model);
443
+ if (result) {
369
444
  processedRelations.push({
370
445
  name: model.name,
371
- stringified
446
+ stringified: result.stringified,
447
+ modelDependencies: result.modelDependencies
372
448
  });
373
449
  }
374
450
  }
@@ -382,26 +458,34 @@ function stringifyRelations(model) {
382
458
  return;
383
459
  }
384
460
  const fields = [];
461
+ const modelDependencies = [];
385
462
  for (const field of model.fields) {
386
463
  const { hidden: fieldHidden } = extractAnnotations(field.documentation);
387
464
  if (fieldHidden) continue;
388
465
  if (field.kind !== "object") continue;
466
+ const relatedModelPlain = `${field.type}Plain`;
467
+ if (!modelDependencies.includes(field.type)) {
468
+ modelDependencies.push(field.type);
469
+ }
389
470
  let fieldType;
390
471
  if (field.isList) {
391
- fieldType = `type("unknown").array()`;
472
+ fieldType = `${relatedModelPlain}.array()`;
392
473
  } else if (!field.isRequired) {
393
- fieldType = `"unknown | null"`;
474
+ fieldType = `${relatedModelPlain}.or("null")`;
394
475
  } else {
395
- fieldType = `"unknown"`;
476
+ fieldType = relatedModelPlain;
396
477
  }
397
478
  fields.push(`"${field.name}": ${fieldType}`);
398
479
  }
399
480
  if (fields.length === 0) {
400
481
  return;
401
482
  }
402
- return `{
483
+ return {
484
+ stringified: `{
403
485
  ${fields.join(",\n ")}
404
- }`;
486
+ }`,
487
+ modelDependencies
488
+ };
405
489
  }
406
490
  function processRelationsCreate(models) {
407
491
  for (const model of models) {
@@ -523,9 +607,7 @@ function processSelect(models) {
523
607
  Object.freeze(processedSelect);
524
608
  }
525
609
  function stringifySelect(model) {
526
- const { hidden } = extractAnnotations(
527
- model.documentation
528
- );
610
+ const { hidden } = extractAnnotations(model.documentation);
529
611
  if (hidden) {
530
612
  return;
531
613
  }
@@ -551,7 +633,8 @@ function processUpdate(models) {
551
633
  processedUpdate.push({
552
634
  name: model.name,
553
635
  stringified: result.stringified,
554
- enumDependencies: result.enumDependencies
636
+ enumDependencies: result.enumDependencies,
637
+ externalSchemaDependencies: result.externalSchemaDependencies
555
638
  });
556
639
  }
557
640
  }
@@ -560,6 +643,7 @@ function processUpdate(models) {
560
643
 
561
644
  const processedWhere = [];
562
645
  const processedWhereUnique = [];
646
+ const extRegex = /\.(ts|js)$/;
563
647
  function processWhere(models) {
564
648
  for (const model of models) {
565
649
  const result = stringifyWhere(model);
@@ -567,7 +651,8 @@ function processWhere(models) {
567
651
  processedWhere.push({
568
652
  name: model.name,
569
653
  stringified: result.stringified,
570
- enumDependencies: result.enumDependencies
654
+ enumDependencies: result.enumDependencies,
655
+ externalSchemaDependencies: result.externalSchemaDependencies
571
656
  });
572
657
  }
573
658
  const uniqueResult = stringifyWhereUnique(model);
@@ -575,7 +660,8 @@ function processWhere(models) {
575
660
  processedWhereUnique.push({
576
661
  name: model.name,
577
662
  stringified: uniqueResult.stringified,
578
- enumDependencies: uniqueResult.enumDependencies
663
+ enumDependencies: uniqueResult.enumDependencies,
664
+ externalSchemaDependencies: uniqueResult.externalSchemaDependencies
579
665
  });
580
666
  }
581
667
  }
@@ -583,21 +669,51 @@ function processWhere(models) {
583
669
  Object.freeze(processedWhereUnique);
584
670
  }
585
671
  function stringifyWhere(model) {
586
- const { hidden } = extractAnnotations(
587
- model.documentation
588
- );
672
+ const { hidden } = extractAnnotations(model.documentation);
589
673
  if (hidden) {
590
674
  return;
591
675
  }
592
676
  const fields = [];
593
677
  const enumDependencies = [];
678
+ const externalSchemaDependencies = [];
679
+ function generateUniqueAlias(path, exportName, fieldName) {
680
+ const baseName = exportName || path.split("/").pop()?.replace(extRegex, "") || "Schema";
681
+ const suffix = fieldName ? `_${fieldName}` : "";
682
+ return `${baseName}${suffix}`;
683
+ }
594
684
  for (const field of model.fields) {
595
685
  const { annotations: fieldAnnotations, hidden: fieldHidden } = extractAnnotations(field.documentation);
596
686
  if (fieldHidden) continue;
597
687
  if (field.kind === "object") continue;
688
+ const schemaAnnotation = fieldAnnotations.find(isSchema);
598
689
  const typeOverwrite = fieldAnnotations.find(isTypeOverwrite);
599
690
  let fieldType;
600
- if (typeOverwrite) {
691
+ if (schemaAnnotation) {
692
+ if (schemaAnnotation.isExternal) {
693
+ const alias = generateUniqueAlias(
694
+ schemaAnnotation.importPath,
695
+ schemaAnnotation.exportName,
696
+ field.name
697
+ );
698
+ if (!externalSchemaDependencies.some((d) => d.localAlias === alias)) {
699
+ const dependency = {
700
+ importPath: schemaAnnotation.importPath,
701
+ localAlias: alias
702
+ };
703
+ if (schemaAnnotation.exportName) {
704
+ dependency.exportName = schemaAnnotation.exportName;
705
+ }
706
+ externalSchemaDependencies.push(dependency);
707
+ }
708
+ fieldType = alias;
709
+ } else {
710
+ if (schemaAnnotation.value.trim().startsWith("{")) {
711
+ fieldType = schemaAnnotation.value;
712
+ } else {
713
+ fieldType = `"${schemaAnnotation.value}"`;
714
+ }
715
+ }
716
+ } else if (typeOverwrite) {
601
717
  fieldType = typeOverwrite.value;
602
718
  } else if (isPrimitivePrismaFieldType(field.type)) {
603
719
  fieldType = stringifyPrimitiveType(field.type);
@@ -611,9 +727,10 @@ function stringifyWhere(model) {
611
727
  } else {
612
728
  continue;
613
729
  }
614
- const isEnumType = field.kind === "enum" && !typeOverwrite;
730
+ const isEnumType = field.kind === "enum" && !typeOverwrite && !schemaAnnotation;
731
+ const isExternalSchema = schemaAnnotation?.isExternal === true;
615
732
  if (field.isList) {
616
- if (isEnumType) {
733
+ if (isExternalSchema || isEnumType) {
617
734
  fieldType = `${fieldType}.array()`;
618
735
  } else {
619
736
  const inner = fieldType.slice(1, -1);
@@ -626,26 +743,57 @@ function stringifyWhere(model) {
626
743
  stringified: `{
627
744
  ${fields.join(",\n ")}
628
745
  }`,
629
- enumDependencies
746
+ enumDependencies,
747
+ externalSchemaDependencies
630
748
  };
631
749
  }
632
750
  function stringifyWhereUnique(model) {
633
- const { hidden } = extractAnnotations(
634
- model.documentation
635
- );
751
+ const { hidden } = extractAnnotations(model.documentation);
636
752
  if (hidden) {
637
753
  return;
638
754
  }
639
755
  const fields = [];
640
756
  const enumDependencies = [];
757
+ const externalSchemaDependencies = [];
758
+ function generateUniqueAlias(path, exportName, fieldName) {
759
+ const baseName = exportName || path.split("/").pop()?.replace(extRegex, "") || "Schema";
760
+ const suffix = fieldName ? `_${fieldName}` : "";
761
+ return `${baseName}${suffix}`;
762
+ }
641
763
  for (const field of model.fields) {
642
764
  const { annotations: fieldAnnotations, hidden: fieldHidden } = extractAnnotations(field.documentation);
643
765
  if (fieldHidden) continue;
644
766
  if (field.kind === "object") continue;
645
767
  if (!(field.isId || field.isUnique)) continue;
768
+ const schemaAnnotation = fieldAnnotations.find(isSchema);
646
769
  const typeOverwrite = fieldAnnotations.find(isTypeOverwrite);
647
770
  let fieldType;
648
- if (typeOverwrite) {
771
+ if (schemaAnnotation) {
772
+ if (schemaAnnotation.isExternal) {
773
+ const alias = generateUniqueAlias(
774
+ schemaAnnotation.importPath,
775
+ schemaAnnotation.exportName,
776
+ field.name
777
+ );
778
+ if (!externalSchemaDependencies.some((d) => d.localAlias === alias)) {
779
+ const dependency = {
780
+ importPath: schemaAnnotation.importPath,
781
+ localAlias: alias
782
+ };
783
+ if (schemaAnnotation.exportName) {
784
+ dependency.exportName = schemaAnnotation.exportName;
785
+ }
786
+ externalSchemaDependencies.push(dependency);
787
+ }
788
+ fieldType = alias;
789
+ } else {
790
+ if (schemaAnnotation.value.trim().startsWith("{")) {
791
+ fieldType = schemaAnnotation.value;
792
+ } else {
793
+ fieldType = `"${schemaAnnotation.value}"`;
794
+ }
795
+ }
796
+ } else if (typeOverwrite) {
649
797
  fieldType = typeOverwrite.value;
650
798
  } else if (isPrimitivePrismaFieldType(field.type)) {
651
799
  fieldType = stringifyPrimitiveType(field.type);
@@ -668,7 +816,8 @@ function stringifyWhereUnique(model) {
668
816
  stringified: `{
669
817
  ${fields.join(",\n ")}
670
818
  }`,
671
- enumDependencies
819
+ enumDependencies,
820
+ externalSchemaDependencies
672
821
  };
673
822
  }
674
823
 
@@ -682,6 +831,27 @@ function generateEnumImports(enumDependencies) {
682
831
  return `${enumDependencies.map((enumName) => `import { ${enumName} } from "./${enumName}";`).join("\n")}
683
832
  `;
684
833
  }
834
+ function generateModelImports(modelDependencies) {
835
+ if (!modelDependencies || modelDependencies.length === 0) {
836
+ return "";
837
+ }
838
+ return `${modelDependencies.map(
839
+ (modelName) => `import { ${modelName}Plain } from "./${modelName}Plain";`
840
+ ).join("\n")}
841
+ `;
842
+ }
843
+ function generateExternalSchemaImports(externalSchemaDependencies) {
844
+ if (!externalSchemaDependencies || externalSchemaDependencies.length === 0) {
845
+ return "";
846
+ }
847
+ return `${externalSchemaDependencies.map((dep) => {
848
+ if (dep.exportName) {
849
+ return `import { ${dep.exportName} as ${dep.localAlias} } from "${dep.importPath}";`;
850
+ }
851
+ return `import ${dep.localAlias} from "${dep.importPath}";`;
852
+ }).join("\n")}
853
+ `;
854
+ }
685
855
  function mapAllModelsForWrite(processedEnums, processedPlain, processedRelations, processedWhere, processedWhereUnique, processedCreate, processedUpdate, processedRelationsCreate, processedRelationsUpdate, processedSelect, processedInclude, processedOrderBy) {
686
856
  const config = getConfig();
687
857
  const modelMap = /* @__PURE__ */ new Map();
@@ -695,12 +865,16 @@ function mapAllModelsForWrite(processedEnums, processedPlain, processedRelations
695
865
  }
696
866
  for (const model of processedPlain) {
697
867
  const enumImports = generateEnumImports(model.enumDependencies);
698
- const content = `${arktypeImport}${enumImports}export const ${model.name}Plain = type(${model.stringified});
868
+ const externalSchemaImports = generateExternalSchemaImports(
869
+ model.externalSchemaDependencies
870
+ );
871
+ const content = `${arktypeImport}${enumImports}${externalSchemaImports}export const ${model.name}Plain = type(${model.stringified});
699
872
  `;
700
873
  modelMap.set(`${model.name}Plain`, content);
701
874
  }
702
875
  for (const model of processedRelations) {
703
- const content = `${arktypeImport}export const ${model.name}Relations = type(${model.stringified});
876
+ const modelImports = generateModelImports(model.modelDependencies);
877
+ const content = `${arktypeImport}${modelImports}export const ${model.name}Relations = type(${model.stringified});
704
878
  `;
705
879
  modelMap.set(`${model.name}Relations`, content);
706
880
  }
@@ -723,25 +897,37 @@ export const ${plain.name} = ${plain.name}Plain;
723
897
  }
724
898
  for (const model of processedWhere) {
725
899
  const enumImports = generateEnumImports(model.enumDependencies);
726
- const content = `${arktypeImport}${enumImports}export const ${model.name}Where = type(${model.stringified});
900
+ const externalSchemaImports = generateExternalSchemaImports(
901
+ model.externalSchemaDependencies
902
+ );
903
+ const content = `${arktypeImport}${enumImports}${externalSchemaImports}export const ${model.name}Where = type(${model.stringified});
727
904
  `;
728
905
  modelMap.set(`${model.name}Where`, content);
729
906
  }
730
907
  for (const model of processedWhereUnique) {
731
908
  const enumImports = generateEnumImports(model.enumDependencies);
732
- const content = `${arktypeImport}${enumImports}export const ${model.name}WhereUnique = type(${model.stringified});
909
+ const externalSchemaImports = generateExternalSchemaImports(
910
+ model.externalSchemaDependencies
911
+ );
912
+ const content = `${arktypeImport}${enumImports}${externalSchemaImports}export const ${model.name}WhereUnique = type(${model.stringified});
733
913
  `;
734
914
  modelMap.set(`${model.name}WhereUnique`, content);
735
915
  }
736
916
  for (const model of processedCreate) {
737
917
  const enumImports = generateEnumImports(model.enumDependencies);
738
- const content = `${arktypeImport}${enumImports}export const ${model.name}Create = type(${model.stringified});
918
+ const externalSchemaImports = generateExternalSchemaImports(
919
+ model.externalSchemaDependencies
920
+ );
921
+ const content = `${arktypeImport}${enumImports}${externalSchemaImports}export const ${model.name}Create = type(${model.stringified});
739
922
  `;
740
923
  modelMap.set(`${model.name}Create`, content);
741
924
  }
742
925
  for (const model of processedUpdate) {
743
926
  const enumImports = generateEnumImports(model.enumDependencies);
744
- const content = `${arktypeImport}${enumImports}export const ${model.name}Update = type(${model.stringified});
927
+ const externalSchemaImports = generateExternalSchemaImports(
928
+ model.externalSchemaDependencies
929
+ );
930
+ const content = `${arktypeImport}${enumImports}${externalSchemaImports}export const ${model.name}Update = type(${model.stringified});
745
931
  `;
746
932
  modelMap.set(`${model.name}Update`, content);
747
933
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prisma-arktype",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "description": "Generate ArkType schemas from your Prisma schema",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -55,11 +55,11 @@
55
55
  "vitest": "^4.0.16"
56
56
  },
57
57
  "scripts": {
58
- "build": "pkgroll",
58
+ "build": "pkgroll && prisma generate",
59
59
  "dev": "pkgroll --watch",
60
60
  "test": "vitest run",
61
61
  "test:watch": "vitest",
62
- "test:e2e": "pnpm build && prisma generate && vitest run",
62
+ "test:e2e": "pnpm build && vitest run",
63
63
  "pretest": "pnpm build",
64
64
  "postinstall": "lefthook install",
65
65
  "lint": "biome check",