@prisma-next/emitter 0.3.0-dev.155 → 0.3.0-dev.157

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.
@@ -19,12 +19,20 @@ declare function generateHashTypeAliases(hashes: {
19
19
  readonly executionHash?: string;
20
20
  readonly profileHash: string;
21
21
  }): string;
22
- declare function generateFieldResolvedType(field: ContractField, codecLookup?: CodecLookup): string;
22
+ type ResolvedFieldType = {
23
+ readonly input: string;
24
+ readonly output: string;
25
+ };
26
+ declare function resolveFieldType(field: ContractField, codecLookup?: CodecLookup): ResolvedFieldType;
27
+ declare function generateFieldResolvedType(field: ContractField, codecLookup?: CodecLookup, side?: 'input' | 'output'): string;
28
+ declare function generateBothFieldTypesMaps(models: Record<string, ContractModel> | undefined, codecLookup?: CodecLookup): ResolvedFieldType;
23
29
  declare function generateFieldOutputTypesMap(models: Record<string, ContractModel> | undefined, codecLookup?: CodecLookup): string;
24
- declare function generateValueObjectType(_voName: string, vo: ContractValueObject, _valueObjects: Record<string, ContractValueObject>): string;
30
+ declare function generateFieldInputTypesMap(models: Record<string, ContractModel> | undefined, codecLookup?: CodecLookup): string;
31
+ declare function generateValueObjectType(_voName: string, vo: ContractValueObject, _valueObjects: Record<string, ContractValueObject>, side?: 'input' | 'output', codecLookup?: CodecLookup): string;
32
+ declare function resolveValueObjectType(_voName: string, vo: ContractValueObject, _valueObjects: Record<string, ContractValueObject>, codecLookup?: CodecLookup): ResolvedFieldType;
25
33
  declare function generateContractFieldDescriptor(fieldName: string, field: ContractField): string;
26
34
  declare function generateValueObjectsDescriptorType(valueObjects: Record<string, ContractValueObject> | undefined): string;
27
- declare function generateValueObjectTypeAliases(valueObjects: Record<string, ContractValueObject> | undefined): string;
35
+ declare function generateValueObjectTypeAliases(valueObjects: Record<string, ContractValueObject> | undefined, codecLookup?: CodecLookup): string;
28
36
  //#endregion
29
- export { deduplicateImports, generateCodecTypeIntersection, generateContractFieldDescriptor, generateFieldOutputTypesMap, generateFieldResolvedType, generateHashTypeAliases, generateImportLines, generateModelFieldEntry, generateModelFieldsType, generateModelRelationsType, generateModelsType, generateRootsType, generateValueObjectType, generateValueObjectTypeAliases, generateValueObjectsDescriptorType, serializeExecutionType, serializeObjectKey, serializeValue };
37
+ export { ResolvedFieldType, deduplicateImports, generateBothFieldTypesMaps, generateCodecTypeIntersection, generateContractFieldDescriptor, generateFieldInputTypesMap, generateFieldOutputTypesMap, generateFieldResolvedType, generateHashTypeAliases, generateImportLines, generateModelFieldEntry, generateModelFieldsType, generateModelRelationsType, generateModelsType, generateRootsType, generateValueObjectType, generateValueObjectTypeAliases, generateValueObjectsDescriptorType, resolveFieldType, resolveValueObjectType, serializeExecutionType, serializeObjectKey, serializeValue };
30
38
  //# sourceMappingURL=domain-type-generation.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"domain-type-generation.d.mts","names":[],"sources":["../src/domain-type-generation.ts"],"sourcesContent":[],"mappings":";;;;;iBASgB,cAAA;iBA+BA,kBAAA;AA/BA,iBAsCA,iBAAA,CAtCc,KAAA,EAsCW,MAtCX,CAAA,MAAA,EAAA,MAAA,CAAA,GAAA,SAAA,CAAA,EAAA,MAAA;AA+Bd,iBAuBA,uBAAA,CAvBkB,SAAA,EAAA,MAAA,EAAA,KAAA,EAuBgC,aAvBhC,CAAA,EAAA,MAAA;AAOlB,iBAgCA,uBAAA,CAhC+B,MAAA,EAgCC,MAhCD,CAAA,MAAA,EAgCgB,aAhChB,CAAA,CAAA,EAAA,MAAA;AAgB/B,iBAwBA,0BAAA,CAxBkD,SAAa,EAwBzB,MAxByB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAAA,MAAA;AAgB/D,iBA8CA,kBAAA,CA9C+C,MAAA,EA+CrD,MA/CsC,CAAA,MAAM,EA+C7B,aA/C6B,CAAA,EAAA,oBAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,KAAA,EAgDH,aAhDG,EAAA,GAAA,MAAA,CAAA,EAAA,MAAA;AAQtC,iBA6EA,kBAAA,CA7E0B,OAAY,EA6EV,eA7EgB,EAAA,CAAA,EA6EI,eA7EJ,EAAA;AAsC5C,iBAoDA,mBAAA,CApDkB,OAAA,EAoDW,eApDX,EAAA,CAAA,EAAA,MAAA,EAAA;AACT,iBA0DT,6BAAA,CA1DS,OAAA,EA2Dd,aA3Dc,CA2DA,eA3DA,CAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAAf,iBAkEM,sBAAA,CAlEN,SAAA,EAkEwC,MAlExC,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAAA,MAAA;AACyC,iBA0EnC,uBAAA,CA1EmC,MAAA,EAAA;EAAa,SAAA,WAAA,EAAA,MAAA;EAqChD,SAAA,aAAkB,CAAA,EAAA,MAAA;EAalB,SAAA,WAAA,EAAmB,MAAA;AAOnC,CAAA,CAAA,EAAgB,MAAA;AAQA,iBAyBA,yBAAA,CAzBwC,KAAA,EAyBP,aAzBO,EAAA,WAAA,CAAA,EAyBsB,WAzBtB,CAAA,EAAA,MAAA;AASxC,iBAgEA,2BAAA,CAhEuB,MAAA,EAiE7B,MAjE6B,CAAA,MAAA,EAiEd,aAjEc,CAAA,GAAA,SAAA,EAAA,WAAA,CAAA,EAkEvB,WAlEuB,CAAA,EAAA,MAAA;AAgBvB,iBAwEA,uBAAA,CAxEiC,OAAA,EAAA,MAA6B,EAAA,EAAA,EA0ExE,mBA1EmF,EAAA,aAAA,EA2ExE,MA3EwE,CAAA,MAAA,EA2EzD,mBA3EyD,CAAA,CAAA,EAAA,MAAA;AAgDzE,iBAqCA,+BAAA,CArC2B,SAAA,EAAA,MAAA,EAAA,KAAA,EAqC+B,aArC/B,CAAA,EAAA,MAAA;AAClB,iBAwDT,kCAAA,CAxDS,YAAA,EAyDT,MAzDS,CAAA,MAAA,EAyDM,mBAzDN,CAAA,GAAA,SAAA,CAAA,EAAA,MAAA;AAAf,iBA6EM,8BAAA,CA7EN,YAAA,EA8EM,MA9EN,CAAA,MAAA,EA8EqB,mBA9ErB,CAAA,GAAA,SAAA,CAAA,EAAA,MAAA"}
1
+ {"version":3,"file":"domain-type-generation.d.mts","names":[],"sources":["../src/domain-type-generation.ts"],"sourcesContent":[],"mappings":"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"}
@@ -117,62 +117,103 @@ function generateHashTypeAliases(hashes) {
117
117
  `export type ProfileHash = ProfileHashBase<'${hashes.profileHash}'>;`
118
118
  ].join("\n");
119
119
  }
120
- function generateFieldResolvedType(field, codecLookup) {
121
- let baseType;
120
+ function applyModifiers(base, field) {
121
+ let result = base;
122
+ if (field.many === true) result = `ReadonlyArray<${result}>`;
123
+ if (field.dict === true) result = `Readonly<Record<string, ${result}>>`;
124
+ if (field.nullable) result = `${result} | null`;
125
+ return result;
126
+ }
127
+ function resolveFieldType(field, codecLookup) {
122
128
  const { type } = field;
123
129
  switch (type.kind) {
124
130
  case "scalar": {
125
- let resolved;
131
+ let outputResolved;
126
132
  if (codecLookup && type.typeParams && Object.keys(type.typeParams).length > 0) {
127
133
  const codec = codecLookup.get(type.codecId);
128
134
  if (codec?.renderOutputType) {
129
135
  const rendered = codec.renderOutputType(type.typeParams);
130
- if (rendered && isSafeTypeExpression(rendered)) resolved = rendered;
136
+ if (rendered && isSafeTypeExpression(rendered)) outputResolved = rendered;
131
137
  }
132
138
  }
133
- baseType = resolved ?? `CodecTypes[${serializeValue(type.codecId)}]['output']`;
134
- break;
139
+ const codecAccessor = `CodecTypes[${serializeValue(type.codecId)}]`;
140
+ return {
141
+ output: applyModifiers(outputResolved ?? `${codecAccessor}['output']`, field),
142
+ input: applyModifiers(`${codecAccessor}['input']`, field)
143
+ };
135
144
  }
136
- case "valueObject":
137
- baseType = type.name;
138
- break;
139
- case "union":
140
- baseType = type.members.map((m) => {
141
- if (m.kind === "scalar") return `CodecTypes[${serializeValue(m.codecId)}]['output']`;
142
- return m.name;
143
- }).join(" | ");
144
- break;
145
- default:
146
- baseType = "unknown";
147
- break;
145
+ case "valueObject": return {
146
+ output: applyModifiers(`${type.name}Output`, field),
147
+ input: applyModifiers(`${type.name}Input`, field)
148
+ };
149
+ case "union": {
150
+ const outputMembers = type.members.map((m) => m.kind === "scalar" ? `CodecTypes[${serializeValue(m.codecId)}]['output']` : `${m.name}Output`);
151
+ const inputMembers = type.members.map((m) => m.kind === "scalar" ? `CodecTypes[${serializeValue(m.codecId)}]['input']` : `${m.name}Input`);
152
+ return {
153
+ output: applyModifiers(outputMembers.join(" | "), field),
154
+ input: applyModifiers(inputMembers.join(" | "), field)
155
+ };
156
+ }
157
+ default: return {
158
+ output: applyModifiers("unknown", field),
159
+ input: applyModifiers("unknown", field)
160
+ };
148
161
  }
149
- if (field.many === true) baseType = `ReadonlyArray<${baseType}>`;
150
- if (field.dict === true) baseType = `Readonly<Record<string, ${baseType}>>`;
151
- if (field.nullable) baseType = `${baseType} | null`;
152
- return baseType;
153
162
  }
154
- function generateFieldOutputTypesMap(models, codecLookup) {
155
- if (!models || Object.keys(models).length === 0) return "Record<string, never>";
156
- const modelEntries = [];
163
+ function generateFieldResolvedType(field, codecLookup, side = "output") {
164
+ return resolveFieldType(field, codecLookup)[side];
165
+ }
166
+ function generateBothFieldTypesMaps(models, codecLookup) {
167
+ if (!models || Object.keys(models).length === 0) return {
168
+ output: "Record<string, never>",
169
+ input: "Record<string, never>"
170
+ };
171
+ const outputModelEntries = [];
172
+ const inputModelEntries = [];
157
173
  for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {
158
174
  if (!model) continue;
159
- const fieldEntries = [];
175
+ const outputFieldEntries = [];
176
+ const inputFieldEntries = [];
160
177
  for (const [fieldName, field] of Object.entries(model.fields)) {
161
- const resolvedType = generateFieldResolvedType(field, codecLookup);
162
- fieldEntries.push(`readonly ${serializeObjectKey(fieldName)}: ${resolvedType}`);
178
+ const resolved = resolveFieldType(field, codecLookup);
179
+ const key = `readonly ${serializeObjectKey(fieldName)}`;
180
+ outputFieldEntries.push(`${key}: ${resolved.output}`);
181
+ inputFieldEntries.push(`${key}: ${resolved.input}`);
163
182
  }
164
- const fieldsType = fieldEntries.length > 0 ? `{ ${fieldEntries.join("; ")} }` : "Record<string, never>";
165
- modelEntries.push(`readonly ${serializeObjectKey(modelName)}: ${fieldsType}`);
183
+ const outputFields = outputFieldEntries.length > 0 ? `{ ${outputFieldEntries.join("; ")} }` : "Record<string, never>";
184
+ const inputFields = inputFieldEntries.length > 0 ? `{ ${inputFieldEntries.join("; ")} }` : "Record<string, never>";
185
+ const modelKey = `readonly ${serializeObjectKey(modelName)}`;
186
+ outputModelEntries.push(`${modelKey}: ${outputFields}`);
187
+ inputModelEntries.push(`${modelKey}: ${inputFields}`);
166
188
  }
167
- return `{ ${modelEntries.join("; ")} }`;
189
+ return {
190
+ output: `{ ${outputModelEntries.join("; ")} }`,
191
+ input: `{ ${inputModelEntries.join("; ")} }`
192
+ };
168
193
  }
169
- function generateValueObjectType(_voName, vo, _valueObjects) {
170
- const fieldEntries = [];
194
+ function generateFieldOutputTypesMap(models, codecLookup) {
195
+ return generateBothFieldTypesMaps(models, codecLookup).output;
196
+ }
197
+ function generateFieldInputTypesMap(models, codecLookup) {
198
+ return generateBothFieldTypesMaps(models, codecLookup).input;
199
+ }
200
+ function generateValueObjectType(_voName, vo, _valueObjects, side = "output", codecLookup) {
201
+ return resolveValueObjectType(_voName, vo, _valueObjects, codecLookup)[side];
202
+ }
203
+ function resolveValueObjectType(_voName, vo, _valueObjects, codecLookup) {
204
+ const outputEntries = [];
205
+ const inputEntries = [];
171
206
  for (const [fieldName, field] of Object.entries(vo.fields)) {
172
- const tsType = generateFieldResolvedType(field);
173
- fieldEntries.push(`readonly ${serializeObjectKey(fieldName)}: ${tsType}`);
207
+ const resolved = resolveFieldType(field, codecLookup);
208
+ const key = `readonly ${serializeObjectKey(fieldName)}`;
209
+ outputEntries.push(`${key}: ${resolved.output}`);
210
+ inputEntries.push(`${key}: ${resolved.input}`);
174
211
  }
175
- return fieldEntries.length > 0 ? `{ ${fieldEntries.join("; ")} }` : "Record<string, never>";
212
+ const empty = "Record<string, never>";
213
+ return {
214
+ output: outputEntries.length > 0 ? `{ ${outputEntries.join("; ")} }` : empty,
215
+ input: inputEntries.length > 0 ? `{ ${inputEntries.join("; ")} }` : empty
216
+ };
176
217
  }
177
218
  function generateContractFieldDescriptor(fieldName, field) {
178
219
  const mods = [];
@@ -198,16 +239,17 @@ function generateValueObjectsDescriptorType(valueObjects) {
198
239
  }
199
240
  return `{ ${voEntries.join("; ")} }`;
200
241
  }
201
- function generateValueObjectTypeAliases(valueObjects) {
242
+ function generateValueObjectTypeAliases(valueObjects, codecLookup) {
202
243
  if (!valueObjects || Object.keys(valueObjects).length === 0) return "";
203
244
  const aliases = [];
204
245
  for (const [voName, vo] of Object.entries(valueObjects)) {
205
- const voType = generateValueObjectType(voName, vo, valueObjects);
206
- aliases.push(`export type ${voName} = ${voType};`);
246
+ const resolved = resolveValueObjectType(voName, vo, valueObjects, codecLookup);
247
+ aliases.push(`export type ${voName}Output = ${resolved.output};`);
248
+ aliases.push(`export type ${voName}Input = ${resolved.input};`);
207
249
  }
208
250
  return aliases.join("\n");
209
251
  }
210
252
 
211
253
  //#endregion
212
- export { deduplicateImports, generateCodecTypeIntersection, generateContractFieldDescriptor, generateFieldOutputTypesMap, generateFieldResolvedType, generateHashTypeAliases, generateImportLines, generateModelFieldEntry, generateModelFieldsType, generateModelRelationsType, generateModelsType, generateRootsType, generateValueObjectType, generateValueObjectTypeAliases, generateValueObjectsDescriptorType, serializeExecutionType, serializeObjectKey, serializeValue };
254
+ export { deduplicateImports, generateBothFieldTypesMaps, generateCodecTypeIntersection, generateContractFieldDescriptor, generateFieldInputTypesMap, generateFieldOutputTypesMap, generateFieldResolvedType, generateHashTypeAliases, generateImportLines, generateModelFieldEntry, generateModelFieldsType, generateModelRelationsType, generateModelsType, generateRootsType, generateValueObjectType, generateValueObjectTypeAliases, generateValueObjectsDescriptorType, resolveFieldType, resolveValueObjectType, serializeExecutionType, serializeObjectKey, serializeValue };
213
255
  //# sourceMappingURL=domain-type-generation.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"domain-type-generation.mjs","names":["entries: string[]","fieldEntries: string[]","relationEntries: string[]","parts: string[]","modelTypes: string[]","modelParts: string[]","result: TypesImportSpec[]","baseType: string","resolved: string | undefined","modelEntries: string[]","mods: string[]","voEntries: string[]","aliases: string[]"],"sources":["../src/domain-type-generation.ts"],"sourcesContent":["import type {\n ContractField,\n ContractModel,\n ContractValueObject,\n} from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { TypesImportSpec } from '@prisma-next/framework-components/emission';\nimport { isSafeTypeExpression } from './type-expression-safety';\n\nexport function serializeValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n if (value === undefined) {\n return 'undefined';\n }\n if (typeof value === 'string') {\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n return `'${escaped}'`;\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (typeof value === 'bigint') {\n return `${value}n`;\n }\n if (Array.isArray(value)) {\n const items = value.map((v) => serializeValue(v)).join(', ');\n return `readonly [${items}]`;\n }\n if (typeof value === 'object') {\n const entries: string[] = [];\n for (const [k, v] of Object.entries(value)) {\n entries.push(`readonly ${serializeObjectKey(k)}: ${serializeValue(v)}`);\n }\n return `{ ${entries.join('; ')} }`;\n }\n return 'unknown';\n}\n\nexport function serializeObjectKey(key: string): string {\n if (/^[$A-Z_a-z][$\\w]*$/.test(key)) {\n return key;\n }\n return serializeValue(key);\n}\n\nexport function generateRootsType(roots: Record<string, string> | undefined): string {\n if (!roots || Object.keys(roots).length === 0) {\n return 'Record<string, string>';\n }\n const entries = Object.entries(roots)\n .map(([key, value]) => `readonly ${serializeObjectKey(key)}: ${serializeValue(value)}`)\n .join('; ');\n return `{ ${entries} }`;\n}\n\nfunction contractFieldModifierSuffix(field: ContractField): string {\n const many = field.many === true ? '; readonly many: true' : '';\n const dict = field.dict === true ? '; readonly dict: true' : '';\n return many + dict;\n}\n\nexport function generateModelFieldEntry(fieldName: string, field: ContractField): string {\n const mods = contractFieldModifierSuffix(field);\n const { nullable, type } = field;\n if (type.kind === 'scalar') {\n const typeParamsSpec =\n type.typeParams && Object.keys(type.typeParams).length > 0\n ? `; readonly typeParams: ${serializeValue(type.typeParams)}`\n : '';\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${nullable}; readonly type: { readonly kind: 'scalar'; readonly codecId: ${serializeValue(type.codecId)}${typeParamsSpec} }${mods} }`;\n }\n if (type.kind === 'valueObject') {\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${nullable}; readonly type: { readonly kind: 'valueObject'; readonly name: ${serializeValue(type.name)} }${mods} }`;\n }\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${nullable}; readonly type: ${serializeValue(type)}${mods} }`;\n}\n\nexport function generateModelFieldsType(fields: Record<string, ContractField>): string {\n const fieldEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(fields)) {\n fieldEntries.push(generateModelFieldEntry(fieldName, field));\n }\n return fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';\n}\n\nexport function generateModelRelationsType(relations: Record<string, unknown>): string {\n const relationEntries: string[] = [];\n\n for (const [relName, rel] of Object.entries(relations)) {\n if (typeof rel !== 'object' || rel === null) continue;\n const relObj = rel as Record<string, unknown>;\n const parts: string[] = [];\n\n if (relObj['to']) parts.push(`readonly to: ${serializeValue(relObj['to'])}`);\n if (relObj['cardinality'])\n parts.push(`readonly cardinality: ${serializeValue(relObj['cardinality'])}`);\n\n const on = relObj['on'] as { localFields?: string[]; targetFields?: string[] } | undefined;\n if (on && (!on.localFields || !on.targetFields)) {\n throw new Error(\n `Relation \"${relName}\" has an \"on\" block but is missing localFields or targetFields`,\n );\n }\n if (on?.localFields && on.targetFields) {\n const localFields = on.localFields.map((f) => serializeValue(f)).join(', ');\n const targetFields = on.targetFields.map((f) => serializeValue(f)).join(', ');\n parts.push(\n `readonly on: { readonly localFields: readonly [${localFields}]; readonly targetFields: readonly [${targetFields}] }`,\n );\n }\n\n if (parts.length > 0) {\n relationEntries.push(`readonly ${relName}: { ${parts.join('; ')} }`);\n }\n }\n\n if (relationEntries.length === 0) {\n return 'Record<string, never>';\n }\n\n return `{ ${relationEntries.join('; ')} }`;\n}\n\nexport function generateModelsType(\n models: Record<string, ContractModel>,\n generateModelStorage: (modelName: string, model: ContractModel) => string,\n): string {\n if (!models || Object.keys(models).length === 0) {\n return 'Record<string, never>';\n }\n\n const modelTypes: string[] = [];\n for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {\n const fieldsType = generateModelFieldsType(model.fields);\n const relationsType = generateModelRelationsType(model.relations);\n const storageType = generateModelStorage(modelName, model);\n\n const modelParts: string[] = [\n `readonly fields: ${fieldsType}`,\n `readonly relations: ${relationsType}`,\n `readonly storage: ${storageType}`,\n ];\n\n if (model.owner) {\n modelParts.push(`readonly owner: ${serializeValue(model.owner)}`);\n }\n if (model.discriminator) {\n modelParts.push(`readonly discriminator: ${serializeValue(model.discriminator)}`);\n }\n if (model.variants) {\n modelParts.push(`readonly variants: ${serializeValue(model.variants)}`);\n }\n if (model.base) {\n modelParts.push(`readonly base: ${serializeValue(model.base)}`);\n }\n\n modelTypes.push(`readonly ${modelName}: { ${modelParts.join('; ')} }`);\n }\n\n return `{ ${modelTypes.join('; ')} }`;\n}\n\nexport function deduplicateImports(imports: TypesImportSpec[]): TypesImportSpec[] {\n const seenKeys = new Set<string>();\n const result: TypesImportSpec[] = [];\n for (const imp of imports) {\n const key = `${imp.package}::${imp.named}`;\n if (!seenKeys.has(key)) {\n seenKeys.add(key);\n result.push(imp);\n }\n }\n return result;\n}\n\nexport function generateImportLines(imports: TypesImportSpec[]): string[] {\n return imports.map((imp) => {\n const importClause = imp.named === imp.alias ? imp.named : `${imp.named} as ${imp.alias}`;\n return `import type { ${importClause} } from '${imp.package}';`;\n });\n}\n\nexport function generateCodecTypeIntersection(\n imports: ReadonlyArray<TypesImportSpec>,\n named: string,\n): string {\n const aliases = imports.filter((imp) => imp.named === named).map((imp) => imp.alias);\n return aliases.join(' & ') || 'Record<string, never>';\n}\n\nexport function serializeExecutionType(execution: Record<string, unknown>): string {\n const parts: string[] = ['readonly executionHash: ExecutionHash'];\n for (const [key, value] of Object.entries(execution)) {\n if (key === 'executionHash') continue;\n parts.push(`readonly ${serializeObjectKey(key)}: ${serializeValue(value)}`);\n }\n return `{ ${parts.join('; ')} }`;\n}\n\nexport function generateHashTypeAliases(hashes: {\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n}): string {\n const executionHashType = hashes.executionHash\n ? `ExecutionHashBase<'${hashes.executionHash}'>`\n : 'ExecutionHashBase<string>';\n\n return [\n `export type StorageHash = StorageHashBase<'${hashes.storageHash}'>;`,\n `export type ExecutionHash = ${executionHashType};`,\n `export type ProfileHash = ProfileHashBase<'${hashes.profileHash}'>;`,\n ].join('\\n');\n}\n\nexport function generateFieldResolvedType(field: ContractField, codecLookup?: CodecLookup): string {\n let baseType: string;\n const { type } = field;\n\n switch (type.kind) {\n case 'scalar': {\n let resolved: string | undefined;\n if (codecLookup && type.typeParams && Object.keys(type.typeParams).length > 0) {\n const codec = codecLookup.get(type.codecId);\n if (codec?.renderOutputType) {\n const rendered = codec.renderOutputType(type.typeParams);\n if (rendered && isSafeTypeExpression(rendered)) {\n resolved = rendered;\n }\n }\n }\n baseType = resolved ?? `CodecTypes[${serializeValue(type.codecId)}]['output']`;\n break;\n }\n case 'valueObject':\n baseType = type.name;\n break;\n case 'union': {\n const memberTypes = type.members.map((m) => {\n if (m.kind === 'scalar') return `CodecTypes[${serializeValue(m.codecId)}]['output']`;\n return m.name;\n });\n baseType = memberTypes.join(' | ');\n break;\n }\n default:\n baseType = 'unknown';\n break;\n }\n\n if (field.many === true) {\n baseType = `ReadonlyArray<${baseType}>`;\n }\n if (field.dict === true) {\n baseType = `Readonly<Record<string, ${baseType}>>`;\n }\n if (field.nullable) {\n baseType = `${baseType} | null`;\n }\n\n return baseType;\n}\n\nexport function generateFieldOutputTypesMap(\n models: Record<string, ContractModel> | undefined,\n codecLookup?: CodecLookup,\n): string {\n if (!models || Object.keys(models).length === 0) {\n return 'Record<string, never>';\n }\n\n const modelEntries: string[] = [];\n for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {\n if (!model) continue;\n const fieldEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(model.fields)) {\n const resolvedType = generateFieldResolvedType(field, codecLookup);\n fieldEntries.push(`readonly ${serializeObjectKey(fieldName)}: ${resolvedType}`);\n }\n const fieldsType =\n fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';\n modelEntries.push(`readonly ${serializeObjectKey(modelName)}: ${fieldsType}`);\n }\n\n return `{ ${modelEntries.join('; ')} }`;\n}\n\nexport function generateValueObjectType(\n _voName: string,\n vo: ContractValueObject,\n _valueObjects: Record<string, ContractValueObject>,\n): string {\n const fieldEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(vo.fields)) {\n const tsType = generateFieldResolvedType(field);\n fieldEntries.push(`readonly ${serializeObjectKey(fieldName)}: ${tsType}`);\n }\n return fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';\n}\n\nexport function generateContractFieldDescriptor(fieldName: string, field: ContractField): string {\n const mods: string[] = [];\n if (field.many === true) mods.push('; readonly many: true');\n if (field.dict === true) mods.push('; readonly dict: true');\n const modStr = mods.join('');\n\n const { type } = field;\n if (type.kind === 'scalar') {\n const typeParamsSpec =\n type.typeParams && Object.keys(type.typeParams).length > 0\n ? `; readonly typeParams: ${serializeValue(type.typeParams)}`\n : '';\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${field.nullable}; readonly type: { readonly kind: 'scalar'; readonly codecId: ${serializeValue(type.codecId)}${typeParamsSpec} }${modStr} }`;\n }\n if (type.kind === 'valueObject') {\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${field.nullable}; readonly type: { readonly kind: 'valueObject'; readonly name: ${serializeValue(type.name)} }${modStr} }`;\n }\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${field.nullable}; readonly type: ${serializeValue(type)}${modStr} }`;\n}\n\nexport function generateValueObjectsDescriptorType(\n valueObjects: Record<string, ContractValueObject> | undefined,\n): string {\n if (!valueObjects || Object.keys(valueObjects).length === 0) {\n return 'Record<string, never>';\n }\n\n const voEntries: string[] = [];\n for (const [voName, vo] of Object.entries(valueObjects)) {\n const fieldEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(vo.fields)) {\n fieldEntries.push(generateContractFieldDescriptor(fieldName, field));\n }\n const fieldsType =\n fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';\n voEntries.push(`readonly ${serializeObjectKey(voName)}: { readonly fields: ${fieldsType} }`);\n }\n\n return `{ ${voEntries.join('; ')} }`;\n}\n\nexport function generateValueObjectTypeAliases(\n valueObjects: Record<string, ContractValueObject> | undefined,\n): string {\n if (!valueObjects || Object.keys(valueObjects).length === 0) {\n return '';\n }\n\n const aliases: string[] = [];\n for (const [voName, vo] of Object.entries(valueObjects)) {\n const voType = generateValueObjectType(voName, vo, valueObjects);\n aliases.push(`export type ${voName} = ${voType};`);\n }\n return aliases.join('\\n');\n}\n"],"mappings":";;;AASA,SAAgB,eAAe,OAAwB;AACrD,KAAI,UAAU,KACZ,QAAO;AAET,KAAI,UAAU,OACZ,QAAO;AAET,KAAI,OAAO,UAAU,SAEnB,QAAO,IADS,MAAM,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,MAAM,CAC9C;AAErB,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAChD,QAAO,OAAO,MAAM;AAEtB,KAAI,OAAO,UAAU,SACnB,QAAO,GAAG,MAAM;AAElB,KAAI,MAAM,QAAQ,MAAM,CAEtB,QAAO,aADO,MAAM,KAAK,MAAM,eAAe,EAAE,CAAC,CAAC,KAAK,KAAK,CAClC;AAE5B,KAAI,OAAO,UAAU,UAAU;EAC7B,MAAMA,UAAoB,EAAE;AAC5B,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,CACxC,SAAQ,KAAK,YAAY,mBAAmB,EAAE,CAAC,IAAI,eAAe,EAAE,GAAG;AAEzE,SAAO,KAAK,QAAQ,KAAK,KAAK,CAAC;;AAEjC,QAAO;;AAGT,SAAgB,mBAAmB,KAAqB;AACtD,KAAI,qBAAqB,KAAK,IAAI,CAChC,QAAO;AAET,QAAO,eAAe,IAAI;;AAG5B,SAAgB,kBAAkB,OAAmD;AACnF,KAAI,CAAC,SAAS,OAAO,KAAK,MAAM,CAAC,WAAW,EAC1C,QAAO;AAKT,QAAO,KAHS,OAAO,QAAQ,MAAM,CAClC,KAAK,CAAC,KAAK,WAAW,YAAY,mBAAmB,IAAI,CAAC,IAAI,eAAe,MAAM,GAAG,CACtF,KAAK,KAAK,CACO;;AAGtB,SAAS,4BAA4B,OAA8B;AAGjE,SAFa,MAAM,SAAS,OAAO,0BAA0B,OAChD,MAAM,SAAS,OAAO,0BAA0B;;AAI/D,SAAgB,wBAAwB,WAAmB,OAA8B;CACvF,MAAM,OAAO,4BAA4B,MAAM;CAC/C,MAAM,EAAE,UAAU,SAAS;AAC3B,KAAI,KAAK,SAAS,UAAU;EAC1B,MAAM,iBACJ,KAAK,cAAc,OAAO,KAAK,KAAK,WAAW,CAAC,SAAS,IACrD,0BAA0B,eAAe,KAAK,WAAW,KACzD;AACN,SAAO,YAAY,mBAAmB,UAAU,CAAC,yBAAyB,SAAS,gEAAgE,eAAe,KAAK,QAAQ,GAAG,eAAe,IAAI,KAAK;;AAE5M,KAAI,KAAK,SAAS,cAChB,QAAO,YAAY,mBAAmB,UAAU,CAAC,yBAAyB,SAAS,kEAAkE,eAAe,KAAK,KAAK,CAAC,IAAI,KAAK;AAE1L,QAAO,YAAY,mBAAmB,UAAU,CAAC,yBAAyB,SAAS,mBAAmB,eAAe,KAAK,GAAG,KAAK;;AAGpI,SAAgB,wBAAwB,QAA+C;CACrF,MAAMC,eAAyB,EAAE;AACjC,MAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,OAAO,CACrD,cAAa,KAAK,wBAAwB,WAAW,MAAM,CAAC;AAE9D,QAAO,aAAa,SAAS,IAAI,KAAK,aAAa,KAAK,KAAK,CAAC,MAAM;;AAGtE,SAAgB,2BAA2B,WAA4C;CACrF,MAAMC,kBAA4B,EAAE;AAEpC,MAAK,MAAM,CAAC,SAAS,QAAQ,OAAO,QAAQ,UAAU,EAAE;AACtD,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM;EAC7C,MAAM,SAAS;EACf,MAAMC,QAAkB,EAAE;AAE1B,MAAI,OAAO,MAAO,OAAM,KAAK,gBAAgB,eAAe,OAAO,MAAM,GAAG;AAC5E,MAAI,OAAO,eACT,OAAM,KAAK,yBAAyB,eAAe,OAAO,eAAe,GAAG;EAE9E,MAAM,KAAK,OAAO;AAClB,MAAI,OAAO,CAAC,GAAG,eAAe,CAAC,GAAG,cAChC,OAAM,IAAI,MACR,aAAa,QAAQ,gEACtB;AAEH,MAAI,IAAI,eAAe,GAAG,cAAc;GACtC,MAAM,cAAc,GAAG,YAAY,KAAK,MAAM,eAAe,EAAE,CAAC,CAAC,KAAK,KAAK;GAC3E,MAAM,eAAe,GAAG,aAAa,KAAK,MAAM,eAAe,EAAE,CAAC,CAAC,KAAK,KAAK;AAC7E,SAAM,KACJ,kDAAkD,YAAY,sCAAsC,aAAa,KAClH;;AAGH,MAAI,MAAM,SAAS,EACjB,iBAAgB,KAAK,YAAY,QAAQ,MAAM,MAAM,KAAK,KAAK,CAAC,IAAI;;AAIxE,KAAI,gBAAgB,WAAW,EAC7B,QAAO;AAGT,QAAO,KAAK,gBAAgB,KAAK,KAAK,CAAC;;AAGzC,SAAgB,mBACd,QACA,sBACQ;AACR,KAAI,CAAC,UAAU,OAAO,KAAK,OAAO,CAAC,WAAW,EAC5C,QAAO;CAGT,MAAMC,aAAuB,EAAE;AAC/B,MAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;EAC9F,MAAM,aAAa,wBAAwB,MAAM,OAAO;EACxD,MAAM,gBAAgB,2BAA2B,MAAM,UAAU;EACjE,MAAM,cAAc,qBAAqB,WAAW,MAAM;EAE1D,MAAMC,aAAuB;GAC3B,oBAAoB;GACpB,uBAAuB;GACvB,qBAAqB;GACtB;AAED,MAAI,MAAM,MACR,YAAW,KAAK,mBAAmB,eAAe,MAAM,MAAM,GAAG;AAEnE,MAAI,MAAM,cACR,YAAW,KAAK,2BAA2B,eAAe,MAAM,cAAc,GAAG;AAEnF,MAAI,MAAM,SACR,YAAW,KAAK,sBAAsB,eAAe,MAAM,SAAS,GAAG;AAEzE,MAAI,MAAM,KACR,YAAW,KAAK,kBAAkB,eAAe,MAAM,KAAK,GAAG;AAGjE,aAAW,KAAK,YAAY,UAAU,MAAM,WAAW,KAAK,KAAK,CAAC,IAAI;;AAGxE,QAAO,KAAK,WAAW,KAAK,KAAK,CAAC;;AAGpC,SAAgB,mBAAmB,SAA+C;CAChF,MAAM,2BAAW,IAAI,KAAa;CAClC,MAAMC,SAA4B,EAAE;AACpC,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,MAAM,GAAG,IAAI,QAAQ,IAAI,IAAI;AACnC,MAAI,CAAC,SAAS,IAAI,IAAI,EAAE;AACtB,YAAS,IAAI,IAAI;AACjB,UAAO,KAAK,IAAI;;;AAGpB,QAAO;;AAGT,SAAgB,oBAAoB,SAAsC;AACxE,QAAO,QAAQ,KAAK,QAAQ;AAE1B,SAAO,iBADc,IAAI,UAAU,IAAI,QAAQ,IAAI,QAAQ,GAAG,IAAI,MAAM,MAAM,IAAI,QAC7C,WAAW,IAAI,QAAQ;GAC5D;;AAGJ,SAAgB,8BACd,SACA,OACQ;AAER,QADgB,QAAQ,QAAQ,QAAQ,IAAI,UAAU,MAAM,CAAC,KAAK,QAAQ,IAAI,MAAM,CACrE,KAAK,MAAM,IAAI;;AAGhC,SAAgB,uBAAuB,WAA4C;CACjF,MAAMH,QAAkB,CAAC,wCAAwC;AACjE,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,UAAU,EAAE;AACpD,MAAI,QAAQ,gBAAiB;AAC7B,QAAM,KAAK,YAAY,mBAAmB,IAAI,CAAC,IAAI,eAAe,MAAM,GAAG;;AAE7E,QAAO,KAAK,MAAM,KAAK,KAAK,CAAC;;AAG/B,SAAgB,wBAAwB,QAI7B;CACT,MAAM,oBAAoB,OAAO,gBAC7B,sBAAsB,OAAO,cAAc,MAC3C;AAEJ,QAAO;EACL,8CAA8C,OAAO,YAAY;EACjE,+BAA+B,kBAAkB;EACjD,8CAA8C,OAAO,YAAY;EAClE,CAAC,KAAK,KAAK;;AAGd,SAAgB,0BAA0B,OAAsB,aAAmC;CACjG,IAAII;CACJ,MAAM,EAAE,SAAS;AAEjB,SAAQ,KAAK,MAAb;EACE,KAAK,UAAU;GACb,IAAIC;AACJ,OAAI,eAAe,KAAK,cAAc,OAAO,KAAK,KAAK,WAAW,CAAC,SAAS,GAAG;IAC7E,MAAM,QAAQ,YAAY,IAAI,KAAK,QAAQ;AAC3C,QAAI,OAAO,kBAAkB;KAC3B,MAAM,WAAW,MAAM,iBAAiB,KAAK,WAAW;AACxD,SAAI,YAAY,qBAAqB,SAAS,CAC5C,YAAW;;;AAIjB,cAAW,YAAY,cAAc,eAAe,KAAK,QAAQ,CAAC;AAClE;;EAEF,KAAK;AACH,cAAW,KAAK;AAChB;EACF,KAAK;AAKH,cAJoB,KAAK,QAAQ,KAAK,MAAM;AAC1C,QAAI,EAAE,SAAS,SAAU,QAAO,cAAc,eAAe,EAAE,QAAQ,CAAC;AACxE,WAAO,EAAE;KACT,CACqB,KAAK,MAAM;AAClC;EAEF;AACE,cAAW;AACX;;AAGJ,KAAI,MAAM,SAAS,KACjB,YAAW,iBAAiB,SAAS;AAEvC,KAAI,MAAM,SAAS,KACjB,YAAW,2BAA2B,SAAS;AAEjD,KAAI,MAAM,SACR,YAAW,GAAG,SAAS;AAGzB,QAAO;;AAGT,SAAgB,4BACd,QACA,aACQ;AACR,KAAI,CAAC,UAAU,OAAO,KAAK,OAAO,CAAC,WAAW,EAC5C,QAAO;CAGT,MAAMC,eAAyB,EAAE;AACjC,MAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;AAC9F,MAAI,CAAC,MAAO;EACZ,MAAMR,eAAyB,EAAE;AACjC,OAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,MAAM,OAAO,EAAE;GAC7D,MAAM,eAAe,0BAA0B,OAAO,YAAY;AAClE,gBAAa,KAAK,YAAY,mBAAmB,UAAU,CAAC,IAAI,eAAe;;EAEjF,MAAM,aACJ,aAAa,SAAS,IAAI,KAAK,aAAa,KAAK,KAAK,CAAC,MAAM;AAC/D,eAAa,KAAK,YAAY,mBAAmB,UAAU,CAAC,IAAI,aAAa;;AAG/E,QAAO,KAAK,aAAa,KAAK,KAAK,CAAC;;AAGtC,SAAgB,wBACd,SACA,IACA,eACQ;CACR,MAAMA,eAAyB,EAAE;AACjC,MAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,GAAG,OAAO,EAAE;EAC1D,MAAM,SAAS,0BAA0B,MAAM;AAC/C,eAAa,KAAK,YAAY,mBAAmB,UAAU,CAAC,IAAI,SAAS;;AAE3E,QAAO,aAAa,SAAS,IAAI,KAAK,aAAa,KAAK,KAAK,CAAC,MAAM;;AAGtE,SAAgB,gCAAgC,WAAmB,OAA8B;CAC/F,MAAMS,OAAiB,EAAE;AACzB,KAAI,MAAM,SAAS,KAAM,MAAK,KAAK,wBAAwB;AAC3D,KAAI,MAAM,SAAS,KAAM,MAAK,KAAK,wBAAwB;CAC3D,MAAM,SAAS,KAAK,KAAK,GAAG;CAE5B,MAAM,EAAE,SAAS;AACjB,KAAI,KAAK,SAAS,UAAU;EAC1B,MAAM,iBACJ,KAAK,cAAc,OAAO,KAAK,KAAK,WAAW,CAAC,SAAS,IACrD,0BAA0B,eAAe,KAAK,WAAW,KACzD;AACN,SAAO,YAAY,mBAAmB,UAAU,CAAC,yBAAyB,MAAM,SAAS,gEAAgE,eAAe,KAAK,QAAQ,GAAG,eAAe,IAAI,OAAO;;AAEpN,KAAI,KAAK,SAAS,cAChB,QAAO,YAAY,mBAAmB,UAAU,CAAC,yBAAyB,MAAM,SAAS,kEAAkE,eAAe,KAAK,KAAK,CAAC,IAAI,OAAO;AAElM,QAAO,YAAY,mBAAmB,UAAU,CAAC,yBAAyB,MAAM,SAAS,mBAAmB,eAAe,KAAK,GAAG,OAAO;;AAG5I,SAAgB,mCACd,cACQ;AACR,KAAI,CAAC,gBAAgB,OAAO,KAAK,aAAa,CAAC,WAAW,EACxD,QAAO;CAGT,MAAMC,YAAsB,EAAE;AAC9B,MAAK,MAAM,CAAC,QAAQ,OAAO,OAAO,QAAQ,aAAa,EAAE;EACvD,MAAMV,eAAyB,EAAE;AACjC,OAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,GAAG,OAAO,CACxD,cAAa,KAAK,gCAAgC,WAAW,MAAM,CAAC;EAEtE,MAAM,aACJ,aAAa,SAAS,IAAI,KAAK,aAAa,KAAK,KAAK,CAAC,MAAM;AAC/D,YAAU,KAAK,YAAY,mBAAmB,OAAO,CAAC,uBAAuB,WAAW,IAAI;;AAG9F,QAAO,KAAK,UAAU,KAAK,KAAK,CAAC;;AAGnC,SAAgB,+BACd,cACQ;AACR,KAAI,CAAC,gBAAgB,OAAO,KAAK,aAAa,CAAC,WAAW,EACxD,QAAO;CAGT,MAAMW,UAAoB,EAAE;AAC5B,MAAK,MAAM,CAAC,QAAQ,OAAO,OAAO,QAAQ,aAAa,EAAE;EACvD,MAAM,SAAS,wBAAwB,QAAQ,IAAI,aAAa;AAChE,UAAQ,KAAK,eAAe,OAAO,KAAK,OAAO,GAAG;;AAEpD,QAAO,QAAQ,KAAK,KAAK"}
1
+ {"version":3,"file":"domain-type-generation.mjs","names":["entries: string[]","fieldEntries: string[]","relationEntries: string[]","parts: string[]","modelTypes: string[]","modelParts: string[]","result: TypesImportSpec[]","outputResolved: string | undefined","outputModelEntries: string[]","inputModelEntries: string[]","outputFieldEntries: string[]","inputFieldEntries: string[]","outputEntries: string[]","inputEntries: string[]","mods: string[]","voEntries: string[]","aliases: string[]"],"sources":["../src/domain-type-generation.ts"],"sourcesContent":["import type {\n ContractField,\n ContractModel,\n ContractValueObject,\n} from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type { TypesImportSpec } from '@prisma-next/framework-components/emission';\nimport { isSafeTypeExpression } from './type-expression-safety';\n\nexport function serializeValue(value: unknown): string {\n if (value === null) {\n return 'null';\n }\n if (value === undefined) {\n return 'undefined';\n }\n if (typeof value === 'string') {\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n return `'${escaped}'`;\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n if (typeof value === 'bigint') {\n return `${value}n`;\n }\n if (Array.isArray(value)) {\n const items = value.map((v) => serializeValue(v)).join(', ');\n return `readonly [${items}]`;\n }\n if (typeof value === 'object') {\n const entries: string[] = [];\n for (const [k, v] of Object.entries(value)) {\n entries.push(`readonly ${serializeObjectKey(k)}: ${serializeValue(v)}`);\n }\n return `{ ${entries.join('; ')} }`;\n }\n return 'unknown';\n}\n\nexport function serializeObjectKey(key: string): string {\n if (/^[$A-Z_a-z][$\\w]*$/.test(key)) {\n return key;\n }\n return serializeValue(key);\n}\n\nexport function generateRootsType(roots: Record<string, string> | undefined): string {\n if (!roots || Object.keys(roots).length === 0) {\n return 'Record<string, string>';\n }\n const entries = Object.entries(roots)\n .map(([key, value]) => `readonly ${serializeObjectKey(key)}: ${serializeValue(value)}`)\n .join('; ');\n return `{ ${entries} }`;\n}\n\nfunction contractFieldModifierSuffix(field: ContractField): string {\n const many = field.many === true ? '; readonly many: true' : '';\n const dict = field.dict === true ? '; readonly dict: true' : '';\n return many + dict;\n}\n\nexport function generateModelFieldEntry(fieldName: string, field: ContractField): string {\n const mods = contractFieldModifierSuffix(field);\n const { nullable, type } = field;\n if (type.kind === 'scalar') {\n const typeParamsSpec =\n type.typeParams && Object.keys(type.typeParams).length > 0\n ? `; readonly typeParams: ${serializeValue(type.typeParams)}`\n : '';\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${nullable}; readonly type: { readonly kind: 'scalar'; readonly codecId: ${serializeValue(type.codecId)}${typeParamsSpec} }${mods} }`;\n }\n if (type.kind === 'valueObject') {\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${nullable}; readonly type: { readonly kind: 'valueObject'; readonly name: ${serializeValue(type.name)} }${mods} }`;\n }\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${nullable}; readonly type: ${serializeValue(type)}${mods} }`;\n}\n\nexport function generateModelFieldsType(fields: Record<string, ContractField>): string {\n const fieldEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(fields)) {\n fieldEntries.push(generateModelFieldEntry(fieldName, field));\n }\n return fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';\n}\n\nexport function generateModelRelationsType(relations: Record<string, unknown>): string {\n const relationEntries: string[] = [];\n\n for (const [relName, rel] of Object.entries(relations)) {\n if (typeof rel !== 'object' || rel === null) continue;\n const relObj = rel as Record<string, unknown>;\n const parts: string[] = [];\n\n if (relObj['to']) parts.push(`readonly to: ${serializeValue(relObj['to'])}`);\n if (relObj['cardinality'])\n parts.push(`readonly cardinality: ${serializeValue(relObj['cardinality'])}`);\n\n const on = relObj['on'] as { localFields?: string[]; targetFields?: string[] } | undefined;\n if (on && (!on.localFields || !on.targetFields)) {\n throw new Error(\n `Relation \"${relName}\" has an \"on\" block but is missing localFields or targetFields`,\n );\n }\n if (on?.localFields && on.targetFields) {\n const localFields = on.localFields.map((f) => serializeValue(f)).join(', ');\n const targetFields = on.targetFields.map((f) => serializeValue(f)).join(', ');\n parts.push(\n `readonly on: { readonly localFields: readonly [${localFields}]; readonly targetFields: readonly [${targetFields}] }`,\n );\n }\n\n if (parts.length > 0) {\n relationEntries.push(`readonly ${relName}: { ${parts.join('; ')} }`);\n }\n }\n\n if (relationEntries.length === 0) {\n return 'Record<string, never>';\n }\n\n return `{ ${relationEntries.join('; ')} }`;\n}\n\nexport function generateModelsType(\n models: Record<string, ContractModel>,\n generateModelStorage: (modelName: string, model: ContractModel) => string,\n): string {\n if (!models || Object.keys(models).length === 0) {\n return 'Record<string, never>';\n }\n\n const modelTypes: string[] = [];\n for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {\n const fieldsType = generateModelFieldsType(model.fields);\n const relationsType = generateModelRelationsType(model.relations);\n const storageType = generateModelStorage(modelName, model);\n\n const modelParts: string[] = [\n `readonly fields: ${fieldsType}`,\n `readonly relations: ${relationsType}`,\n `readonly storage: ${storageType}`,\n ];\n\n if (model.owner) {\n modelParts.push(`readonly owner: ${serializeValue(model.owner)}`);\n }\n if (model.discriminator) {\n modelParts.push(`readonly discriminator: ${serializeValue(model.discriminator)}`);\n }\n if (model.variants) {\n modelParts.push(`readonly variants: ${serializeValue(model.variants)}`);\n }\n if (model.base) {\n modelParts.push(`readonly base: ${serializeValue(model.base)}`);\n }\n\n modelTypes.push(`readonly ${modelName}: { ${modelParts.join('; ')} }`);\n }\n\n return `{ ${modelTypes.join('; ')} }`;\n}\n\nexport function deduplicateImports(imports: TypesImportSpec[]): TypesImportSpec[] {\n const seenKeys = new Set<string>();\n const result: TypesImportSpec[] = [];\n for (const imp of imports) {\n const key = `${imp.package}::${imp.named}`;\n if (!seenKeys.has(key)) {\n seenKeys.add(key);\n result.push(imp);\n }\n }\n return result;\n}\n\nexport function generateImportLines(imports: TypesImportSpec[]): string[] {\n return imports.map((imp) => {\n const importClause = imp.named === imp.alias ? imp.named : `${imp.named} as ${imp.alias}`;\n return `import type { ${importClause} } from '${imp.package}';`;\n });\n}\n\nexport function generateCodecTypeIntersection(\n imports: ReadonlyArray<TypesImportSpec>,\n named: string,\n): string {\n const aliases = imports.filter((imp) => imp.named === named).map((imp) => imp.alias);\n return aliases.join(' & ') || 'Record<string, never>';\n}\n\nexport function serializeExecutionType(execution: Record<string, unknown>): string {\n const parts: string[] = ['readonly executionHash: ExecutionHash'];\n for (const [key, value] of Object.entries(execution)) {\n if (key === 'executionHash') continue;\n parts.push(`readonly ${serializeObjectKey(key)}: ${serializeValue(value)}`);\n }\n return `{ ${parts.join('; ')} }`;\n}\n\nexport function generateHashTypeAliases(hashes: {\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n}): string {\n const executionHashType = hashes.executionHash\n ? `ExecutionHashBase<'${hashes.executionHash}'>`\n : 'ExecutionHashBase<string>';\n\n return [\n `export type StorageHash = StorageHashBase<'${hashes.storageHash}'>;`,\n `export type ExecutionHash = ${executionHashType};`,\n `export type ProfileHash = ProfileHashBase<'${hashes.profileHash}'>;`,\n ].join('\\n');\n}\n\nexport type ResolvedFieldType = { readonly input: string; readonly output: string };\n\nfunction applyModifiers(base: string, field: ContractField): string {\n let result = base;\n if (field.many === true) result = `ReadonlyArray<${result}>`;\n if (field.dict === true) result = `Readonly<Record<string, ${result}>>`;\n if (field.nullable) result = `${result} | null`;\n return result;\n}\n\nexport function resolveFieldType(\n field: ContractField,\n codecLookup?: CodecLookup,\n): ResolvedFieldType {\n const { type } = field;\n\n switch (type.kind) {\n case 'scalar': {\n let outputResolved: string | undefined;\n if (codecLookup && type.typeParams && Object.keys(type.typeParams).length > 0) {\n const codec = codecLookup.get(type.codecId);\n if (codec?.renderOutputType) {\n const rendered = codec.renderOutputType(type.typeParams);\n if (rendered && isSafeTypeExpression(rendered)) {\n outputResolved = rendered;\n }\n }\n }\n const codecAccessor = `CodecTypes[${serializeValue(type.codecId)}]`;\n return {\n output: applyModifiers(outputResolved ?? `${codecAccessor}['output']`, field),\n input: applyModifiers(`${codecAccessor}['input']`, field),\n };\n }\n case 'valueObject':\n return {\n output: applyModifiers(`${type.name}Output`, field),\n input: applyModifiers(`${type.name}Input`, field),\n };\n case 'union': {\n const outputMembers = type.members.map((m) =>\n m.kind === 'scalar'\n ? `CodecTypes[${serializeValue(m.codecId)}]['output']`\n : `${m.name}Output`,\n );\n const inputMembers = type.members.map((m) =>\n m.kind === 'scalar'\n ? `CodecTypes[${serializeValue(m.codecId)}]['input']`\n : `${m.name}Input`,\n );\n return {\n output: applyModifiers(outputMembers.join(' | '), field),\n input: applyModifiers(inputMembers.join(' | '), field),\n };\n }\n default:\n return {\n output: applyModifiers('unknown', field),\n input: applyModifiers('unknown', field),\n };\n }\n}\n\nexport function generateFieldResolvedType(\n field: ContractField,\n codecLookup?: CodecLookup,\n side: 'input' | 'output' = 'output',\n): string {\n return resolveFieldType(field, codecLookup)[side];\n}\n\nexport function generateBothFieldTypesMaps(\n models: Record<string, ContractModel> | undefined,\n codecLookup?: CodecLookup,\n): ResolvedFieldType {\n if (!models || Object.keys(models).length === 0) {\n return { output: 'Record<string, never>', input: 'Record<string, never>' };\n }\n\n const outputModelEntries: string[] = [];\n const inputModelEntries: string[] = [];\n for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {\n if (!model) continue;\n const outputFieldEntries: string[] = [];\n const inputFieldEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(model.fields)) {\n const resolved = resolveFieldType(field, codecLookup);\n const key = `readonly ${serializeObjectKey(fieldName)}`;\n outputFieldEntries.push(`${key}: ${resolved.output}`);\n inputFieldEntries.push(`${key}: ${resolved.input}`);\n }\n const outputFields =\n outputFieldEntries.length > 0\n ? `{ ${outputFieldEntries.join('; ')} }`\n : 'Record<string, never>';\n const inputFields =\n inputFieldEntries.length > 0\n ? `{ ${inputFieldEntries.join('; ')} }`\n : 'Record<string, never>';\n const modelKey = `readonly ${serializeObjectKey(modelName)}`;\n outputModelEntries.push(`${modelKey}: ${outputFields}`);\n inputModelEntries.push(`${modelKey}: ${inputFields}`);\n }\n\n return {\n output: `{ ${outputModelEntries.join('; ')} }`,\n input: `{ ${inputModelEntries.join('; ')} }`,\n };\n}\n\nexport function generateFieldOutputTypesMap(\n models: Record<string, ContractModel> | undefined,\n codecLookup?: CodecLookup,\n): string {\n return generateBothFieldTypesMaps(models, codecLookup).output;\n}\n\nexport function generateFieldInputTypesMap(\n models: Record<string, ContractModel> | undefined,\n codecLookup?: CodecLookup,\n): string {\n return generateBothFieldTypesMaps(models, codecLookup).input;\n}\n\nexport function generateValueObjectType(\n _voName: string,\n vo: ContractValueObject,\n _valueObjects: Record<string, ContractValueObject>,\n side: 'input' | 'output' = 'output',\n codecLookup?: CodecLookup,\n): string {\n return resolveValueObjectType(_voName, vo, _valueObjects, codecLookup)[side];\n}\n\nexport function resolveValueObjectType(\n _voName: string,\n vo: ContractValueObject,\n _valueObjects: Record<string, ContractValueObject>,\n codecLookup?: CodecLookup,\n): ResolvedFieldType {\n const outputEntries: string[] = [];\n const inputEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(vo.fields)) {\n const resolved = resolveFieldType(field, codecLookup);\n const key = `readonly ${serializeObjectKey(fieldName)}`;\n outputEntries.push(`${key}: ${resolved.output}`);\n inputEntries.push(`${key}: ${resolved.input}`);\n }\n const empty = 'Record<string, never>';\n return {\n output: outputEntries.length > 0 ? `{ ${outputEntries.join('; ')} }` : empty,\n input: inputEntries.length > 0 ? `{ ${inputEntries.join('; ')} }` : empty,\n };\n}\n\nexport function generateContractFieldDescriptor(fieldName: string, field: ContractField): string {\n const mods: string[] = [];\n if (field.many === true) mods.push('; readonly many: true');\n if (field.dict === true) mods.push('; readonly dict: true');\n const modStr = mods.join('');\n\n const { type } = field;\n if (type.kind === 'scalar') {\n const typeParamsSpec =\n type.typeParams && Object.keys(type.typeParams).length > 0\n ? `; readonly typeParams: ${serializeValue(type.typeParams)}`\n : '';\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${field.nullable}; readonly type: { readonly kind: 'scalar'; readonly codecId: ${serializeValue(type.codecId)}${typeParamsSpec} }${modStr} }`;\n }\n if (type.kind === 'valueObject') {\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${field.nullable}; readonly type: { readonly kind: 'valueObject'; readonly name: ${serializeValue(type.name)} }${modStr} }`;\n }\n return `readonly ${serializeObjectKey(fieldName)}: { readonly nullable: ${field.nullable}; readonly type: ${serializeValue(type)}${modStr} }`;\n}\n\nexport function generateValueObjectsDescriptorType(\n valueObjects: Record<string, ContractValueObject> | undefined,\n): string {\n if (!valueObjects || Object.keys(valueObjects).length === 0) {\n return 'Record<string, never>';\n }\n\n const voEntries: string[] = [];\n for (const [voName, vo] of Object.entries(valueObjects)) {\n const fieldEntries: string[] = [];\n for (const [fieldName, field] of Object.entries(vo.fields)) {\n fieldEntries.push(generateContractFieldDescriptor(fieldName, field));\n }\n const fieldsType =\n fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';\n voEntries.push(`readonly ${serializeObjectKey(voName)}: { readonly fields: ${fieldsType} }`);\n }\n\n return `{ ${voEntries.join('; ')} }`;\n}\n\nexport function generateValueObjectTypeAliases(\n valueObjects: Record<string, ContractValueObject> | undefined,\n codecLookup?: CodecLookup,\n): string {\n if (!valueObjects || Object.keys(valueObjects).length === 0) {\n return '';\n }\n\n const aliases: string[] = [];\n for (const [voName, vo] of Object.entries(valueObjects)) {\n const resolved = resolveValueObjectType(voName, vo, valueObjects, codecLookup);\n aliases.push(`export type ${voName}Output = ${resolved.output};`);\n aliases.push(`export type ${voName}Input = ${resolved.input};`);\n }\n return aliases.join('\\n');\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { deduplicateImports, generateCodecTypeIntersection, generateFieldOutputTypesMap, generateHashTypeAliases, generateImportLines, generateModelRelationsType, generateModelsType, generateRootsType, generateValueObjectTypeAliases, generateValueObjectsDescriptorType, serializeExecutionType, serializeObjectKey, serializeValue } from "../domain-type-generation.mjs";
1
+ import { deduplicateImports, generateBothFieldTypesMaps, generateCodecTypeIntersection, generateFieldOutputTypesMap, generateHashTypeAliases, generateImportLines, generateModelRelationsType, generateModelsType, generateRootsType, generateValueObjectTypeAliases, generateValueObjectsDescriptorType, serializeExecutionType, serializeObjectKey, serializeValue } from "../domain-type-generation.mjs";
2
2
  import { canonicalizeContractToObject } from "@prisma-next/contract/hashing";
3
3
  import { ifDefined } from "@prisma-next/utils/defined";
4
4
  import { format } from "prettier";
@@ -18,10 +18,10 @@ function generateContractDts(contract, emitter, codecTypeImports, operationTypeI
18
18
  const modelsType = generateModelsType(contract.models, (name, model) => emitter.generateModelStorageType(name, model));
19
19
  const rootsType = generateRootsType(contract.roots);
20
20
  const valueObjects = contract.valueObjects;
21
- const valueObjectTypeAliases = generateValueObjectTypeAliases(valueObjects);
21
+ const valueObjectTypeAliases = generateValueObjectTypeAliases(valueObjects, codecLookup);
22
22
  const valueObjectsDescriptor = generateValueObjectsDescriptorType(valueObjects);
23
23
  const executionClause = contract.execution !== void 0 ? `\n readonly execution: ${serializeExecutionType(contract.execution)};` : "";
24
- const fieldOutputTypesMap = generateFieldOutputTypesMap(contract.models, codecLookup);
24
+ const fieldTypesMaps = generateBothFieldTypesMaps(contract.models, codecLookup);
25
25
  const contractWrapper = emitter.getContractWrapper("ContractBase", "TypeMaps");
26
26
  return `// ⚠️ GENERATED FILE - DO NOT EDIT
27
27
  // This file is automatically generated by 'prisma-next contract emit'.
@@ -42,7 +42,8 @@ export type CodecTypes = ${codecTypes};
42
42
  export type OperationTypes = ${operationTypes};
43
43
  ${familyTypeAliases}
44
44
  ${valueObjectTypeAliases}
45
- export type FieldOutputTypes = ${fieldOutputTypesMap};
45
+ export type FieldOutputTypes = ${fieldTypesMaps.output};
46
+ export type FieldInputTypes = ${fieldTypesMaps.input};
46
47
  export type TypeMaps = ${typeMapsExpr};
47
48
 
48
49
  type ContractBase = ContractType<
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["allImports: TypesImportSpec[]"],"sources":["../../src/generate-contract-dts.ts","../../src/emit.ts"],"sourcesContent":["import type { Contract, ContractModel, ContractValueObject } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type {\n EmissionSpi,\n GenerateContractTypesOptions,\n TypesImportSpec,\n} from '@prisma-next/framework-components/emission';\nimport {\n deduplicateImports,\n generateCodecTypeIntersection,\n generateFieldOutputTypesMap,\n generateHashTypeAliases,\n generateImportLines,\n generateModelsType,\n generateRootsType,\n generateValueObjectsDescriptorType,\n generateValueObjectTypeAliases,\n serializeExecutionType,\n serializeValue,\n} from './domain-type-generation';\n\nexport function generateContractDts(\n contract: Contract,\n emitter: EmissionSpi,\n codecTypeImports: ReadonlyArray<TypesImportSpec>,\n operationTypeImports: ReadonlyArray<TypesImportSpec>,\n hashes: {\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n },\n options?: GenerateContractTypesOptions,\n codecLookup?: CodecLookup,\n): string {\n const allImports: TypesImportSpec[] = [...codecTypeImports, ...operationTypeImports];\n if (options?.queryOperationTypeImports) {\n allImports.push(...options.queryOperationTypeImports);\n }\n const uniqueImports = deduplicateImports(allImports);\n const importLines = generateImportLines(uniqueImports);\n\n const familyImportLines = emitter.getFamilyImports();\n\n const hashAliases = generateHashTypeAliases(hashes);\n\n const codecTypes = generateCodecTypeIntersection(codecTypeImports, 'CodecTypes');\n const operationTypes = generateCodecTypeIntersection(operationTypeImports, 'OperationTypes');\n\n const familyTypeAliases = emitter.getFamilyTypeAliases(options);\n\n const typeMapsExpr = emitter.getTypeMapsExpression();\n\n const storageType = emitter.generateStorageType(contract, 'StorageHash');\n\n const modelsType = generateModelsType(\n contract.models as Record<string, ContractModel>,\n (name, model) => emitter.generateModelStorageType(name, model),\n );\n\n const rootsType = generateRootsType(contract.roots);\n\n const valueObjects = contract.valueObjects as Record<string, ContractValueObject> | undefined;\n const valueObjectTypeAliases = generateValueObjectTypeAliases(valueObjects);\n const valueObjectsDescriptor = generateValueObjectsDescriptorType(valueObjects);\n\n const executionClause =\n contract.execution !== undefined\n ? `\\n readonly execution: ${serializeExecutionType(contract.execution)};`\n : '';\n\n const fieldOutputTypesMap = generateFieldOutputTypesMap(\n contract.models as Record<string, ContractModel> | undefined,\n codecLookup,\n );\n\n const contractWrapper = emitter.getContractWrapper('ContractBase', 'TypeMaps');\n\n return `// ⚠️ GENERATED FILE - DO NOT EDIT\n// This file is automatically generated by 'prisma-next contract emit'.\n// To regenerate, run: prisma-next contract emit\n${importLines.join('\\n')}\n\n${familyImportLines.join('\\n')}\nimport type {\n Contract as ContractType,\n ExecutionHashBase,\n ProfileHashBase,\n StorageHashBase,\n} from '@prisma-next/contract/types';\n\n${hashAliases}\n\nexport type CodecTypes = ${codecTypes};\nexport type OperationTypes = ${operationTypes};\n${familyTypeAliases}\n${valueObjectTypeAliases}\nexport type FieldOutputTypes = ${fieldOutputTypesMap};\nexport type TypeMaps = ${typeMapsExpr};\n\ntype ContractBase = ContractType<\n${storageType},\n${modelsType}\n> & {\n readonly target: ${serializeValue(contract.target)};\n readonly targetFamily: ${serializeValue(contract.targetFamily)};\n readonly roots: ${rootsType};\n readonly capabilities: ${serializeValue(contract.capabilities)};\n readonly extensionPacks: ${serializeValue(contract.extensionPacks)};${executionClause}\n readonly meta: ${serializeValue(contract.meta)};\n ${valueObjects ? `readonly valueObjects: ${valueObjectsDescriptor};` : ''}\n readonly profileHash: ProfileHash;\n};\n\n${contractWrapper}\n`;\n}\n","import { canonicalizeContractToObject } from '@prisma-next/contract/hashing';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { EmissionSpi } from '@prisma-next/framework-components/emission';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { format } from 'prettier';\nimport type { EmitResult, EmitStackInput } from './emit-types';\nimport { generateContractDts } from './generate-contract-dts';\n\nconst SCHEMA_VERSION = '1';\n\nexport async function emit(\n contract: Contract,\n stack: EmitStackInput,\n targetFamily: EmissionSpi,\n): Promise<EmitResult> {\n const { codecTypeImports, operationTypeImports, queryOperationTypeImports } = stack;\n\n const { storageHash } = contract.storage;\n const executionHash = contract.execution?.executionHash;\n const { profileHash } = contract;\n\n const canonicalized = canonicalizeContractToObject(contract, {\n schemaVersion: SCHEMA_VERSION,\n });\n const contractJsonString = JSON.stringify(\n {\n ...canonicalized,\n _generated: {\n warning: '⚠️ GENERATED FILE - DO NOT EDIT',\n message: 'This file is automatically generated by \"prisma-next contract emit\".',\n regenerate: 'To regenerate, run: prisma-next contract emit',\n },\n },\n null,\n 2,\n );\n\n const generateOptions = queryOperationTypeImports ? { queryOperationTypeImports } : undefined;\n\n const contractTypeHashes = {\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n const contractDtsRaw = generateContractDts(\n contract,\n targetFamily,\n codecTypeImports ?? [],\n operationTypeImports ?? [],\n contractTypeHashes,\n generateOptions,\n stack.codecLookup,\n );\n const contractDts = await format(contractDtsRaw, {\n parser: 'typescript',\n singleQuote: true,\n semi: true,\n printWidth: 100,\n });\n\n return {\n contractJson: contractJsonString,\n contractDts,\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,oBACd,UACA,SACA,kBACA,sBACA,QAKA,SACA,aACQ;CACR,MAAMA,aAAgC,CAAC,GAAG,kBAAkB,GAAG,qBAAqB;AACpF,KAAI,SAAS,0BACX,YAAW,KAAK,GAAG,QAAQ,0BAA0B;CAGvD,MAAM,cAAc,oBADE,mBAAmB,WAAW,CACE;CAEtD,MAAM,oBAAoB,QAAQ,kBAAkB;CAEpD,MAAM,cAAc,wBAAwB,OAAO;CAEnD,MAAM,aAAa,8BAA8B,kBAAkB,aAAa;CAChF,MAAM,iBAAiB,8BAA8B,sBAAsB,iBAAiB;CAE5F,MAAM,oBAAoB,QAAQ,qBAAqB,QAAQ;CAE/D,MAAM,eAAe,QAAQ,uBAAuB;CAEpD,MAAM,cAAc,QAAQ,oBAAoB,UAAU,cAAc;CAExE,MAAM,aAAa,mBACjB,SAAS,SACR,MAAM,UAAU,QAAQ,yBAAyB,MAAM,MAAM,CAC/D;CAED,MAAM,YAAY,kBAAkB,SAAS,MAAM;CAEnD,MAAM,eAAe,SAAS;CAC9B,MAAM,yBAAyB,+BAA+B,aAAa;CAC3E,MAAM,yBAAyB,mCAAmC,aAAa;CAE/E,MAAM,kBACJ,SAAS,cAAc,SACnB,2BAA2B,uBAAuB,SAAS,UAAU,CAAC,KACtE;CAEN,MAAM,sBAAsB,4BAC1B,SAAS,QACT,YACD;CAED,MAAM,kBAAkB,QAAQ,mBAAmB,gBAAgB,WAAW;AAE9E,QAAO;;;EAGP,YAAY,KAAK,KAAK,CAAC;;EAEvB,kBAAkB,KAAK,KAAK,CAAC;;;;;;;;EAQ7B,YAAY;;2BAEa,WAAW;+BACP,eAAe;EAC5C,kBAAkB;EAClB,uBAAuB;iCACQ,oBAAoB;yBAC5B,aAAa;;;EAGpC,YAAY;EACZ,WAAW;;qBAEQ,eAAe,SAAS,OAAO,CAAC;2BAC1B,eAAe,SAAS,aAAa,CAAC;oBAC7C,UAAU;2BACH,eAAe,SAAS,aAAa,CAAC;6BACpC,eAAe,SAAS,eAAe,CAAC,GAAG,gBAAgB;mBACrE,eAAe,SAAS,KAAK,CAAC;IAC7C,eAAe,0BAA0B,uBAAuB,KAAK,GAAG;;;;EAI1E,gBAAgB;;;;;;ACzGlB,MAAM,iBAAiB;AAEvB,eAAsB,KACpB,UACA,OACA,cACqB;CACrB,MAAM,EAAE,kBAAkB,sBAAsB,8BAA8B;CAE9E,MAAM,EAAE,gBAAgB,SAAS;CACjC,MAAM,gBAAgB,SAAS,WAAW;CAC1C,MAAM,EAAE,gBAAgB;CAExB,MAAM,gBAAgB,6BAA6B,UAAU,EAC3D,eAAe,gBAChB,CAAC;CACF,MAAM,qBAAqB,KAAK,UAC9B;EACE,GAAG;EACH,YAAY;GACV,SAAS;GACT,SAAS;GACT,YAAY;GACb;EACF,EACD,MACA,EACD;CAED,MAAM,kBAAkB,4BAA4B,EAAE,2BAA2B,GAAG;CAEpF,MAAM,qBAAqB;EACzB;EACA,GAAG,UAAU,iBAAiB,cAAc;EAC5C;EACD;AAiBD,QAAO;EACL,cAAc;EACd,aATkB,MAAM,OATH,oBACrB,UACA,cACA,oBAAoB,EAAE,EACtB,wBAAwB,EAAE,EAC1B,oBACA,iBACA,MAAM,YACP,EACgD;GAC/C,QAAQ;GACR,aAAa;GACb,MAAM;GACN,YAAY;GACb,CAAC;EAKA;EACA,GAAG,UAAU,iBAAiB,cAAc;EAC5C;EACD"}
1
+ {"version":3,"file":"index.mjs","names":["allImports: TypesImportSpec[]"],"sources":["../../src/generate-contract-dts.ts","../../src/emit.ts"],"sourcesContent":["import type { Contract, ContractModel, ContractValueObject } from '@prisma-next/contract/types';\nimport type { CodecLookup } from '@prisma-next/framework-components/codec';\nimport type {\n EmissionSpi,\n GenerateContractTypesOptions,\n TypesImportSpec,\n} from '@prisma-next/framework-components/emission';\nimport {\n deduplicateImports,\n generateBothFieldTypesMaps,\n generateCodecTypeIntersection,\n generateHashTypeAliases,\n generateImportLines,\n generateModelsType,\n generateRootsType,\n generateValueObjectsDescriptorType,\n generateValueObjectTypeAliases,\n serializeExecutionType,\n serializeValue,\n} from './domain-type-generation';\n\nexport function generateContractDts(\n contract: Contract,\n emitter: EmissionSpi,\n codecTypeImports: ReadonlyArray<TypesImportSpec>,\n operationTypeImports: ReadonlyArray<TypesImportSpec>,\n hashes: {\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n },\n options?: GenerateContractTypesOptions,\n codecLookup?: CodecLookup,\n): string {\n const allImports: TypesImportSpec[] = [...codecTypeImports, ...operationTypeImports];\n if (options?.queryOperationTypeImports) {\n allImports.push(...options.queryOperationTypeImports);\n }\n const uniqueImports = deduplicateImports(allImports);\n const importLines = generateImportLines(uniqueImports);\n\n const familyImportLines = emitter.getFamilyImports();\n\n const hashAliases = generateHashTypeAliases(hashes);\n\n const codecTypes = generateCodecTypeIntersection(codecTypeImports, 'CodecTypes');\n const operationTypes = generateCodecTypeIntersection(operationTypeImports, 'OperationTypes');\n\n const familyTypeAliases = emitter.getFamilyTypeAliases(options);\n\n const typeMapsExpr = emitter.getTypeMapsExpression();\n\n const storageType = emitter.generateStorageType(contract, 'StorageHash');\n\n const modelsType = generateModelsType(\n contract.models as Record<string, ContractModel>,\n (name, model) => emitter.generateModelStorageType(name, model),\n );\n\n const rootsType = generateRootsType(contract.roots);\n\n const valueObjects = contract.valueObjects as Record<string, ContractValueObject> | undefined;\n const valueObjectTypeAliases = generateValueObjectTypeAliases(valueObjects, codecLookup);\n const valueObjectsDescriptor = generateValueObjectsDescriptorType(valueObjects);\n\n const executionClause =\n contract.execution !== undefined\n ? `\\n readonly execution: ${serializeExecutionType(contract.execution)};`\n : '';\n\n const fieldTypesMaps = generateBothFieldTypesMaps(\n contract.models as Record<string, ContractModel> | undefined,\n codecLookup,\n );\n\n const contractWrapper = emitter.getContractWrapper('ContractBase', 'TypeMaps');\n\n return `// ⚠️ GENERATED FILE - DO NOT EDIT\n// This file is automatically generated by 'prisma-next contract emit'.\n// To regenerate, run: prisma-next contract emit\n${importLines.join('\\n')}\n\n${familyImportLines.join('\\n')}\nimport type {\n Contract as ContractType,\n ExecutionHashBase,\n ProfileHashBase,\n StorageHashBase,\n} from '@prisma-next/contract/types';\n\n${hashAliases}\n\nexport type CodecTypes = ${codecTypes};\nexport type OperationTypes = ${operationTypes};\n${familyTypeAliases}\n${valueObjectTypeAliases}\nexport type FieldOutputTypes = ${fieldTypesMaps.output};\nexport type FieldInputTypes = ${fieldTypesMaps.input};\nexport type TypeMaps = ${typeMapsExpr};\n\ntype ContractBase = ContractType<\n${storageType},\n${modelsType}\n> & {\n readonly target: ${serializeValue(contract.target)};\n readonly targetFamily: ${serializeValue(contract.targetFamily)};\n readonly roots: ${rootsType};\n readonly capabilities: ${serializeValue(contract.capabilities)};\n readonly extensionPacks: ${serializeValue(contract.extensionPacks)};${executionClause}\n readonly meta: ${serializeValue(contract.meta)};\n ${valueObjects ? `readonly valueObjects: ${valueObjectsDescriptor};` : ''}\n readonly profileHash: ProfileHash;\n};\n\n${contractWrapper}\n`;\n}\n","import { canonicalizeContractToObject } from '@prisma-next/contract/hashing';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { EmissionSpi } from '@prisma-next/framework-components/emission';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { format } from 'prettier';\nimport type { EmitResult, EmitStackInput } from './emit-types';\nimport { generateContractDts } from './generate-contract-dts';\n\nconst SCHEMA_VERSION = '1';\n\nexport async function emit(\n contract: Contract,\n stack: EmitStackInput,\n targetFamily: EmissionSpi,\n): Promise<EmitResult> {\n const { codecTypeImports, operationTypeImports, queryOperationTypeImports } = stack;\n\n const { storageHash } = contract.storage;\n const executionHash = contract.execution?.executionHash;\n const { profileHash } = contract;\n\n const canonicalized = canonicalizeContractToObject(contract, {\n schemaVersion: SCHEMA_VERSION,\n });\n const contractJsonString = JSON.stringify(\n {\n ...canonicalized,\n _generated: {\n warning: '⚠️ GENERATED FILE - DO NOT EDIT',\n message: 'This file is automatically generated by \"prisma-next contract emit\".',\n regenerate: 'To regenerate, run: prisma-next contract emit',\n },\n },\n null,\n 2,\n );\n\n const generateOptions = queryOperationTypeImports ? { queryOperationTypeImports } : undefined;\n\n const contractTypeHashes = {\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n const contractDtsRaw = generateContractDts(\n contract,\n targetFamily,\n codecTypeImports ?? [],\n operationTypeImports ?? [],\n contractTypeHashes,\n generateOptions,\n stack.codecLookup,\n );\n const contractDts = await format(contractDtsRaw, {\n parser: 'typescript',\n singleQuote: true,\n semi: true,\n printWidth: 100,\n });\n\n return {\n contractJson: contractJsonString,\n contractDts,\n storageHash,\n ...ifDefined('executionHash', executionHash),\n profileHash,\n };\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,oBACd,UACA,SACA,kBACA,sBACA,QAKA,SACA,aACQ;CACR,MAAMA,aAAgC,CAAC,GAAG,kBAAkB,GAAG,qBAAqB;AACpF,KAAI,SAAS,0BACX,YAAW,KAAK,GAAG,QAAQ,0BAA0B;CAGvD,MAAM,cAAc,oBADE,mBAAmB,WAAW,CACE;CAEtD,MAAM,oBAAoB,QAAQ,kBAAkB;CAEpD,MAAM,cAAc,wBAAwB,OAAO;CAEnD,MAAM,aAAa,8BAA8B,kBAAkB,aAAa;CAChF,MAAM,iBAAiB,8BAA8B,sBAAsB,iBAAiB;CAE5F,MAAM,oBAAoB,QAAQ,qBAAqB,QAAQ;CAE/D,MAAM,eAAe,QAAQ,uBAAuB;CAEpD,MAAM,cAAc,QAAQ,oBAAoB,UAAU,cAAc;CAExE,MAAM,aAAa,mBACjB,SAAS,SACR,MAAM,UAAU,QAAQ,yBAAyB,MAAM,MAAM,CAC/D;CAED,MAAM,YAAY,kBAAkB,SAAS,MAAM;CAEnD,MAAM,eAAe,SAAS;CAC9B,MAAM,yBAAyB,+BAA+B,cAAc,YAAY;CACxF,MAAM,yBAAyB,mCAAmC,aAAa;CAE/E,MAAM,kBACJ,SAAS,cAAc,SACnB,2BAA2B,uBAAuB,SAAS,UAAU,CAAC,KACtE;CAEN,MAAM,iBAAiB,2BACrB,SAAS,QACT,YACD;CAED,MAAM,kBAAkB,QAAQ,mBAAmB,gBAAgB,WAAW;AAE9E,QAAO;;;EAGP,YAAY,KAAK,KAAK,CAAC;;EAEvB,kBAAkB,KAAK,KAAK,CAAC;;;;;;;;EAQ7B,YAAY;;2BAEa,WAAW;+BACP,eAAe;EAC5C,kBAAkB;EAClB,uBAAuB;iCACQ,eAAe,OAAO;gCACvB,eAAe,MAAM;yBAC5B,aAAa;;;EAGpC,YAAY;EACZ,WAAW;;qBAEQ,eAAe,SAAS,OAAO,CAAC;2BAC1B,eAAe,SAAS,aAAa,CAAC;oBAC7C,UAAU;2BACH,eAAe,SAAS,aAAa,CAAC;6BACpC,eAAe,SAAS,eAAe,CAAC,GAAG,gBAAgB;mBACrE,eAAe,SAAS,KAAK,CAAC;IAC7C,eAAe,0BAA0B,uBAAuB,KAAK,GAAG;;;;EAI1E,gBAAgB;;;;;;AC1GlB,MAAM,iBAAiB;AAEvB,eAAsB,KACpB,UACA,OACA,cACqB;CACrB,MAAM,EAAE,kBAAkB,sBAAsB,8BAA8B;CAE9E,MAAM,EAAE,gBAAgB,SAAS;CACjC,MAAM,gBAAgB,SAAS,WAAW;CAC1C,MAAM,EAAE,gBAAgB;CAExB,MAAM,gBAAgB,6BAA6B,UAAU,EAC3D,eAAe,gBAChB,CAAC;CACF,MAAM,qBAAqB,KAAK,UAC9B;EACE,GAAG;EACH,YAAY;GACV,SAAS;GACT,SAAS;GACT,YAAY;GACb;EACF,EACD,MACA,EACD;CAED,MAAM,kBAAkB,4BAA4B,EAAE,2BAA2B,GAAG;CAEpF,MAAM,qBAAqB;EACzB;EACA,GAAG,UAAU,iBAAiB,cAAc;EAC5C;EACD;AAiBD,QAAO;EACL,cAAc;EACd,aATkB,MAAM,OATH,oBACrB,UACA,cACA,oBAAoB,EAAE,EACtB,wBAAwB,EAAE,EAC1B,oBACA,iBACA,MAAM,YACP,EACgD;GAC/C,QAAQ;GACR,aAAa;GACb,MAAM;GACN,YAAY;GACb,CAAC;EAKA;EACA,GAAG,UAAU,iBAAiB,cAAc;EAC5C;EACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma-next/emitter",
3
- "version": "0.3.0-dev.155",
3
+ "version": "0.3.0-dev.157",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "files": [
@@ -11,10 +11,10 @@
11
11
  "dependencies": {
12
12
  "arktype": "^2.0.0",
13
13
  "prettier": "^3.3.3",
14
- "@prisma-next/contract": "0.3.0-dev.155",
15
- "@prisma-next/utils": "0.3.0-dev.155",
16
- "@prisma-next/operations": "0.3.0-dev.155",
17
- "@prisma-next/framework-components": "0.3.0-dev.155"
14
+ "@prisma-next/contract": "0.3.0-dev.157",
15
+ "@prisma-next/framework-components": "0.3.0-dev.157",
16
+ "@prisma-next/utils": "0.3.0-dev.157",
17
+ "@prisma-next/operations": "0.3.0-dev.157"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/node": "24.10.4",
@@ -215,89 +215,159 @@ export function generateHashTypeAliases(hashes: {
215
215
  ].join('\n');
216
216
  }
217
217
 
218
- export function generateFieldResolvedType(field: ContractField, codecLookup?: CodecLookup): string {
219
- let baseType: string;
218
+ export type ResolvedFieldType = { readonly input: string; readonly output: string };
219
+
220
+ function applyModifiers(base: string, field: ContractField): string {
221
+ let result = base;
222
+ if (field.many === true) result = `ReadonlyArray<${result}>`;
223
+ if (field.dict === true) result = `Readonly<Record<string, ${result}>>`;
224
+ if (field.nullable) result = `${result} | null`;
225
+ return result;
226
+ }
227
+
228
+ export function resolveFieldType(
229
+ field: ContractField,
230
+ codecLookup?: CodecLookup,
231
+ ): ResolvedFieldType {
220
232
  const { type } = field;
221
233
 
222
234
  switch (type.kind) {
223
235
  case 'scalar': {
224
- let resolved: string | undefined;
236
+ let outputResolved: string | undefined;
225
237
  if (codecLookup && type.typeParams && Object.keys(type.typeParams).length > 0) {
226
238
  const codec = codecLookup.get(type.codecId);
227
239
  if (codec?.renderOutputType) {
228
240
  const rendered = codec.renderOutputType(type.typeParams);
229
241
  if (rendered && isSafeTypeExpression(rendered)) {
230
- resolved = rendered;
242
+ outputResolved = rendered;
231
243
  }
232
244
  }
233
245
  }
234
- baseType = resolved ?? `CodecTypes[${serializeValue(type.codecId)}]['output']`;
235
- break;
246
+ const codecAccessor = `CodecTypes[${serializeValue(type.codecId)}]`;
247
+ return {
248
+ output: applyModifiers(outputResolved ?? `${codecAccessor}['output']`, field),
249
+ input: applyModifiers(`${codecAccessor}['input']`, field),
250
+ };
236
251
  }
237
252
  case 'valueObject':
238
- baseType = type.name;
239
- break;
253
+ return {
254
+ output: applyModifiers(`${type.name}Output`, field),
255
+ input: applyModifiers(`${type.name}Input`, field),
256
+ };
240
257
  case 'union': {
241
- const memberTypes = type.members.map((m) => {
242
- if (m.kind === 'scalar') return `CodecTypes[${serializeValue(m.codecId)}]['output']`;
243
- return m.name;
244
- });
245
- baseType = memberTypes.join(' | ');
246
- break;
258
+ const outputMembers = type.members.map((m) =>
259
+ m.kind === 'scalar'
260
+ ? `CodecTypes[${serializeValue(m.codecId)}]['output']`
261
+ : `${m.name}Output`,
262
+ );
263
+ const inputMembers = type.members.map((m) =>
264
+ m.kind === 'scalar'
265
+ ? `CodecTypes[${serializeValue(m.codecId)}]['input']`
266
+ : `${m.name}Input`,
267
+ );
268
+ return {
269
+ output: applyModifiers(outputMembers.join(' | '), field),
270
+ input: applyModifiers(inputMembers.join(' | '), field),
271
+ };
247
272
  }
248
273
  default:
249
- baseType = 'unknown';
250
- break;
251
- }
252
-
253
- if (field.many === true) {
254
- baseType = `ReadonlyArray<${baseType}>`;
255
- }
256
- if (field.dict === true) {
257
- baseType = `Readonly<Record<string, ${baseType}>>`;
258
- }
259
- if (field.nullable) {
260
- baseType = `${baseType} | null`;
274
+ return {
275
+ output: applyModifiers('unknown', field),
276
+ input: applyModifiers('unknown', field),
277
+ };
261
278
  }
279
+ }
262
280
 
263
- return baseType;
281
+ export function generateFieldResolvedType(
282
+ field: ContractField,
283
+ codecLookup?: CodecLookup,
284
+ side: 'input' | 'output' = 'output',
285
+ ): string {
286
+ return resolveFieldType(field, codecLookup)[side];
264
287
  }
265
288
 
266
- export function generateFieldOutputTypesMap(
289
+ export function generateBothFieldTypesMaps(
267
290
  models: Record<string, ContractModel> | undefined,
268
291
  codecLookup?: CodecLookup,
269
- ): string {
292
+ ): ResolvedFieldType {
270
293
  if (!models || Object.keys(models).length === 0) {
271
- return 'Record<string, never>';
294
+ return { output: 'Record<string, never>', input: 'Record<string, never>' };
272
295
  }
273
296
 
274
- const modelEntries: string[] = [];
297
+ const outputModelEntries: string[] = [];
298
+ const inputModelEntries: string[] = [];
275
299
  for (const [modelName, model] of Object.entries(models).sort(([a], [b]) => a.localeCompare(b))) {
276
300
  if (!model) continue;
277
- const fieldEntries: string[] = [];
301
+ const outputFieldEntries: string[] = [];
302
+ const inputFieldEntries: string[] = [];
278
303
  for (const [fieldName, field] of Object.entries(model.fields)) {
279
- const resolvedType = generateFieldResolvedType(field, codecLookup);
280
- fieldEntries.push(`readonly ${serializeObjectKey(fieldName)}: ${resolvedType}`);
304
+ const resolved = resolveFieldType(field, codecLookup);
305
+ const key = `readonly ${serializeObjectKey(fieldName)}`;
306
+ outputFieldEntries.push(`${key}: ${resolved.output}`);
307
+ inputFieldEntries.push(`${key}: ${resolved.input}`);
281
308
  }
282
- const fieldsType =
283
- fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';
284
- modelEntries.push(`readonly ${serializeObjectKey(modelName)}: ${fieldsType}`);
309
+ const outputFields =
310
+ outputFieldEntries.length > 0
311
+ ? `{ ${outputFieldEntries.join('; ')} }`
312
+ : 'Record<string, never>';
313
+ const inputFields =
314
+ inputFieldEntries.length > 0
315
+ ? `{ ${inputFieldEntries.join('; ')} }`
316
+ : 'Record<string, never>';
317
+ const modelKey = `readonly ${serializeObjectKey(modelName)}`;
318
+ outputModelEntries.push(`${modelKey}: ${outputFields}`);
319
+ inputModelEntries.push(`${modelKey}: ${inputFields}`);
285
320
  }
286
321
 
287
- return `{ ${modelEntries.join('; ')} }`;
322
+ return {
323
+ output: `{ ${outputModelEntries.join('; ')} }`,
324
+ input: `{ ${inputModelEntries.join('; ')} }`,
325
+ };
326
+ }
327
+
328
+ export function generateFieldOutputTypesMap(
329
+ models: Record<string, ContractModel> | undefined,
330
+ codecLookup?: CodecLookup,
331
+ ): string {
332
+ return generateBothFieldTypesMaps(models, codecLookup).output;
333
+ }
334
+
335
+ export function generateFieldInputTypesMap(
336
+ models: Record<string, ContractModel> | undefined,
337
+ codecLookup?: CodecLookup,
338
+ ): string {
339
+ return generateBothFieldTypesMaps(models, codecLookup).input;
288
340
  }
289
341
 
290
342
  export function generateValueObjectType(
291
343
  _voName: string,
292
344
  vo: ContractValueObject,
293
345
  _valueObjects: Record<string, ContractValueObject>,
346
+ side: 'input' | 'output' = 'output',
347
+ codecLookup?: CodecLookup,
294
348
  ): string {
295
- const fieldEntries: string[] = [];
349
+ return resolveValueObjectType(_voName, vo, _valueObjects, codecLookup)[side];
350
+ }
351
+
352
+ export function resolveValueObjectType(
353
+ _voName: string,
354
+ vo: ContractValueObject,
355
+ _valueObjects: Record<string, ContractValueObject>,
356
+ codecLookup?: CodecLookup,
357
+ ): ResolvedFieldType {
358
+ const outputEntries: string[] = [];
359
+ const inputEntries: string[] = [];
296
360
  for (const [fieldName, field] of Object.entries(vo.fields)) {
297
- const tsType = generateFieldResolvedType(field);
298
- fieldEntries.push(`readonly ${serializeObjectKey(fieldName)}: ${tsType}`);
361
+ const resolved = resolveFieldType(field, codecLookup);
362
+ const key = `readonly ${serializeObjectKey(fieldName)}`;
363
+ outputEntries.push(`${key}: ${resolved.output}`);
364
+ inputEntries.push(`${key}: ${resolved.input}`);
299
365
  }
300
- return fieldEntries.length > 0 ? `{ ${fieldEntries.join('; ')} }` : 'Record<string, never>';
366
+ const empty = 'Record<string, never>';
367
+ return {
368
+ output: outputEntries.length > 0 ? `{ ${outputEntries.join('; ')} }` : empty,
369
+ input: inputEntries.length > 0 ? `{ ${inputEntries.join('; ')} }` : empty,
370
+ };
301
371
  }
302
372
 
303
373
  export function generateContractFieldDescriptor(fieldName: string, field: ContractField): string {
@@ -343,6 +413,7 @@ export function generateValueObjectsDescriptorType(
343
413
 
344
414
  export function generateValueObjectTypeAliases(
345
415
  valueObjects: Record<string, ContractValueObject> | undefined,
416
+ codecLookup?: CodecLookup,
346
417
  ): string {
347
418
  if (!valueObjects || Object.keys(valueObjects).length === 0) {
348
419
  return '';
@@ -350,8 +421,9 @@ export function generateValueObjectTypeAliases(
350
421
 
351
422
  const aliases: string[] = [];
352
423
  for (const [voName, vo] of Object.entries(valueObjects)) {
353
- const voType = generateValueObjectType(voName, vo, valueObjects);
354
- aliases.push(`export type ${voName} = ${voType};`);
424
+ const resolved = resolveValueObjectType(voName, vo, valueObjects, codecLookup);
425
+ aliases.push(`export type ${voName}Output = ${resolved.output};`);
426
+ aliases.push(`export type ${voName}Input = ${resolved.input};`);
355
427
  }
356
428
  return aliases.join('\n');
357
429
  }
@@ -7,8 +7,8 @@ import type {
7
7
  } from '@prisma-next/framework-components/emission';
8
8
  import {
9
9
  deduplicateImports,
10
+ generateBothFieldTypesMaps,
10
11
  generateCodecTypeIntersection,
11
- generateFieldOutputTypesMap,
12
12
  generateHashTypeAliases,
13
13
  generateImportLines,
14
14
  generateModelsType,
@@ -60,7 +60,7 @@ export function generateContractDts(
60
60
  const rootsType = generateRootsType(contract.roots);
61
61
 
62
62
  const valueObjects = contract.valueObjects as Record<string, ContractValueObject> | undefined;
63
- const valueObjectTypeAliases = generateValueObjectTypeAliases(valueObjects);
63
+ const valueObjectTypeAliases = generateValueObjectTypeAliases(valueObjects, codecLookup);
64
64
  const valueObjectsDescriptor = generateValueObjectsDescriptorType(valueObjects);
65
65
 
66
66
  const executionClause =
@@ -68,7 +68,7 @@ export function generateContractDts(
68
68
  ? `\n readonly execution: ${serializeExecutionType(contract.execution)};`
69
69
  : '';
70
70
 
71
- const fieldOutputTypesMap = generateFieldOutputTypesMap(
71
+ const fieldTypesMaps = generateBothFieldTypesMaps(
72
72
  contract.models as Record<string, ContractModel> | undefined,
73
73
  codecLookup,
74
74
  );
@@ -94,7 +94,8 @@ export type CodecTypes = ${codecTypes};
94
94
  export type OperationTypes = ${operationTypes};
95
95
  ${familyTypeAliases}
96
96
  ${valueObjectTypeAliases}
97
- export type FieldOutputTypes = ${fieldOutputTypesMap};
97
+ export type FieldOutputTypes = ${fieldTypesMaps.output};
98
+ export type FieldInputTypes = ${fieldTypesMaps.input};
98
99
  export type TypeMaps = ${typeMapsExpr};
99
100
 
100
101
  type ContractBase = ContractType<
@@ -8,8 +8,10 @@ import type { TypesImportSpec } from '@prisma-next/framework-components/emission
8
8
  import { describe, expect, it, vi } from 'vitest';
9
9
  import {
10
10
  deduplicateImports,
11
+ generateBothFieldTypesMaps,
11
12
  generateCodecTypeIntersection,
12
13
  generateContractFieldDescriptor,
14
+ generateFieldInputTypesMap,
13
15
  generateFieldOutputTypesMap,
14
16
  generateFieldResolvedType,
15
17
  generateHashTypeAliases,
@@ -21,6 +23,7 @@ import {
21
23
  generateValueObjectsDescriptorType,
22
24
  generateValueObjectType,
23
25
  generateValueObjectTypeAliases,
26
+ resolveFieldType,
24
27
  serializeExecutionType,
25
28
  serializeObjectKey,
26
29
  serializeValue,
@@ -479,12 +482,12 @@ describe('generateFieldResolvedType', () => {
479
482
  expect(generateFieldResolvedType(field)).toBe("CodecTypes['mongo/string@1']['output']");
480
483
  });
481
484
 
482
- it('generates named type reference for value object fields', () => {
485
+ it('generates suffixed type reference for value object fields', () => {
483
486
  const field: ContractField = {
484
487
  nullable: false,
485
488
  type: { kind: 'valueObject', name: 'Address' },
486
489
  };
487
- expect(generateFieldResolvedType(field)).toBe('Address');
490
+ expect(generateFieldResolvedType(field)).toBe('AddressOutput');
488
491
  });
489
492
 
490
493
  it('wraps in ReadonlyArray for many: true', () => {
@@ -493,7 +496,7 @@ describe('generateFieldResolvedType', () => {
493
496
  type: { kind: 'valueObject', name: 'Address' },
494
497
  many: true,
495
498
  };
496
- expect(generateFieldResolvedType(field)).toBe('ReadonlyArray<Address>');
499
+ expect(generateFieldResolvedType(field)).toBe('ReadonlyArray<AddressOutput>');
497
500
  });
498
501
 
499
502
  it('wraps in Readonly<Record> for dict: true', () => {
@@ -512,7 +515,7 @@ describe('generateFieldResolvedType', () => {
512
515
  nullable: true,
513
516
  type: { kind: 'valueObject', name: 'Address' },
514
517
  };
515
- expect(generateFieldResolvedType(field)).toBe('Address | null');
518
+ expect(generateFieldResolvedType(field)).toBe('AddressOutput | null');
516
519
  });
517
520
 
518
521
  it('combines many and nullable', () => {
@@ -521,10 +524,10 @@ describe('generateFieldResolvedType', () => {
521
524
  type: { kind: 'valueObject', name: 'Address' },
522
525
  many: true,
523
526
  };
524
- expect(generateFieldResolvedType(field)).toBe('ReadonlyArray<Address> | null');
527
+ expect(generateFieldResolvedType(field)).toBe('ReadonlyArray<AddressOutput> | null');
525
528
  });
526
529
 
527
- it('handles union types', () => {
530
+ it('handles union types with output side', () => {
528
531
  const field: ContractField = {
529
532
  nullable: false,
530
533
  type: {
@@ -536,7 +539,41 @@ describe('generateFieldResolvedType', () => {
536
539
  },
537
540
  };
538
541
  expect(generateFieldResolvedType(field)).toBe(
539
- "CodecTypes['mongo/string@1']['output'] | Address",
542
+ "CodecTypes['mongo/string@1']['output'] | AddressOutput",
543
+ );
544
+ });
545
+
546
+ it('generates input side for scalar fields', () => {
547
+ const field: ContractField = {
548
+ nullable: false,
549
+ type: { kind: 'scalar', codecId: 'mongo/string@1' },
550
+ };
551
+ expect(generateFieldResolvedType(field, undefined, 'input')).toBe(
552
+ "CodecTypes['mongo/string@1']['input']",
553
+ );
554
+ });
555
+
556
+ it('generates input-suffixed type for value object fields on input side', () => {
557
+ const field: ContractField = {
558
+ nullable: false,
559
+ type: { kind: 'valueObject', name: 'Price' },
560
+ };
561
+ expect(generateFieldResolvedType(field, undefined, 'input')).toBe('PriceInput');
562
+ });
563
+
564
+ it('generates input side for union types', () => {
565
+ const field: ContractField = {
566
+ nullable: false,
567
+ type: {
568
+ kind: 'union',
569
+ members: [
570
+ { kind: 'scalar', codecId: 'mongo/string@1' },
571
+ { kind: 'valueObject', name: 'Address' },
572
+ ],
573
+ },
574
+ };
575
+ expect(generateFieldResolvedType(field, undefined, 'input')).toBe(
576
+ "CodecTypes['mongo/string@1']['input'] | AddressInput",
540
577
  );
541
578
  });
542
579
  });
@@ -558,7 +595,7 @@ describe('generateValueObjectType', () => {
558
595
  expect(result).toContain("readonly zip: CodecTypes['mongo/string@1']['output']");
559
596
  });
560
597
 
561
- it('handles value object field referencing another value object', () => {
598
+ it('handles value object field referencing another value object (output)', () => {
562
599
  const companyVo: ContractValueObject = {
563
600
  fields: {
564
601
  name: { nullable: false, type: { kind: 'scalar', codecId: 'mongo/string@1' } },
@@ -567,7 +604,19 @@ describe('generateValueObjectType', () => {
567
604
  };
568
605
  const vos = { ...valueObjects, Company: companyVo };
569
606
  const result = generateValueObjectType('Company', companyVo, vos);
570
- expect(result).toContain('readonly address: Address');
607
+ expect(result).toContain('readonly address: AddressOutput');
608
+ });
609
+
610
+ it('handles value object field referencing another value object (input)', () => {
611
+ const companyVo: ContractValueObject = {
612
+ fields: {
613
+ name: { nullable: false, type: { kind: 'scalar', codecId: 'mongo/string@1' } },
614
+ address: { nullable: false, type: { kind: 'valueObject', name: 'Address' } },
615
+ },
616
+ };
617
+ const vos = { ...valueObjects, Company: companyVo };
618
+ const result = generateValueObjectType('Company', companyVo, vos, 'input');
619
+ expect(result).toContain('readonly address: AddressInput');
571
620
  });
572
621
 
573
622
  it('handles self-referencing value object (no infinite recursion)', () => {
@@ -583,7 +632,7 @@ describe('generateValueObjectType', () => {
583
632
  };
584
633
  const vos = { NavItem: navItemVo };
585
634
  const result = generateValueObjectType('NavItem', navItemVo, vos);
586
- expect(result).toContain('readonly children: ReadonlyArray<NavItem>');
635
+ expect(result).toContain('readonly children: ReadonlyArray<NavItemOutput>');
587
636
  });
588
637
 
589
638
  it('returns Record<string, never> for empty value object', () => {
@@ -678,7 +727,7 @@ describe('generateValueObjectTypeAliases', () => {
678
727
  expect(generateValueObjectTypeAliases({})).toBe('');
679
728
  });
680
729
 
681
- it('generates export type alias for each value object', () => {
730
+ it('generates output and input type alias pairs for each value object', () => {
682
731
  const valueObjects: Record<string, ContractValueObject> = {
683
732
  Address: {
684
733
  fields: {
@@ -687,11 +736,14 @@ describe('generateValueObjectTypeAliases', () => {
687
736
  },
688
737
  };
689
738
  const result = generateValueObjectTypeAliases(valueObjects);
690
- expect(result).toContain('export type Address =');
739
+ expect(result).toContain('export type AddressOutput =');
740
+ expect(result).toContain('export type AddressInput =');
691
741
  expect(result).toContain("readonly street: CodecTypes['mongo/string@1']['output']");
742
+ expect(result).toContain("readonly street: CodecTypes['mongo/string@1']['input']");
743
+ expect(result).not.toMatch(/export type Address =/);
692
744
  });
693
745
 
694
- it('generates multiple type aliases', () => {
746
+ it('generates multiple type alias pairs', () => {
695
747
  const valueObjects: Record<string, ContractValueObject> = {
696
748
  Address: {
697
749
  fields: {
@@ -706,8 +758,10 @@ describe('generateValueObjectTypeAliases', () => {
706
758
  },
707
759
  };
708
760
  const result = generateValueObjectTypeAliases(valueObjects);
709
- expect(result).toContain('export type Address =');
710
- expect(result).toContain('export type GeoPoint =');
761
+ expect(result).toContain('export type AddressOutput =');
762
+ expect(result).toContain('export type AddressInput =');
763
+ expect(result).toContain('export type GeoPointOutput =');
764
+ expect(result).toContain('export type GeoPointInput =');
711
765
  });
712
766
  });
713
767
 
@@ -821,4 +875,123 @@ describe('generateFieldOutputTypesMap', () => {
821
875
  expect(generateFieldOutputTypesMap(undefined)).toBe('Record<string, never>');
822
876
  expect(generateFieldOutputTypesMap({})).toBe('Record<string, never>');
823
877
  });
878
+
879
+ it('references {Name}Output for value object fields', () => {
880
+ const models: Record<string, ContractModel> = {
881
+ Product: {
882
+ fields: {
883
+ price: {
884
+ nullable: false,
885
+ type: { kind: 'valueObject', name: 'Price' },
886
+ },
887
+ },
888
+ relations: {},
889
+ storage: {},
890
+ },
891
+ };
892
+ const result = generateFieldOutputTypesMap(models);
893
+ expect(result).toContain('readonly price: PriceOutput');
894
+ });
895
+ });
896
+
897
+ describe('generateFieldInputTypesMap', () => {
898
+ it('generates input-side codec lookups', () => {
899
+ const models: Record<string, ContractModel> = {
900
+ User: {
901
+ fields: {
902
+ name: {
903
+ nullable: false,
904
+ type: { kind: 'scalar', codecId: 'mongo/string@1' },
905
+ },
906
+ },
907
+ relations: {},
908
+ storage: {},
909
+ },
910
+ };
911
+ const result = generateFieldInputTypesMap(models);
912
+ expect(result).toContain("CodecTypes['mongo/string@1']['input']");
913
+ });
914
+
915
+ it('references {Name}Input for value object fields', () => {
916
+ const models: Record<string, ContractModel> = {
917
+ Product: {
918
+ fields: {
919
+ price: {
920
+ nullable: false,
921
+ type: { kind: 'valueObject', name: 'Price' },
922
+ },
923
+ },
924
+ relations: {},
925
+ storage: {},
926
+ },
927
+ };
928
+ const result = generateFieldInputTypesMap(models);
929
+ expect(result).toContain('readonly price: PriceInput');
930
+ });
931
+
932
+ it('returns Record<string, never> for empty models', () => {
933
+ expect(generateFieldInputTypesMap(undefined)).toBe('Record<string, never>');
934
+ expect(generateFieldInputTypesMap({})).toBe('Record<string, never>');
935
+ });
936
+ });
937
+
938
+ describe('generateBothFieldTypesMaps', () => {
939
+ it('generates both output and input maps in a single pass', () => {
940
+ const models: Record<string, ContractModel> = {
941
+ User: {
942
+ fields: {
943
+ _id: { nullable: false, type: { kind: 'scalar', codecId: 'mongo/objectId@1' } },
944
+ },
945
+ relations: {},
946
+ storage: {},
947
+ },
948
+ };
949
+ const result = generateBothFieldTypesMaps(models);
950
+ expect(result.output).toContain("CodecTypes['mongo/objectId@1']['output']");
951
+ expect(result.input).toContain("CodecTypes['mongo/objectId@1']['input']");
952
+ });
953
+
954
+ it('returns Record<string, never> for empty models on both sides', () => {
955
+ const result = generateBothFieldTypesMaps(undefined);
956
+ expect(result.output).toBe('Record<string, never>');
957
+ expect(result.input).toBe('Record<string, never>');
958
+ });
959
+ });
960
+
961
+ describe('resolveFieldType', () => {
962
+ it('returns both input and output for scalar fields', () => {
963
+ const field: ContractField = {
964
+ nullable: false,
965
+ type: { kind: 'scalar', codecId: 'mongo/string@1' },
966
+ };
967
+ const result = resolveFieldType(field);
968
+ expect(result.output).toBe("CodecTypes['mongo/string@1']['output']");
969
+ expect(result.input).toBe("CodecTypes['mongo/string@1']['input']");
970
+ });
971
+
972
+ it('returns suffixed types for value object fields', () => {
973
+ const field: ContractField = {
974
+ nullable: false,
975
+ type: { kind: 'valueObject', name: 'Price' },
976
+ };
977
+ const result = resolveFieldType(field);
978
+ expect(result.output).toBe('PriceOutput');
979
+ expect(result.input).toBe('PriceInput');
980
+ });
981
+
982
+ it('uses renderOutputType only for output side of parameterized codecs', () => {
983
+ const lookup = stubCodecLookup({
984
+ 'pg/char@1': stubCodec({
985
+ id: 'pg/char@1',
986
+ renderOutputType: (p) => `Char<${p['length']}>`,
987
+ }),
988
+ });
989
+ const field: ContractField = {
990
+ nullable: false,
991
+ type: { kind: 'scalar', codecId: 'pg/char@1', typeParams: { length: 36 } },
992
+ };
993
+ const result = resolveFieldType(field, lookup);
994
+ expect(result.output).toBe('Char<36>');
995
+ expect(result.input).toBe("CodecTypes['pg/char@1']['input']");
996
+ });
824
997
  });