@prisma-next/emitter 0.3.0-dev.156 → 0.3.0-dev.158
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/domain-type-generation.d.mts +12 -4
- package/dist/domain-type-generation.d.mts.map +1 -1
- package/dist/domain-type-generation.mjs +82 -40
- package/dist/domain-type-generation.mjs.map +1 -1
- package/dist/exports/index.mjs +5 -4
- package/dist/exports/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/domain-type-generation.ts +116 -44
- package/src/generate-contract-dts.ts +5 -4
- package/test/domain-type-generation.test.ts +188 -15
|
@@ -19,12 +19,20 @@ declare function generateHashTypeAliases(hashes: {
|
|
|
19
19
|
readonly executionHash?: string;
|
|
20
20
|
readonly profileHash: string;
|
|
21
21
|
}): string;
|
|
22
|
-
|
|
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
|
|
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,
|
|
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
|
|
121
|
-
let
|
|
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
|
|
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))
|
|
136
|
+
if (rendered && isSafeTypeExpression(rendered)) outputResolved = rendered;
|
|
131
137
|
}
|
|
132
138
|
}
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
155
|
-
|
|
156
|
-
|
|
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
|
|
175
|
+
const outputFieldEntries = [];
|
|
176
|
+
const inputFieldEntries = [];
|
|
160
177
|
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
161
|
-
const
|
|
162
|
-
|
|
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
|
|
165
|
-
|
|
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
|
|
189
|
+
return {
|
|
190
|
+
output: `{ ${outputModelEntries.join("; ")} }`,
|
|
191
|
+
input: `{ ${inputModelEntries.join("; ")} }`
|
|
192
|
+
};
|
|
168
193
|
}
|
|
169
|
-
function
|
|
170
|
-
|
|
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
|
|
173
|
-
|
|
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
|
-
|
|
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
|
|
206
|
-
aliases.push(`export type ${voName} = ${
|
|
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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"}
|
package/dist/exports/index.mjs
CHANGED
|
@@ -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
|
|
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 = ${
|
|
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
|
|
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.
|
|
3
|
+
"version": "0.3.0-dev.158",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"files": [
|
|
@@ -11,19 +11,19 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"arktype": "^2.0.0",
|
|
13
13
|
"prettier": "^3.3.3",
|
|
14
|
-
"@prisma-next/
|
|
15
|
-
"@prisma-next/
|
|
16
|
-
"@prisma-next/operations": "0.3.0-dev.
|
|
17
|
-
"@prisma-next/utils": "0.3.0-dev.
|
|
14
|
+
"@prisma-next/framework-components": "0.3.0-dev.158",
|
|
15
|
+
"@prisma-next/contract": "0.3.0-dev.158",
|
|
16
|
+
"@prisma-next/operations": "0.3.0-dev.158",
|
|
17
|
+
"@prisma-next/utils": "0.3.0-dev.158"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/node": "24.10.4",
|
|
21
21
|
"tsdown": "0.18.4",
|
|
22
22
|
"typescript": "5.9.3",
|
|
23
23
|
"vitest": "4.0.17",
|
|
24
|
-
"@prisma-next/
|
|
24
|
+
"@prisma-next/test-utils": "0.0.1",
|
|
25
25
|
"@prisma-next/tsdown": "0.0.0",
|
|
26
|
-
"@prisma-next/
|
|
26
|
+
"@prisma-next/tsconfig": "0.0.0"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
@@ -215,89 +215,159 @@ export function generateHashTypeAliases(hashes: {
|
|
|
215
215
|
].join('\n');
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
export
|
|
219
|
-
|
|
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
|
|
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
|
-
|
|
242
|
+
outputResolved = rendered;
|
|
231
243
|
}
|
|
232
244
|
}
|
|
233
245
|
}
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
239
|
-
|
|
253
|
+
return {
|
|
254
|
+
output: applyModifiers(`${type.name}Output`, field),
|
|
255
|
+
input: applyModifiers(`${type.name}Input`, field),
|
|
256
|
+
};
|
|
240
257
|
case 'union': {
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
250
|
-
|
|
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
|
-
|
|
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
|
|
289
|
+
export function generateBothFieldTypesMaps(
|
|
267
290
|
models: Record<string, ContractModel> | undefined,
|
|
268
291
|
codecLookup?: CodecLookup,
|
|
269
|
-
):
|
|
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
|
|
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
|
|
301
|
+
const outputFieldEntries: string[] = [];
|
|
302
|
+
const inputFieldEntries: string[] = [];
|
|
278
303
|
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
279
|
-
const
|
|
280
|
-
|
|
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
|
|
283
|
-
|
|
284
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
298
|
-
|
|
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
|
-
|
|
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
|
|
354
|
-
aliases.push(`export type ${voName} = ${
|
|
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
|
|
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 = ${
|
|
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
|
|
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('
|
|
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<
|
|
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('
|
|
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<
|
|
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'] |
|
|
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:
|
|
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<
|
|
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
|
|
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
|
|
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
|
|
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
|
|
710
|
-
expect(result).toContain('export type
|
|
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
|
});
|