@kurotako/parser-prisma 0.1.0 → 0.2.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.
package/dist/index.cjs CHANGED
@@ -30,6 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ PrismaAmbiguousRelationError: () => PrismaAmbiguousRelationError,
34
+ PrismaContractError: () => PrismaContractError,
35
+ PrismaContractVersionError: () => PrismaContractVersionError,
36
+ PrismaDialectError: () => PrismaDialectError,
37
+ PrismaEntityCollisionError: () => PrismaEntityCollisionError,
33
38
  PrismaInputError: () => PrismaInputError,
34
39
  PrismaParserOptions: () => PrismaParserOptions,
35
40
  PrismaPeerMissingError: () => PrismaPeerMissingError,
@@ -77,18 +82,536 @@ ${prismaMessage}`,
77
82
  this.prismaMessage = prismaMessage;
78
83
  }
79
84
  };
85
+ var PrismaContractError = class extends import_core.TakoError {
86
+ constructor(detail, options) {
87
+ super(
88
+ "prisma_contract",
89
+ `invalid Prisma 8 contract.json: ${detail}`,
90
+ options
91
+ );
92
+ }
93
+ };
94
+ var PrismaContractVersionError = class extends import_core.TakoError {
95
+ found;
96
+ constructor(found, expected) {
97
+ super(
98
+ "prisma_contract_version",
99
+ `unsupported Prisma contract schemaVersion '${found}' (expected one of: ${expected.join(", ")})`
100
+ );
101
+ this.found = found;
102
+ }
103
+ };
104
+ var PrismaDialectError = class extends import_core.TakoError {
105
+ codecId;
106
+ constructor(codecId) {
107
+ const dialect = codecId.split("/")[0] ?? codecId;
108
+ super(
109
+ "prisma_dialect",
110
+ `unsupported Prisma contract dialect '${dialect}' in codec '${codecId}'; only PostgreSQL contracts are supported currently`
111
+ );
112
+ this.codecId = codecId;
113
+ }
114
+ };
115
+ var PrismaEntityCollisionError = class extends import_core.TakoError {
116
+ entityName;
117
+ models;
118
+ constructor(entityName, models) {
119
+ super(
120
+ "prisma_entity_collision",
121
+ `Prisma contract models ${models.join(", ")} resolve to the same entity name '${entityName}'`
122
+ );
123
+ this.entityName = entityName;
124
+ this.models = models;
125
+ }
126
+ };
127
+ var PrismaAmbiguousRelationError = class extends import_core.TakoError {
128
+ constructor(modelName) {
129
+ super(
130
+ "prisma_ambiguous_relation",
131
+ `Prisma contract relation targets '${modelName}', which exists in multiple namespaces; Prisma 8 RC does not resolve this reliably`
132
+ );
133
+ }
134
+ };
80
135
 
81
136
  // src/options.ts
82
137
  var v = __toESM(require("valibot"), 1);
83
138
  var PrismaParserOptions = v.strictObject({
84
139
  schema: v.optional(v.string(), "./prisma/schema.prisma"),
85
- version: v.optional(v.picklist([7, 8]))
140
+ version: v.optional(v.picklist([7, 8])),
141
+ namespacePrefix: v.optional(v.record(v.string(), v.string())),
142
+ rename: v.optional(v.record(v.string(), v.string()))
86
143
  });
87
144
 
88
145
  // src/parser.ts
146
+ var import_promises3 = require("fs/promises");
89
147
  var import_node_path3 = require("path");
90
148
  var import_config = require("@kurotako/config");
91
149
 
150
+ // src/contract/codecs.ts
151
+ var CODECS = {
152
+ "pg/text": { scalar: "string" },
153
+ "pg/text-array": { scalar: "string" },
154
+ "pg/varchar": { scalar: "string", needsLength: true },
155
+ "sql/varchar": { scalar: "string", needsLength: true },
156
+ "pg/char": { scalar: "string" },
157
+ "pg/bpchar": { scalar: "string" },
158
+ "pg/bool": { scalar: "boolean" },
159
+ "pg/int": { scalar: "int" },
160
+ "pg/int2": { scalar: "int" },
161
+ "pg/int4": { scalar: "int" },
162
+ "pg/int8": { scalar: "bigint" },
163
+ "pg/int8number": { scalar: "int" },
164
+ "pg/unboundedint": { scalar: "bigint" },
165
+ "pg/float": { scalar: "float" },
166
+ "pg/float4": { scalar: "float" },
167
+ "pg/float8": { scalar: "float" },
168
+ "pg/numeric": { scalar: "decimal" },
169
+ "pg/uuid": { scalar: "uuid" },
170
+ "pg/timestamp-string": { scalar: "datetime" },
171
+ "pg/timestamp-temporal": { scalar: "datetime" },
172
+ "pg/timestamptz-string": { scalar: "datetime" },
173
+ "pg/timestamptz-temporal": { scalar: "datetime" },
174
+ "pg/date-string": { scalar: "date" },
175
+ "pg/date-temporal": { scalar: "date" },
176
+ "pg/time-string": { scalar: "datetime", format: "time" },
177
+ "pg/time-temporal": { scalar: "datetime", format: "time" },
178
+ "pg/timetz": { scalar: "datetime", format: "time" },
179
+ "pg/json": { scalar: "json" },
180
+ "pg/jsonb": { scalar: "json" },
181
+ "pg/bytea": { scalar: "bytes" }
182
+ };
183
+ function splitCodec(codecId) {
184
+ const at = codecId.lastIndexOf("@");
185
+ return at === -1 ? { name: codecId } : { name: codecId.slice(0, at), version: codecId.slice(at + 1) };
186
+ }
187
+ function mapCodec(codecId, logger) {
188
+ const { name, version } = splitCodec(codecId);
189
+ if (version !== void 0) {
190
+ logger?.debug(`prisma parser: contract codec '${name}' version ${version}`);
191
+ }
192
+ const entry = CODECS[name];
193
+ if (entry) {
194
+ return {
195
+ type: { kind: "scalar", scalar: entry.scalar },
196
+ ...entry.format !== void 0 ? { format: entry.format } : {},
197
+ ...entry.needsLength ? { needsLength: true } : {}
198
+ };
199
+ }
200
+ if (!name.startsWith("pg/") && !name.startsWith("sql/")) {
201
+ throw new PrismaDialectError(codecId);
202
+ }
203
+ logger?.debug(`prisma parser: unknown contract codec '${codecId}'`);
204
+ return { type: { kind: "unknown", hint: codecId } };
205
+ }
206
+
207
+ // src/contract/naming.ts
208
+ function resolveNames(models, options) {
209
+ const names = /* @__PURE__ */ new Map();
210
+ const collisions = /* @__PURE__ */ new Map();
211
+ for (const { namespace, name } of models) {
212
+ const key = `${namespace}.${name}`;
213
+ const target = options.rename?.[key] ?? `${options.namespacePrefix?.[namespace] ?? ""}${name}`;
214
+ names.set(key, target);
215
+ const entries = collisions.get(target) ?? [];
216
+ entries.push(key);
217
+ collisions.set(target, entries);
218
+ }
219
+ for (const [target, modelsForTarget] of collisions) {
220
+ if (modelsForTarget.length > 1) {
221
+ throw new PrismaEntityCollisionError(target, modelsForTarget);
222
+ }
223
+ }
224
+ return names;
225
+ }
226
+
227
+ // src/contract/schema.ts
228
+ var v2 = __toESM(require("valibot"), 1);
229
+ var scalarType = v2.looseObject({
230
+ kind: v2.literal("scalar"),
231
+ codecId: v2.string(),
232
+ typeParams: v2.optional(v2.looseObject({ length: v2.optional(v2.number()) }))
233
+ });
234
+ var valueObjectType = v2.looseObject({
235
+ kind: v2.literal("valueObject"),
236
+ name: v2.string()
237
+ });
238
+ var field = v2.looseObject({
239
+ nullable: v2.boolean(),
240
+ many: v2.optional(v2.boolean()),
241
+ type: v2.union([scalarType, valueObjectType]),
242
+ valueSet: v2.optional(v2.looseObject({ entityName: v2.string() }))
243
+ });
244
+ var relation = v2.looseObject({
245
+ cardinality: v2.picklist(["1:1", "1:N", "N:1", "N:M"]),
246
+ to: v2.looseObject({ namespace: v2.string(), model: v2.string() }),
247
+ on: v2.looseObject({
248
+ localFields: v2.array(v2.string()),
249
+ targetFields: v2.array(v2.string())
250
+ })
251
+ });
252
+ var model = v2.looseObject({
253
+ fields: v2.record(v2.string(), field),
254
+ relations: v2.optional(v2.record(v2.string(), relation)),
255
+ storage: v2.looseObject({
256
+ table: v2.string(),
257
+ namespaceId: v2.string(),
258
+ fields: v2.record(v2.string(), v2.looseObject({ column: v2.string() }))
259
+ })
260
+ });
261
+ var enumDef = v2.looseObject({
262
+ members: v2.array(v2.looseObject({ name: v2.string(), value: v2.string() }))
263
+ });
264
+ var column = v2.looseObject({
265
+ codecId: v2.string(),
266
+ nullable: v2.boolean(),
267
+ many: v2.optional(v2.boolean()),
268
+ default: v2.optional(
269
+ v2.looseObject({
270
+ kind: v2.picklist(["function", "literal"]),
271
+ expression: v2.optional(v2.string()),
272
+ value: v2.optional(
273
+ v2.union([
274
+ v2.string(),
275
+ v2.number(),
276
+ v2.boolean(),
277
+ v2.array(v2.union([v2.string(), v2.number(), v2.boolean()]))
278
+ ])
279
+ )
280
+ })
281
+ )
282
+ });
283
+ var table = v2.looseObject({
284
+ columns: v2.record(v2.string(), column),
285
+ primaryKey: v2.optional(v2.looseObject({ columns: v2.array(v2.string()) })),
286
+ uniques: v2.optional(
287
+ v2.array(
288
+ v2.looseObject({
289
+ columns: v2.array(v2.string()),
290
+ name: v2.optional(v2.string())
291
+ })
292
+ )
293
+ ),
294
+ indexes: v2.optional(
295
+ v2.array(
296
+ v2.looseObject({
297
+ columns: v2.array(v2.string()),
298
+ name: v2.optional(v2.string()),
299
+ type: v2.optional(v2.string())
300
+ })
301
+ )
302
+ ),
303
+ foreignKeys: v2.optional(
304
+ v2.array(
305
+ v2.looseObject({
306
+ source: v2.looseObject({ columns: v2.array(v2.string()) }),
307
+ onDelete: v2.optional(v2.string()),
308
+ onUpdate: v2.optional(v2.string())
309
+ })
310
+ )
311
+ )
312
+ });
313
+ var ContractSchema = v2.looseObject({
314
+ schemaVersion: v2.string(),
315
+ target: v2.string(),
316
+ targetFamily: v2.string(),
317
+ domain: v2.looseObject({
318
+ namespaces: v2.record(
319
+ v2.string(),
320
+ v2.looseObject({
321
+ models: v2.record(v2.string(), model),
322
+ enum: v2.optional(v2.record(v2.string(), enumDef))
323
+ })
324
+ )
325
+ }),
326
+ storage: v2.looseObject({
327
+ namespaces: v2.record(
328
+ v2.string(),
329
+ v2.looseObject({
330
+ entries: v2.looseObject({
331
+ table: v2.optional(v2.record(v2.string(), table)),
332
+ valueSet: v2.optional(
333
+ v2.record(
334
+ v2.string(),
335
+ v2.looseObject({ values: v2.array(v2.string()) })
336
+ )
337
+ )
338
+ })
339
+ })
340
+ )
341
+ }),
342
+ execution: v2.optional(
343
+ v2.looseObject({
344
+ mutations: v2.optional(
345
+ v2.looseObject({
346
+ defaults: v2.optional(
347
+ v2.array(
348
+ v2.looseObject({
349
+ ref: v2.looseObject({
350
+ namespace: v2.string(),
351
+ table: v2.string(),
352
+ column: v2.string()
353
+ }),
354
+ onCreate: v2.optional(
355
+ v2.looseObject({ kind: v2.string(), id: v2.string() })
356
+ ),
357
+ onUpdate: v2.optional(
358
+ v2.looseObject({ kind: v2.string(), id: v2.string() })
359
+ )
360
+ })
361
+ )
362
+ )
363
+ })
364
+ )
365
+ })
366
+ )
367
+ });
368
+ function issuePath(err) {
369
+ if (err instanceof v2.ValiError) {
370
+ return err.issues.map(
371
+ (issue) => issue.path?.map((part) => String(part.key)).join(".") ?? "<root>"
372
+ ).join(", ");
373
+ }
374
+ return "<root>";
375
+ }
376
+ function parseContract(raw) {
377
+ let value;
378
+ try {
379
+ value = JSON.parse(raw);
380
+ } catch (err) {
381
+ throw new PrismaContractError("invalid JSON", { cause: err });
382
+ }
383
+ try {
384
+ return v2.parse(ContractSchema, value);
385
+ } catch (err) {
386
+ throw new PrismaContractError(`invalid structure at ${issuePath(err)}`, {
387
+ cause: err
388
+ });
389
+ }
390
+ }
391
+
392
+ // src/contract/version.ts
393
+ var SUPPORTED_SCHEMA_VERSIONS = /* @__PURE__ */ new Set(["1"]);
394
+ function assertSupportedVersion(found) {
395
+ if (!SUPPORTED_SCHEMA_VERSIONS.has(found)) {
396
+ throw new PrismaContractVersionError(found, [...SUPPORTED_SCHEMA_VERSIONS]);
397
+ }
398
+ }
399
+
400
+ // src/contract/read.ts
401
+ function record3(value) {
402
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
403
+ }
404
+ function strings(value) {
405
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
406
+ }
407
+ function storageTable(contract, namespace, tableName) {
408
+ const namespaces = record3(record3(contract.storage).namespaces);
409
+ const entries = record3(record3(namespaces[namespace]).entries);
410
+ return record3(record3(entries.table)[tableName]);
411
+ }
412
+ function defaultValue(value) {
413
+ const raw = record3(value);
414
+ if (raw.kind === "literal") {
415
+ return raw.value;
416
+ }
417
+ if (raw.kind === "function" && typeof raw.expression === "string") {
418
+ const expression = raw.expression;
419
+ const match = /^(\\w+)\\((.*)\\)$/.exec(expression);
420
+ return match ? { name: match[1] ?? expression, args: [] } : { name: expression, args: [] };
421
+ }
422
+ return void 0;
423
+ }
424
+ function generatorDefault(contract, namespace, table2, column2) {
425
+ const defaults = record3(
426
+ record3(record3(contract.execution).mutations).defaults
427
+ );
428
+ if (!Array.isArray(defaults)) return void 0;
429
+ return defaults.map(record3).find((entry) => {
430
+ const ref = record3(entry.ref);
431
+ return ref.namespace === namespace && ref.table === table2 && ref.column === column2;
432
+ });
433
+ }
434
+ function readField(name, raw, storageColumn, generator, logger) {
435
+ const type = record3(raw.type);
436
+ if (type.kind === "valueObject") {
437
+ return {
438
+ name,
439
+ type: typeof type.name === "string" ? type.name : "valueObject",
440
+ kind: "unsupported",
441
+ isList: raw.many === true,
442
+ isRequired: raw.nullable !== true,
443
+ isUnique: false,
444
+ isUpdatedAt: false,
445
+ hasDefaultValue: generator !== void 0 || storageColumn.default !== void 0,
446
+ nativeType: null
447
+ };
448
+ }
449
+ const codecId = String(type.codecId);
450
+ const mapped = mapCodec(codecId, logger);
451
+ const valueSet = record3(raw.valueSet);
452
+ const isEnum = typeof valueSet.entityName === "string";
453
+ const typeParams = record3(type.typeParams);
454
+ const maxLength = mapped.needsLength && typeof typeParams.length === "number" ? typeParams.length : void 0;
455
+ const field2 = {
456
+ name,
457
+ type: isEnum ? String(valueSet.entityName) : codecId,
458
+ kind: isEnum ? "enum" : "scalar",
459
+ isList: raw.many === true,
460
+ isRequired: raw.nullable !== true,
461
+ isUnique: false,
462
+ isUpdatedAt: record3(generator?.onUpdate).id === "instantNow",
463
+ hasDefaultValue: generator !== void 0 || storageColumn.default !== void 0,
464
+ nativeType: null
465
+ };
466
+ if (isEnum) return field2;
467
+ field2.mappedType = mapped.type;
468
+ field2.scalarOverride = mapped.scalarOverride;
469
+ field2.format = mapped.format;
470
+ field2.maxLength = maxLength;
471
+ const parsedDefault = defaultValue(storageColumn.default);
472
+ if (parsedDefault !== void 0) field2.default = parsedDefault;
473
+ return field2;
474
+ }
475
+ function readRelationEdges(relations, names, sourceName, table2) {
476
+ const foreignKeys = Array.isArray(table2.foreignKeys) ? table2.foreignKeys.map(record3) : [];
477
+ return Object.entries(relations).map(([fieldName, relation2]) => {
478
+ const raw = record3(relation2);
479
+ const to = record3(raw.to);
480
+ const on = record3(raw.on);
481
+ const localFields = strings(on.localFields);
482
+ const targetFields = strings(on.targetFields);
483
+ const fk = foreignKeys.find((candidate) => {
484
+ const source = record3(candidate.source);
485
+ return JSON.stringify(strings(source.columns)) === JSON.stringify(localFields);
486
+ });
487
+ const targetKey = `${String(to.namespace)}.${String(to.model)}`;
488
+ const cardinality = raw.cardinality;
489
+ const edge = {
490
+ fieldName,
491
+ relationName: [sourceName, String(to.model)].sort().join(":") + `:${[...localFields, ...targetFields].sort().join(",")}`,
492
+ targetEntity: names.get(targetKey) ?? String(to.model),
493
+ isList: cardinality === "1:N" || cardinality === "N:M",
494
+ isRequired: cardinality !== "1:N" && cardinality !== "N:M",
495
+ fromFields: fk ? localFields : [],
496
+ toFields: fk ? targetFields : []
497
+ };
498
+ if (typeof fk?.onDelete === "string") edge.onDelete = fk.onDelete;
499
+ if (typeof fk?.onUpdate === "string") edge.onUpdate = fk.onUpdate;
500
+ return edge;
501
+ });
502
+ }
503
+ function readContract(raw, ctx, options) {
504
+ const parsed = parseContract(raw);
505
+ assertSupportedVersion(parsed.schemaVersion);
506
+ const contract = parsed;
507
+ const namespaces = record3(record3(contract.domain).namespaces);
508
+ const models = Object.entries(namespaces).flatMap(
509
+ ([namespace, rawNamespace]) => Object.keys(record3(record3(rawNamespace).models)).map((name) => ({
510
+ namespace,
511
+ name
512
+ }))
513
+ );
514
+ const modelCounts = /* @__PURE__ */ new Map();
515
+ for (const model2 of models) {
516
+ modelCounts.set(model2.name, (modelCounts.get(model2.name) ?? 0) + 1);
517
+ }
518
+ for (const rawNamespace of Object.values(namespaces)) {
519
+ for (const rawModel of Object.values(record3(record3(rawNamespace).models))) {
520
+ for (const relation2 of Object.values(
521
+ record3(record3(rawModel).relations)
522
+ )) {
523
+ const target = record3(record3(relation2).to);
524
+ if (typeof target.model === "string" && (modelCounts.get(target.model) ?? 0) > 1) {
525
+ throw new PrismaAmbiguousRelationError(target.model);
526
+ }
527
+ }
528
+ }
529
+ }
530
+ const names = resolveNames(models, options);
531
+ const entities = [];
532
+ const enums = [];
533
+ for (const [namespace, rawNamespace] of Object.entries(namespaces)) {
534
+ const namespaceData = record3(rawNamespace);
535
+ const modelDefs = record3(namespaceData.models);
536
+ for (const [sourceName, rawModel] of Object.entries(modelDefs)) {
537
+ const model2 = record3(rawModel);
538
+ const bridge = record3(model2.storage);
539
+ const tableName = String(bridge.table);
540
+ const table2 = storageTable(
541
+ contract,
542
+ String(bridge.namespaceId),
543
+ tableName
544
+ );
545
+ const columns = record3(table2.columns);
546
+ const bridgeFields = record3(bridge.fields);
547
+ const fields = Object.entries(record3(model2.fields)).map(
548
+ ([name, rawField]) => {
549
+ const column2 = String(record3(bridgeFields[name]).column);
550
+ return readField(
551
+ name,
552
+ record3(rawField),
553
+ record3(columns[column2]),
554
+ generatorDefault(
555
+ contract,
556
+ String(bridge.namespaceId),
557
+ tableName,
558
+ column2
559
+ ),
560
+ ctx.logger
561
+ );
562
+ }
563
+ );
564
+ const uniqueColumns = new Set(
565
+ (Array.isArray(table2.uniques) ? table2.uniques : []).flatMap(
566
+ (entry) => strings(record3(entry).columns)
567
+ )
568
+ );
569
+ for (const field2 of fields)
570
+ field2.isUnique = uniqueColumns.has(field2.name);
571
+ const entity = {
572
+ name: names.get(`${namespace}.${sourceName}`) ?? sourceName,
573
+ dbName: tableName === sourceName ? void 0 : tableName,
574
+ fields,
575
+ relationEdges: readRelationEdges(
576
+ record3(model2.relations),
577
+ names,
578
+ sourceName,
579
+ table2
580
+ ),
581
+ primaryKey: strings(record3(table2.primaryKey).columns),
582
+ uniques: (Array.isArray(table2.uniques) ? table2.uniques : []).map(
583
+ (entry) => ({
584
+ fields: strings(record3(entry).columns),
585
+ ...typeof record3(entry).name === "string" ? { name: String(record3(entry).name) } : {}
586
+ })
587
+ ),
588
+ indexes: (Array.isArray(table2.indexes) ? table2.indexes : []).map(
589
+ (entry) => ({
590
+ fields: strings(record3(entry).columns),
591
+ ...typeof record3(entry).name === "string" ? { name: String(record3(entry).name) } : {},
592
+ ...typeof record3(entry).type === "string" ? { type: String(record3(entry).type) } : {}
593
+ })
594
+ )
595
+ };
596
+ entities.push(entity);
597
+ }
598
+ for (const [name, rawEnum] of Object.entries(record3(namespaceData.enum))) {
599
+ const members = Array.isArray(record3(rawEnum).members) ? record3(rawEnum).members : [];
600
+ enums.push({
601
+ name,
602
+ values: members.map((member) => {
603
+ const value = record3(member);
604
+ return {
605
+ name: String(value.name),
606
+ ...String(value.value) !== String(value.name) ? { dbName: String(value.value) } : {}
607
+ };
608
+ })
609
+ });
610
+ }
611
+ }
612
+ return { model: { entities, enums }, generatorVersion: parsed.schemaVersion };
613
+ }
614
+
92
615
  // src/detect.ts
93
616
  var import_promises = require("fs/promises");
94
617
  var import_node_path = require("path");
@@ -214,8 +737,8 @@ var import_node_path2 = require("path");
214
737
  var import_node_url = require("url");
215
738
 
216
739
  // src/dmmf/read.ts
217
- function readField(f) {
218
- const field = {
740
+ function readField2(f) {
741
+ const field2 = {
219
742
  name: f.name,
220
743
  type: f.type,
221
744
  kind: f.kind === "enum" ? "enum" : f.kind === "unsupported" ? "unsupported" : "scalar",
@@ -227,12 +750,12 @@ function readField(f) {
227
750
  nativeType: f.nativeType ? [f.nativeType[0], [...f.nativeType[1]]] : null
228
751
  };
229
752
  if (f.default !== void 0) {
230
- field.default = f.default;
753
+ field2.default = f.default;
231
754
  }
232
755
  if (f.documentation !== void 0) {
233
- field.doc = f.documentation;
756
+ field2.doc = f.documentation;
234
757
  }
235
- return field;
758
+ return field2;
236
759
  }
237
760
  function readEdge(f) {
238
761
  const edge = {
@@ -252,16 +775,16 @@ function readEdge(f) {
252
775
  }
253
776
  return edge;
254
777
  }
255
- function readPrimaryKey(model) {
256
- if (model.primaryKey && model.primaryKey.fields.length > 0) {
257
- return [...model.primaryKey.fields];
778
+ function readPrimaryKey(model2) {
779
+ if (model2.primaryKey && model2.primaryKey.fields.length > 0) {
780
+ return [...model2.primaryKey.fields];
258
781
  }
259
- const id = model.fields.find((f) => f.isId);
782
+ const id = model2.fields.find((f) => f.isId);
260
783
  return id ? [id.name] : [];
261
784
  }
262
- function readUniques(model) {
263
- if (model.uniqueIndexes.length > 0) {
264
- return model.uniqueIndexes.map((u) => {
785
+ function readUniques(model2) {
786
+ if (model2.uniqueIndexes.length > 0) {
787
+ return model2.uniqueIndexes.map((u) => {
265
788
  const entry = { fields: [...u.fields] };
266
789
  if (u.name) {
267
790
  entry.name = u.name;
@@ -269,7 +792,7 @@ function readUniques(model) {
269
792
  return entry;
270
793
  });
271
794
  }
272
- return model.uniqueFields.map((fields) => ({ fields: [...fields] }));
795
+ return model2.uniqueFields.map((fields) => ({ fields: [...fields] }));
273
796
  }
274
797
  function readIndexes(modelName, all) {
275
798
  if (!all) {
@@ -286,29 +809,29 @@ function readIndexes(modelName, all) {
286
809
  return entry;
287
810
  });
288
811
  }
289
- function readEntity(model, doc) {
812
+ function readEntity(model2, doc) {
290
813
  const fields = [];
291
814
  const relationEdges = [];
292
- for (const f of model.fields) {
815
+ for (const f of model2.fields) {
293
816
  if (f.kind === "object") {
294
817
  relationEdges.push(readEdge(f));
295
818
  } else {
296
- fields.push(readField(f));
819
+ fields.push(readField2(f));
297
820
  }
298
821
  }
299
822
  const entity = {
300
- name: model.name,
823
+ name: model2.name,
301
824
  fields,
302
825
  relationEdges,
303
- primaryKey: readPrimaryKey(model),
304
- uniques: readUniques(model),
305
- indexes: readIndexes(model.name, doc.datamodel.indexes)
826
+ primaryKey: readPrimaryKey(model2),
827
+ uniques: readUniques(model2),
828
+ indexes: readIndexes(model2.name, doc.datamodel.indexes)
306
829
  };
307
- if (model.dbName) {
308
- entity.dbName = model.dbName;
830
+ if (model2.dbName) {
831
+ entity.dbName = model2.dbName;
309
832
  }
310
- if (model.documentation !== void 0) {
311
- entity.doc = model.documentation;
833
+ if (model2.documentation !== void 0) {
834
+ entity.doc = model2.documentation;
312
835
  }
313
836
  return entity;
314
837
  }
@@ -331,11 +854,27 @@ function readEnum(e) {
331
854
  }
332
855
  return def;
333
856
  }
334
- function toPrismaModel(doc) {
335
- return {
857
+ function toPrismaModel(doc, options) {
858
+ const result = {
336
859
  entities: doc.datamodel.models.map((m) => readEntity(m, doc)),
337
860
  enums: doc.datamodel.enums.map(readEnum)
338
861
  };
862
+ if (!options?.rename) {
863
+ return result;
864
+ }
865
+ const names = new Map(
866
+ result.entities.map((entity) => [
867
+ entity.name,
868
+ options.rename?.[entity.name] ?? entity.name
869
+ ])
870
+ );
871
+ for (const entity of result.entities) {
872
+ entity.name = names.get(entity.name) ?? entity.name;
873
+ for (const edge of entity.relationEdges) {
874
+ edge.targetEntity = names.get(edge.targetEntity) ?? edge.targetEntity;
875
+ }
876
+ }
877
+ return result;
339
878
  }
340
879
 
341
880
  // src/dmmf/load.ts
@@ -374,7 +913,7 @@ async function resolveInternals(ctx) {
374
913
  }
375
914
  return { getDMMF, prismaVersion };
376
915
  }
377
- async function readDmmf(input, ctx) {
916
+ async function readDmmf(input, ctx, options) {
378
917
  const { getDMMF, prismaVersion } = await resolveInternals(ctx);
379
918
  const datamodel = input.kind === "file" ? input.files[0]?.[1] ?? "" : input.files.map(([path, content]) => [path, content]);
380
919
  let doc;
@@ -384,7 +923,7 @@ async function readDmmf(input, ctx) {
384
923
  const message = err instanceof Error ? err.message : String(err);
385
924
  throw new PrismaSchemaError(ctx.namespace, message, { cause: err });
386
925
  }
387
- return { model: toPrismaModel(doc), prismaVersion };
926
+ return { model: toPrismaModel(doc, options), prismaVersion };
388
927
  }
389
928
 
390
929
  // src/map/build.ts
@@ -458,7 +997,7 @@ var NOOP_NATIVE = /* @__PURE__ */ new Set([
458
997
  "DateTime2",
459
998
  "DateTimeOffset"
460
999
  ]);
461
- function refineNative(native, constraints, result, field, logger) {
1000
+ function refineNative(native, constraints, result, field2, logger) {
462
1001
  const [name, args] = native;
463
1002
  if (LENGTH_NATIVE.has(name)) {
464
1003
  const n = Number(args[0]);
@@ -483,27 +1022,27 @@ function refineNative(native, constraints, result, field, logger) {
483
1022
  return;
484
1023
  }
485
1024
  logger?.debug(`prisma parser: ignoring unmapped native type @db.${name}`, {
486
- field: field.name
1025
+ field: field2.name
487
1026
  });
488
1027
  }
489
- function mapFieldType(field, logger) {
1028
+ function mapFieldType(field2, logger) {
490
1029
  const constraints = {};
491
- if (field.kind === "unsupported") {
492
- return { type: { kind: "unknown", hint: field.type }, constraints };
1030
+ if (field2.kind === "unsupported") {
1031
+ return { type: { kind: "unknown", hint: field2.type }, constraints };
493
1032
  }
494
- if (field.kind === "enum") {
495
- return { type: { kind: "enum", ref: field.type }, constraints };
1033
+ if (field2.kind === "enum") {
1034
+ return { type: { kind: "enum", ref: field2.type }, constraints };
496
1035
  }
497
- const scalar = SCALAR_TABLE[field.type];
1036
+ const scalar = SCALAR_TABLE[field2.type];
498
1037
  if (scalar === void 0) {
499
- return { type: { kind: "unknown", hint: field.type }, constraints };
1038
+ return { type: { kind: "unknown", hint: field2.type }, constraints };
500
1039
  }
501
1040
  const result = {
502
1041
  type: { kind: "scalar", scalar },
503
1042
  constraints
504
1043
  };
505
- if (field.nativeType) {
506
- refineNative(field.nativeType, constraints, result, field, logger);
1044
+ if (field2.nativeType) {
1045
+ refineNative(field2.nativeType, constraints, result, field2, logger);
507
1046
  }
508
1047
  return result;
509
1048
  }
@@ -531,9 +1070,9 @@ function pkScalar(entities, entityName, logger) {
531
1070
  const entity = entities.get(entityName);
532
1071
  if (entity && entity.primaryKey.length === 1) {
533
1072
  const pkName = entity.primaryKey[0];
534
- const field = entity.fields.find((f) => f.name === pkName);
535
- if (field) {
536
- const mapped = mapFieldType(field);
1073
+ const field2 = entity.fields.find((f) => f.name === pkName);
1074
+ if (field2) {
1075
+ const mapped = mapFieldType(field2);
537
1076
  if (mapped.scalarOverride) {
538
1077
  return mapped.scalarOverride;
539
1078
  }
@@ -549,7 +1088,7 @@ function pkScalar(entities, entityName, logger) {
549
1088
  }
550
1089
  function normalRelation(edge, back) {
551
1090
  const owning = edge.fromFields.length > 0;
552
- const relation = {
1091
+ const relation2 = {
553
1092
  name: edge.fieldName,
554
1093
  target: { namespace: "", entity: edge.targetEntity },
555
1094
  cardinality: edge.isList ? "many" : "one",
@@ -557,21 +1096,21 @@ function normalRelation(edge, back) {
557
1096
  owning
558
1097
  };
559
1098
  if (owning) {
560
- relation.fkFields = [...edge.fromFields];
561
- relation.references = [...edge.toFields];
1099
+ relation2.fkFields = [...edge.fromFields];
1100
+ relation2.references = [...edge.toFields];
562
1101
  }
563
1102
  if (back) {
564
- relation.backRelation = back.fieldName;
1103
+ relation2.backRelation = back.fieldName;
565
1104
  }
566
1105
  const onDelete = mapAction(edge.onDelete);
567
1106
  if (onDelete) {
568
- relation.onDelete = onDelete;
1107
+ relation2.onDelete = onDelete;
569
1108
  }
570
1109
  const onUpdate = mapAction(edge.onUpdate);
571
1110
  if (onUpdate) {
572
- relation.onUpdate = onUpdate;
1111
+ relation2.onUpdate = onUpdate;
573
1112
  }
574
- return relation;
1113
+ return relation2;
575
1114
  }
576
1115
  function materialiseM2M(a, b, relationName, entities, logger) {
577
1116
  const sorted = [a.owner, b.owner].sort(
@@ -636,17 +1175,17 @@ function materialiseM2M(a, b, relationName, entities, logger) {
636
1175
  ]
637
1176
  };
638
1177
  }
639
- function buildRelations(model, logger) {
640
- const entities = new Map(model.entities.map((e) => [e.name, e]));
1178
+ function buildRelations(model2, logger) {
1179
+ const entities = new Map(model2.entities.map((e) => [e.name, e]));
641
1180
  const relations = /* @__PURE__ */ new Map();
642
1181
  const syntheticEntities = [];
643
- const push = (owner, relation) => {
1182
+ const push = (owner, relation2) => {
644
1183
  const list = relations.get(owner) ?? [];
645
- list.push(relation);
1184
+ list.push(relation2);
646
1185
  relations.set(owner, list);
647
1186
  };
648
1187
  const groups = /* @__PURE__ */ new Map();
649
- for (const entity of model.entities) {
1188
+ for (const entity of model2.entities) {
650
1189
  for (const edge of entity.relationEdges) {
651
1190
  const list = groups.get(edge.relationName) ?? [];
652
1191
  list.push({ owner: entity.name, edge });
@@ -664,8 +1203,8 @@ function buildRelations(model, logger) {
664
1203
  logger
665
1204
  );
666
1205
  syntheticEntities.push(synthetic);
667
- for (const { owner, relation } of rewrites) {
668
- push(owner, relation);
1206
+ for (const { owner, relation: relation2 } of rewrites) {
1207
+ push(owner, relation2);
669
1208
  }
670
1209
  continue;
671
1210
  }
@@ -738,17 +1277,24 @@ function addRelation(eb, rel, namespace) {
738
1277
  }
739
1278
  });
740
1279
  }
741
- function buildSourceIR(namespace, model, parserVersion, logger) {
1280
+ function buildSourceIR(namespace, model2, parserVersion, logger) {
742
1281
  const b = (0, import_ir.createSourceIR)({ namespace, parser: "prisma", parserVersion });
743
- for (const e of model.enums) {
1282
+ for (const e of model2.enums) {
744
1283
  b.addEnum(e.name, (eb) => fillEnum(eb, e));
745
1284
  }
746
- const { relations, syntheticEntities } = buildRelations(model, logger);
747
- for (const entity of model.entities) {
1285
+ const { relations, syntheticEntities } = buildRelations(model2, logger);
1286
+ for (const entity of model2.entities) {
748
1287
  b.addEntity(entity.name, (eb) => {
749
- for (const field of entity.fields) {
750
- eb.field(field.name, (fb) => {
751
- const mapped = mapFieldType(field, logger);
1288
+ for (const field2 of entity.fields) {
1289
+ eb.field(field2.name, (fb) => {
1290
+ const mapped = field2.mappedType ? {
1291
+ type: field2.mappedType,
1292
+ constraints: {
1293
+ ...field2.maxLength !== void 0 ? { maxLength: field2.maxLength } : {},
1294
+ ...field2.format !== void 0 ? { format: field2.format } : {}
1295
+ },
1296
+ scalarOverride: field2.scalarOverride
1297
+ } : mapFieldType(field2, logger);
752
1298
  const scalar = mapped.scalarOverride ?? (mapped.type.kind === "scalar" ? mapped.type.scalar : void 0);
753
1299
  if (scalar !== void 0) {
754
1300
  fb.scalar(scalar);
@@ -764,7 +1310,7 @@ function buildSourceIR(namespace, model, parserVersion, logger) {
764
1310
  if (maxLength !== void 0) {
765
1311
  fb.maxLength(maxLength);
766
1312
  }
767
- const mappedDefault = mapDefault(field.default);
1313
+ const mappedDefault = mapDefault(field2.default);
768
1314
  if (mappedDefault.default) {
769
1315
  fb.default(mappedDefault.default);
770
1316
  }
@@ -774,24 +1320,24 @@ function buildSourceIR(namespace, model, parserVersion, logger) {
774
1320
  fb.format(format);
775
1321
  } else {
776
1322
  logger?.debug(
777
- `prisma parser: dropping format '${format}' on non-string field '${entity.name}.${field.name}'`
1323
+ `prisma parser: dropping format '${format}' on non-string field '${entity.name}.${field2.name}'`
778
1324
  );
779
1325
  }
780
1326
  }
781
- if (field.isList) {
1327
+ if (field2.isList) {
782
1328
  fb.list();
783
1329
  }
784
- if (!field.isRequired) {
1330
+ if (!field2.isRequired) {
785
1331
  fb.nullable();
786
1332
  }
787
- if (field.hasDefaultValue || field.isUpdatedAt) {
1333
+ if (field2.hasDefaultValue || field2.isUpdatedAt) {
788
1334
  fb.optional();
789
1335
  }
790
- if (field.isUnique) {
1336
+ if (field2.isUnique) {
791
1337
  fb.unique();
792
1338
  }
793
- if (field.doc !== void 0) {
794
- fb.doc(field.doc);
1339
+ if (field2.doc !== void 0) {
1340
+ fb.doc(field2.doc);
795
1341
  }
796
1342
  });
797
1343
  }
@@ -828,8 +1374,8 @@ function buildSourceIR(namespace, model, parserVersion, logger) {
828
1374
  }
829
1375
  for (const synthetic of syntheticEntities) {
830
1376
  b.addEntity(synthetic.name, (eb) => {
831
- for (const field of synthetic.fields) {
832
- eb.field(field.name, (fb) => fb.scalar(field.scalar));
1377
+ for (const field2 of synthetic.fields) {
1378
+ eb.field(field2.name, (fb) => fb.scalar(field2.scalar));
833
1379
  }
834
1380
  eb.primaryKey(...synthetic.primaryKey);
835
1381
  for (const rel of synthetic.relations) {
@@ -847,16 +1393,24 @@ var prismaParser = (0, import_config.defineParser)({
847
1393
  async parse(ctx, options) {
848
1394
  const input = await resolveInput(ctx.cwd, options, ctx.namespace);
849
1395
  if (input.mode === 8) {
850
- throw new PrismaInputError(
1396
+ const raw = await (0, import_promises3.readFile)(input.contractPath, "utf8");
1397
+ const { model: model3, generatorVersion } = readContract(raw, ctx, options);
1398
+ return buildSourceIR(
851
1399
  ctx.namespace,
852
- input.contractPath,
853
- "the Prisma 8 contract.json mode is not implemented in kurotako v1"
1400
+ model3,
1401
+ `prisma-contract@${generatorVersion}`,
1402
+ ctx.logger
1403
+ );
1404
+ }
1405
+ if (options.namespacePrefix) {
1406
+ ctx.logger.warn(
1407
+ "prisma parser: namespacePrefix is ignored in Prisma 7 mode"
854
1408
  );
855
1409
  }
856
- const { model, prismaVersion } = await readDmmf(input, ctx);
1410
+ const { model: model2, prismaVersion } = await readDmmf(input, ctx, options);
857
1411
  return buildSourceIR(
858
1412
  ctx.namespace,
859
- model,
1413
+ model2,
860
1414
  `prisma@${prismaVersion}`,
861
1415
  ctx.logger
862
1416
  );
@@ -870,6 +1424,11 @@ var prismaParser = (0, import_config.defineParser)({
870
1424
  });
871
1425
  // Annotate the CommonJS export names for ESM import in node:
872
1426
  0 && (module.exports = {
1427
+ PrismaAmbiguousRelationError,
1428
+ PrismaContractError,
1429
+ PrismaContractVersionError,
1430
+ PrismaDialectError,
1431
+ PrismaEntityCollisionError,
873
1432
  PrismaInputError,
874
1433
  PrismaParserOptions,
875
1434
  PrismaPeerMissingError,