@prisma-next/emitter 0.3.0-dev.130 → 0.3.0-dev.132

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.
@@ -1 +1 @@
1
- {"version":3,"file":"domain-type-generation.d.mts","names":[],"sources":["../src/domain-type-generation.ts"],"sourcesContent":[],"mappings":";;;iBAEgB,cAAA;iBA+BA,kBAAA;AA/BA,iBAsCA,iBAAA,CAtCc,KAAA,EAsCW,MAtCX,CAAA,MAAA,EAAA,MAAA,CAAA,GAAA,SAAA,CAAA,EAAA,MAAA;AA+Bd,iBAiBA,0BAAA,CAjBkB,SAAA,EAiBoB,MAjBpB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAAA,MAAA;AAOlB,iBA2CA,kBAAA,CA3C+B,OAAA,EA2CH,eA3CG,EAAA,CAAA,EA2CiB,eA3CjB,EAAA;AAU/B,iBA8CA,mBAAA,CA9CsC,OAAM,EA8Cf,eA9Ce,EAAA,CAAA,EAAA,MAAA,EAAA;AAiC5C,iBAoBA,6BAAA,CApBgD,OAAA,EAqBrD,aArBoE,CAqBtD,eArBsD,CAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAa/D,iBAeA,uBAAA,CAf6B,MAAe,EAAA;EAO5C,SAAA,WAAA,EAAA,MAAA;EAQA,SAAA,aAAA,CAAA,EAAA,MAAuB"}
1
+ {"version":3,"file":"domain-type-generation.d.mts","names":[],"sources":["../src/domain-type-generation.ts"],"sourcesContent":[],"mappings":";;;iBAEgB,cAAA;iBA+BA,kBAAA;AA/BA,iBAsCA,iBAAA,CAtCc,KAAA,EAsCW,MAtCX,CAAA,MAAA,EAAA,MAAA,CAAA,GAAA,SAAA,CAAA,EAAA,MAAA;AA+Bd,iBAiBA,0BAAA,CAjBkB,SAAA,EAiBoB,MAjBpB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,EAAA,MAAA;AAOlB,iBAgDA,kBAAA,CAhD+B,OAAA,EAgDH,eAhDG,EAAA,CAAA,EAgDiB,eAhDjB,EAAA;AAU/B,iBAmDA,mBAAA,CAnDsC,OAAM,EAmDf,eAnDe,EAAA,CAAA,EAAA,MAAA,EAAA;AAsC5C,iBAoBA,6BAAA,CApBgD,OAAA,EAqBrD,aArBoE,CAqBtD,eArBsD,CAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AAa/D,iBAeA,uBAAA,CAf6B,MAAe,EAAA;EAO5C,SAAA,WAAA,EAAA,MAAA;EAQA,SAAA,aAAA,CAAA,EAAA,MAAuB"}
@@ -30,6 +30,7 @@ function generateModelRelationsType(relations) {
30
30
  if (relObj["to"]) parts.push(`readonly to: ${serializeValue(relObj["to"])}`);
31
31
  if (relObj["cardinality"]) parts.push(`readonly cardinality: ${serializeValue(relObj["cardinality"])}`);
32
32
  const on = relObj["on"];
33
+ if (on && (!on.localFields || !on.targetFields)) throw new Error(`Relation "${relName}" has an "on" block but is missing localFields or targetFields`);
33
34
  if (on?.localFields && on.targetFields) {
34
35
  const localFields = on.localFields.map((f) => serializeValue(f)).join(", ");
35
36
  const targetFields = on.targetFields.map((f) => serializeValue(f)).join(", ");
@@ -1 +1 @@
1
- {"version":3,"file":"domain-type-generation.mjs","names":["entries: string[]","relationEntries: string[]","parts: string[]","result: TypesImportSpec[]"],"sources":["../src/domain-type-generation.ts"],"sourcesContent":["import type { TypesImportSpec } from '@prisma-next/contract/types';\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\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?.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 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 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"],"mappings":";AAEA,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,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,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,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,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"}
1
+ {"version":3,"file":"domain-type-generation.mjs","names":["entries: string[]","relationEntries: string[]","parts: string[]","result: TypesImportSpec[]"],"sources":["../src/domain-type-generation.ts"],"sourcesContent":["import type { TypesImportSpec } from '@prisma-next/contract/types';\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\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 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 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"],"mappings":";AAEA,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,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,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,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"}
@@ -15,7 +15,6 @@ function createContractIR(overrides = {}) {
15
15
  const hasStorageHash = "storageHash" in overrides;
16
16
  const hasSchemaVersion = "schemaVersion" in overrides;
17
17
  const hasModels = "models" in overrides;
18
- const hasRelations = "relations" in overrides;
19
18
  const hasStorage = "storage" in overrides;
20
19
  const hasCapabilities = "capabilities" in overrides;
21
20
  const hasExtensionPacks = "extensionPacks" in overrides;
@@ -49,8 +48,7 @@ function createContractIR(overrides = {}) {
49
48
  meta: hasMeta && overrides.meta === void 0 ? void 0 : !hasMeta || overrides.meta !== void 0 ? meta.meta : {},
50
49
  sources: hasSources && overrides.sources === void 0 ? void 0 : !hasSources || overrides.sources !== void 0 ? meta.sources : {},
51
50
  storage: hasStorage && overrides.storage === void 0 ? void 0 : hasStorage && overrides.storage !== void 0 ? overrides.storage : !hasStorage ? { tables: {} } : {},
52
- models: hasModels && overrides.models === void 0 ? void 0 : hasModels && overrides.models !== void 0 ? overrides.models : !hasModels ? {} : {},
53
- relations: hasRelations && overrides.relations === void 0 ? void 0 : hasRelations && overrides.relations !== void 0 ? overrides.relations : !hasRelations ? {} : {}
51
+ models: hasModels && overrides.models === void 0 ? void 0 : hasModels && overrides.models !== void 0 ? overrides.models : !hasModels ? {} : {}
54
52
  };
55
53
  }
56
54
 
@@ -1 +1 @@
1
- {"version":3,"file":"utils.mjs","names":["headerOpts: {\n target?: string;\n targetFamily?: string;\n storageHash?: string;\n profileHash?: string;\n }","metaOpts: {\n capabilities?: Record<string, Record<string, boolean>>;\n extensionPacks?: Record<string, unknown>;\n meta?: Record<string, unknown>;\n sources?: Record<string, unknown>;\n }"],"sources":["../../test/utils.ts"],"sourcesContent":["import { type ContractIR, irHeader, irMeta } from '@prisma-next/contract/ir';\n\n/**\n * Factory function for creating ContractIR objects in tests.\n * Provides sensible defaults and allows overriding specific fields.\n * Uses the emitter factories internally for consistency.\n *\n * If a field is explicitly set to `undefined` in overrides, it will be omitted\n * from the result (useful for testing validation of missing fields).\n */\nexport function createContractIR(\n overrides: Partial<ContractIR> & { storageHash?: string; profileHash?: string } = {},\n): ContractIR {\n // Check if fields are explicitly undefined (not just missing)\n const hasTarget = 'target' in overrides;\n const hasTargetFamily = 'targetFamily' in overrides;\n const hasStorageHash = 'storageHash' in overrides;\n const hasSchemaVersion = 'schemaVersion' in overrides;\n const hasModels = 'models' in overrides;\n const hasRelations = 'relations' in overrides;\n const hasStorage = 'storage' in overrides;\n const hasCapabilities = 'capabilities' in overrides;\n const hasExtensionPacks = 'extensionPacks' in overrides;\n const hasMeta = 'meta' in overrides;\n const hasSources = 'sources' in overrides;\n\n // Build header, omitting fields that are explicitly undefined\n const headerOpts: {\n target?: string;\n targetFamily?: string;\n storageHash?: string;\n profileHash?: string;\n } = {};\n\n if (hasTarget && overrides.target !== undefined) {\n headerOpts.target = overrides.target;\n } else if (!hasTarget) {\n headerOpts.target = 'postgres';\n }\n\n if (hasTargetFamily && overrides.targetFamily !== undefined) {\n headerOpts.targetFamily = overrides.targetFamily;\n } else if (!hasTargetFamily) {\n headerOpts.targetFamily = 'sql';\n }\n\n if (hasStorageHash && overrides.storageHash !== undefined) {\n headerOpts.storageHash = overrides.storageHash;\n } else if (!hasStorageHash) {\n headerOpts.storageHash = 'sha256:test';\n }\n\n // profileHash is not part of ContractIR, but we can accept it for header creation\n if (overrides.profileHash !== undefined) {\n headerOpts.profileHash = overrides.profileHash;\n }\n\n const header = irHeader(\n headerOpts as {\n target: string;\n targetFamily: string;\n storageHash: string;\n profileHash?: string;\n },\n );\n\n // Build meta, handling explicitly undefined fields\n // If a field is explicitly undefined, we'll omit it from the result later\n const metaOpts: {\n capabilities?: Record<string, Record<string, boolean>>;\n extensionPacks?: Record<string, unknown>;\n meta?: Record<string, unknown>;\n sources?: Record<string, unknown>;\n } = {};\n\n if (hasCapabilities && overrides.capabilities !== undefined) {\n metaOpts.capabilities = overrides.capabilities;\n } else if (!hasCapabilities) {\n metaOpts.capabilities = {};\n }\n\n if (hasExtensionPacks && overrides.extensionPacks !== undefined) {\n metaOpts.extensionPacks = overrides.extensionPacks;\n } else if (!hasExtensionPacks) {\n metaOpts.extensionPacks = {};\n }\n\n if (hasMeta && overrides.meta !== undefined) {\n metaOpts.meta = overrides.meta;\n } else if (!hasMeta) {\n metaOpts.meta = {};\n }\n\n if (hasSources && overrides.sources !== undefined) {\n metaOpts.sources = overrides.sources;\n } else if (!hasSources) {\n metaOpts.sources = {};\n }\n\n const meta = irMeta(Object.keys(metaOpts).length > 0 ? metaOpts : undefined);\n\n // Build result by constructing the object directly (ContractIR doesn't include storageHash/profileHash)\n // When fields are explicitly undefined, include them as undefined (tests use type assertions to bypass TS)\n const result = {\n schemaVersion:\n hasSchemaVersion && overrides.schemaVersion !== undefined\n ? overrides.schemaVersion\n : hasSchemaVersion && overrides.schemaVersion === undefined\n ? (undefined as unknown as string)\n : header.schemaVersion,\n target: header.target,\n targetFamily: header.targetFamily,\n // Only include meta fields if they're not explicitly undefined\n capabilities:\n hasCapabilities && overrides.capabilities === undefined\n ? (undefined as unknown as Record<string, Record<string, boolean>>)\n : !hasCapabilities || overrides.capabilities !== undefined\n ? meta.capabilities\n : ({} as Record<string, Record<string, boolean>>),\n extensionPacks:\n hasExtensionPacks && overrides.extensionPacks === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : !hasExtensionPacks || overrides.extensionPacks !== undefined\n ? meta.extensionPacks\n : ({} as Record<string, unknown>),\n meta:\n hasMeta && overrides.meta === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : !hasMeta || overrides.meta !== undefined\n ? meta.meta\n : ({} as Record<string, unknown>),\n sources:\n hasSources && overrides.sources === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : !hasSources || overrides.sources !== undefined\n ? meta.sources\n : ({} as Record<string, unknown>),\n // Only include family sections if they're not explicitly undefined\n storage:\n hasStorage && overrides.storage === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : hasStorage && overrides.storage !== undefined\n ? (overrides.storage as Record<string, unknown>)\n : !hasStorage\n ? ({ tables: {} } as Record<string, unknown>)\n : ({} as Record<string, unknown>),\n models:\n hasModels && overrides.models === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : hasModels && overrides.models !== undefined\n ? (overrides.models as Record<string, unknown>)\n : !hasModels\n ? {}\n : ({} as Record<string, unknown>),\n relations:\n hasRelations && overrides.relations === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : hasRelations && overrides.relations !== undefined\n ? (overrides.relations as Record<string, unknown>)\n : !hasRelations\n ? {}\n : ({} as Record<string, unknown>),\n } as ContractIR;\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;AAUA,SAAgB,iBACd,YAAkF,EAAE,EACxE;CAEZ,MAAM,YAAY,YAAY;CAC9B,MAAM,kBAAkB,kBAAkB;CAC1C,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,mBAAmB,mBAAmB;CAC5C,MAAM,YAAY,YAAY;CAC9B,MAAM,eAAe,eAAe;CACpC,MAAM,aAAa,aAAa;CAChC,MAAM,kBAAkB,kBAAkB;CAC1C,MAAM,oBAAoB,oBAAoB;CAC9C,MAAM,UAAU,UAAU;CAC1B,MAAM,aAAa,aAAa;CAGhC,MAAMA,aAKF,EAAE;AAEN,KAAI,aAAa,UAAU,WAAW,OACpC,YAAW,SAAS,UAAU;UACrB,CAAC,UACV,YAAW,SAAS;AAGtB,KAAI,mBAAmB,UAAU,iBAAiB,OAChD,YAAW,eAAe,UAAU;UAC3B,CAAC,gBACV,YAAW,eAAe;AAG5B,KAAI,kBAAkB,UAAU,gBAAgB,OAC9C,YAAW,cAAc,UAAU;UAC1B,CAAC,eACV,YAAW,cAAc;AAI3B,KAAI,UAAU,gBAAgB,OAC5B,YAAW,cAAc,UAAU;CAGrC,MAAM,SAAS,SACb,WAMD;CAID,MAAMC,WAKF,EAAE;AAEN,KAAI,mBAAmB,UAAU,iBAAiB,OAChD,UAAS,eAAe,UAAU;UACzB,CAAC,gBACV,UAAS,eAAe,EAAE;AAG5B,KAAI,qBAAqB,UAAU,mBAAmB,OACpD,UAAS,iBAAiB,UAAU;UAC3B,CAAC,kBACV,UAAS,iBAAiB,EAAE;AAG9B,KAAI,WAAW,UAAU,SAAS,OAChC,UAAS,OAAO,UAAU;UACjB,CAAC,QACV,UAAS,OAAO,EAAE;AAGpB,KAAI,cAAc,UAAU,YAAY,OACtC,UAAS,UAAU,UAAU;UACpB,CAAC,WACV,UAAS,UAAU,EAAE;CAGvB,MAAM,OAAO,OAAO,OAAO,KAAK,SAAS,CAAC,SAAS,IAAI,WAAW,OAAU;AAiE5E,QA7De;EACb,eACE,oBAAoB,UAAU,kBAAkB,SAC5C,UAAU,gBACV,oBAAoB,UAAU,kBAAkB,SAC7C,SACD,OAAO;EACf,QAAQ,OAAO;EACf,cAAc,OAAO;EAErB,cACE,mBAAmB,UAAU,iBAAiB,SACzC,SACD,CAAC,mBAAmB,UAAU,iBAAiB,SAC7C,KAAK,eACJ,EAAE;EACX,gBACE,qBAAqB,UAAU,mBAAmB,SAC7C,SACD,CAAC,qBAAqB,UAAU,mBAAmB,SACjD,KAAK,iBACJ,EAAE;EACX,MACE,WAAW,UAAU,SAAS,SACzB,SACD,CAAC,WAAW,UAAU,SAAS,SAC7B,KAAK,OACJ,EAAE;EACX,SACE,cAAc,UAAU,YAAY,SAC/B,SACD,CAAC,cAAc,UAAU,YAAY,SACnC,KAAK,UACJ,EAAE;EAEX,SACE,cAAc,UAAU,YAAY,SAC/B,SACD,cAAc,UAAU,YAAY,SACjC,UAAU,UACX,CAAC,aACE,EAAE,QAAQ,EAAE,EAAE,GACd,EAAE;EACb,QACE,aAAa,UAAU,WAAW,SAC7B,SACD,aAAa,UAAU,WAAW,SAC/B,UAAU,SACX,CAAC,YACC,EAAE,GACD,EAAE;EACb,WACE,gBAAgB,UAAU,cAAc,SACnC,SACD,gBAAgB,UAAU,cAAc,SACrC,UAAU,YACX,CAAC,eACC,EAAE,GACD,EAAE;EACd"}
1
+ {"version":3,"file":"utils.mjs","names":["headerOpts: {\n target?: string;\n targetFamily?: string;\n storageHash?: string;\n profileHash?: string;\n }","metaOpts: {\n capabilities?: Record<string, Record<string, boolean>>;\n extensionPacks?: Record<string, unknown>;\n meta?: Record<string, unknown>;\n sources?: Record<string, unknown>;\n }"],"sources":["../../test/utils.ts"],"sourcesContent":["import { type ContractIR, irHeader, irMeta } from '@prisma-next/contract/ir';\n\n/**\n * Factory function for creating ContractIR objects in tests.\n * Provides sensible defaults and allows overriding specific fields.\n * Uses the emitter factories internally for consistency.\n *\n * If a field is explicitly set to `undefined` in overrides, it will be omitted\n * from the result (useful for testing validation of missing fields).\n */\nexport function createContractIR(\n overrides: Partial<ContractIR> & { storageHash?: string; profileHash?: string } = {},\n): ContractIR {\n // Check if fields are explicitly undefined (not just missing)\n const hasTarget = 'target' in overrides;\n const hasTargetFamily = 'targetFamily' in overrides;\n const hasStorageHash = 'storageHash' in overrides;\n const hasSchemaVersion = 'schemaVersion' in overrides;\n const hasModels = 'models' in overrides;\n const hasStorage = 'storage' in overrides;\n const hasCapabilities = 'capabilities' in overrides;\n const hasExtensionPacks = 'extensionPacks' in overrides;\n const hasMeta = 'meta' in overrides;\n const hasSources = 'sources' in overrides;\n\n // Build header, omitting fields that are explicitly undefined\n const headerOpts: {\n target?: string;\n targetFamily?: string;\n storageHash?: string;\n profileHash?: string;\n } = {};\n\n if (hasTarget && overrides.target !== undefined) {\n headerOpts.target = overrides.target;\n } else if (!hasTarget) {\n headerOpts.target = 'postgres';\n }\n\n if (hasTargetFamily && overrides.targetFamily !== undefined) {\n headerOpts.targetFamily = overrides.targetFamily;\n } else if (!hasTargetFamily) {\n headerOpts.targetFamily = 'sql';\n }\n\n if (hasStorageHash && overrides.storageHash !== undefined) {\n headerOpts.storageHash = overrides.storageHash;\n } else if (!hasStorageHash) {\n headerOpts.storageHash = 'sha256:test';\n }\n\n // profileHash is not part of ContractIR, but we can accept it for header creation\n if (overrides.profileHash !== undefined) {\n headerOpts.profileHash = overrides.profileHash;\n }\n\n const header = irHeader(\n headerOpts as {\n target: string;\n targetFamily: string;\n storageHash: string;\n profileHash?: string;\n },\n );\n\n // Build meta, handling explicitly undefined fields\n // If a field is explicitly undefined, we'll omit it from the result later\n const metaOpts: {\n capabilities?: Record<string, Record<string, boolean>>;\n extensionPacks?: Record<string, unknown>;\n meta?: Record<string, unknown>;\n sources?: Record<string, unknown>;\n } = {};\n\n if (hasCapabilities && overrides.capabilities !== undefined) {\n metaOpts.capabilities = overrides.capabilities;\n } else if (!hasCapabilities) {\n metaOpts.capabilities = {};\n }\n\n if (hasExtensionPacks && overrides.extensionPacks !== undefined) {\n metaOpts.extensionPacks = overrides.extensionPacks;\n } else if (!hasExtensionPacks) {\n metaOpts.extensionPacks = {};\n }\n\n if (hasMeta && overrides.meta !== undefined) {\n metaOpts.meta = overrides.meta;\n } else if (!hasMeta) {\n metaOpts.meta = {};\n }\n\n if (hasSources && overrides.sources !== undefined) {\n metaOpts.sources = overrides.sources;\n } else if (!hasSources) {\n metaOpts.sources = {};\n }\n\n const meta = irMeta(Object.keys(metaOpts).length > 0 ? metaOpts : undefined);\n\n // Build result by constructing the object directly (ContractIR doesn't include storageHash/profileHash)\n // When fields are explicitly undefined, include them as undefined (tests use type assertions to bypass TS)\n const result = {\n schemaVersion:\n hasSchemaVersion && overrides.schemaVersion !== undefined\n ? overrides.schemaVersion\n : hasSchemaVersion && overrides.schemaVersion === undefined\n ? (undefined as unknown as string)\n : header.schemaVersion,\n target: header.target,\n targetFamily: header.targetFamily,\n // Only include meta fields if they're not explicitly undefined\n capabilities:\n hasCapabilities && overrides.capabilities === undefined\n ? (undefined as unknown as Record<string, Record<string, boolean>>)\n : !hasCapabilities || overrides.capabilities !== undefined\n ? meta.capabilities\n : ({} as Record<string, Record<string, boolean>>),\n extensionPacks:\n hasExtensionPacks && overrides.extensionPacks === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : !hasExtensionPacks || overrides.extensionPacks !== undefined\n ? meta.extensionPacks\n : ({} as Record<string, unknown>),\n meta:\n hasMeta && overrides.meta === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : !hasMeta || overrides.meta !== undefined\n ? meta.meta\n : ({} as Record<string, unknown>),\n sources:\n hasSources && overrides.sources === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : !hasSources || overrides.sources !== undefined\n ? meta.sources\n : ({} as Record<string, unknown>),\n // Only include family sections if they're not explicitly undefined\n storage:\n hasStorage && overrides.storage === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : hasStorage && overrides.storage !== undefined\n ? (overrides.storage as Record<string, unknown>)\n : !hasStorage\n ? ({ tables: {} } as Record<string, unknown>)\n : ({} as Record<string, unknown>),\n models:\n hasModels && overrides.models === undefined\n ? (undefined as unknown as Record<string, unknown>)\n : hasModels && overrides.models !== undefined\n ? (overrides.models as Record<string, unknown>)\n : !hasModels\n ? {}\n : ({} as Record<string, unknown>),\n } as ContractIR;\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;AAUA,SAAgB,iBACd,YAAkF,EAAE,EACxE;CAEZ,MAAM,YAAY,YAAY;CAC9B,MAAM,kBAAkB,kBAAkB;CAC1C,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,mBAAmB,mBAAmB;CAC5C,MAAM,YAAY,YAAY;CAC9B,MAAM,aAAa,aAAa;CAChC,MAAM,kBAAkB,kBAAkB;CAC1C,MAAM,oBAAoB,oBAAoB;CAC9C,MAAM,UAAU,UAAU;CAC1B,MAAM,aAAa,aAAa;CAGhC,MAAMA,aAKF,EAAE;AAEN,KAAI,aAAa,UAAU,WAAW,OACpC,YAAW,SAAS,UAAU;UACrB,CAAC,UACV,YAAW,SAAS;AAGtB,KAAI,mBAAmB,UAAU,iBAAiB,OAChD,YAAW,eAAe,UAAU;UAC3B,CAAC,gBACV,YAAW,eAAe;AAG5B,KAAI,kBAAkB,UAAU,gBAAgB,OAC9C,YAAW,cAAc,UAAU;UAC1B,CAAC,eACV,YAAW,cAAc;AAI3B,KAAI,UAAU,gBAAgB,OAC5B,YAAW,cAAc,UAAU;CAGrC,MAAM,SAAS,SACb,WAMD;CAID,MAAMC,WAKF,EAAE;AAEN,KAAI,mBAAmB,UAAU,iBAAiB,OAChD,UAAS,eAAe,UAAU;UACzB,CAAC,gBACV,UAAS,eAAe,EAAE;AAG5B,KAAI,qBAAqB,UAAU,mBAAmB,OACpD,UAAS,iBAAiB,UAAU;UAC3B,CAAC,kBACV,UAAS,iBAAiB,EAAE;AAG9B,KAAI,WAAW,UAAU,SAAS,OAChC,UAAS,OAAO,UAAU;UACjB,CAAC,QACV,UAAS,OAAO,EAAE;AAGpB,KAAI,cAAc,UAAU,YAAY,OACtC,UAAS,UAAU,UAAU;UACpB,CAAC,WACV,UAAS,UAAU,EAAE;CAGvB,MAAM,OAAO,OAAO,OAAO,KAAK,SAAS,CAAC,SAAS,IAAI,WAAW,OAAU;AAyD5E,QArDe;EACb,eACE,oBAAoB,UAAU,kBAAkB,SAC5C,UAAU,gBACV,oBAAoB,UAAU,kBAAkB,SAC7C,SACD,OAAO;EACf,QAAQ,OAAO;EACf,cAAc,OAAO;EAErB,cACE,mBAAmB,UAAU,iBAAiB,SACzC,SACD,CAAC,mBAAmB,UAAU,iBAAiB,SAC7C,KAAK,eACJ,EAAE;EACX,gBACE,qBAAqB,UAAU,mBAAmB,SAC7C,SACD,CAAC,qBAAqB,UAAU,mBAAmB,SACjD,KAAK,iBACJ,EAAE;EACX,MACE,WAAW,UAAU,SAAS,SACzB,SACD,CAAC,WAAW,UAAU,SAAS,SAC7B,KAAK,OACJ,EAAE;EACX,SACE,cAAc,UAAU,YAAY,SAC/B,SACD,CAAC,cAAc,UAAU,YAAY,SACnC,KAAK,UACJ,EAAE;EAEX,SACE,cAAc,UAAU,YAAY,SAC/B,SACD,cAAc,UAAU,YAAY,SACjC,UAAU,UACX,CAAC,aACE,EAAE,QAAQ,EAAE,EAAE,GACd,EAAE;EACb,QACE,aAAa,UAAU,WAAW,SAC7B,SACD,aAAa,UAAU,WAAW,SAC/B,UAAU,SACX,CAAC,YACC,EAAE,GACD,EAAE;EACd"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma-next/emitter",
3
- "version": "0.3.0-dev.130",
3
+ "version": "0.3.0-dev.132",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "files": [
@@ -10,18 +10,18 @@
10
10
  ],
11
11
  "dependencies": {
12
12
  "arktype": "^2.0.0",
13
- "@prisma-next/contract": "0.3.0-dev.130",
14
- "@prisma-next/core-control-plane": "0.3.0-dev.130"
13
+ "@prisma-next/contract": "0.3.0-dev.132",
14
+ "@prisma-next/core-control-plane": "0.3.0-dev.132"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@types/node": "24.10.4",
18
18
  "tsdown": "0.18.4",
19
19
  "typescript": "5.9.3",
20
20
  "vitest": "4.0.17",
21
+ "@prisma-next/operations": "0.3.0-dev.132",
21
22
  "@prisma-next/test-utils": "0.0.1",
22
- "@prisma-next/tsdown": "0.0.0",
23
- "@prisma-next/operations": "0.3.0-dev.130",
24
- "@prisma-next/tsconfig": "0.0.0"
23
+ "@prisma-next/tsconfig": "0.0.0",
24
+ "@prisma-next/tsdown": "0.0.0"
25
25
  },
26
26
  "exports": {
27
27
  ".": {
@@ -61,6 +61,11 @@ export function generateModelRelationsType(relations: Record<string, unknown>):
61
61
  parts.push(`readonly cardinality: ${serializeValue(relObj['cardinality'])}`);
62
62
 
63
63
  const on = relObj['on'] as { localFields?: string[]; targetFields?: string[] } | undefined;
64
+ if (on && (!on.localFields || !on.targetFields)) {
65
+ throw new Error(
66
+ `Relation "${relName}" has an "on" block but is missing localFields or targetFields`,
67
+ );
68
+ }
64
69
  if (on?.localFields && on.targetFields) {
65
70
  const localFields = on.localFields.map((f) => serializeValue(f)).join(', ');
66
71
  const targetFields = on.targetFields.map((f) => serializeValue(f)).join(', ');
@@ -17,7 +17,6 @@ describe('canonicalization', () => {
17
17
  const targetFamilyIndex = keys.indexOf('targetFamily');
18
18
  const targetIndex = keys.indexOf('target');
19
19
  const modelsIndex = keys.indexOf('models');
20
- const relationsIndex = keys.indexOf('relations');
21
20
  const storageIndex = keys.indexOf('storage');
22
21
  const capabilitiesIndex = keys.indexOf('capabilities');
23
22
  const metaIndex = keys.indexOf('meta');
@@ -25,8 +24,6 @@ describe('canonicalization', () => {
25
24
  expect(schemaVersionIndex).toBeLessThan(targetFamilyIndex);
26
25
  expect(targetFamilyIndex).toBeLessThan(targetIndex);
27
26
  expect(targetIndex).toBeLessThan(modelsIndex);
28
- expect(modelsIndex).toBeLessThan(relationsIndex);
29
- expect(relationsIndex).toBeLessThan(storageIndex);
30
27
  expect(modelsIndex).toBeLessThan(storageIndex);
31
28
  expect(storageIndex).toBeLessThan(capabilitiesIndex);
32
29
  expect(capabilitiesIndex).toBeLessThan(metaIndex);
@@ -136,13 +133,13 @@ describe('canonicalization', () => {
136
133
  tables: expect.anything(),
137
134
  },
138
135
  });
139
- // Required top-level fields (capabilities, extensionPacks, meta, relations) are preserved even when empty.
136
+ // Required top-level fields (capabilities, extensionPacks, meta) are preserved even when empty.
140
137
  expect(parsed).toMatchObject({
141
138
  capabilities: expect.anything(),
142
139
  extensionPacks: expect.anything(),
143
140
  meta: expect.anything(),
144
- relations: expect.anything(),
145
141
  });
142
+ expect(parsed).not.toHaveProperty('relations');
146
143
  });
147
144
 
148
145
  it('preserves semantic array order for column lists', () => {
@@ -157,6 +157,18 @@ describe('generateModelRelationsType', () => {
157
157
  });
158
158
  expect(result).toBe('Record<string, never>');
159
159
  });
160
+
161
+ it('throws when relation has on but missing localFields/targetFields', () => {
162
+ expect(() =>
163
+ generateModelRelationsType({
164
+ author: {
165
+ to: 'User',
166
+ cardinality: 'N:1',
167
+ on: { parentCols: ['userId'], childCols: ['id'] },
168
+ },
169
+ }),
170
+ ).toThrow('missing localFields or targetFields');
171
+ });
160
172
  });
161
173
 
162
174
  describe('deduplicateImports', () => {
@@ -259,7 +259,6 @@ describe('emitter integration', () => {
259
259
  targetFamily: contractJson1['targetFamily'] as string,
260
260
  target: contractJson1['target'] as string,
261
261
  models: contractJson1['models'] as Record<string, unknown>,
262
- relations: (contractJson1['relations'] as Record<string, unknown>) || {},
263
262
  storage: contractJson1['storage'] as Record<string, unknown>,
264
263
  extensionPacks: contractJson1['extensionPacks'] as Record<string, unknown>,
265
264
  capabilities:
@@ -121,7 +121,6 @@ describe('emitter round-trip', () => {
121
121
  targetFamily: contractJson1['targetFamily'] as string,
122
122
  target: contractJson1['target'] as string,
123
123
  models: contractJson1['models'] as Record<string, unknown>,
124
- relations: (contractJson1['relations'] as Record<string, unknown>) || {},
125
124
  storage: contractJson1['storage'] as Record<string, unknown>,
126
125
  extensionPacks: contractJson1['extensionPacks'] as Record<string, unknown>,
127
126
  capabilities:
@@ -218,7 +217,6 @@ describe('emitter round-trip', () => {
218
217
  targetFamily: contractJson1['targetFamily'] as string,
219
218
  target: contractJson1['target'] as string,
220
219
  models: contractJson1['models'] as Record<string, unknown>,
221
- relations: (contractJson1['relations'] as Record<string, unknown>) || {},
222
220
  storage: contractJson1['storage'] as Record<string, unknown>,
223
221
  extensionPacks: contractJson1['extensionPacks'] as Record<string, unknown>,
224
222
  capabilities:
@@ -277,7 +275,6 @@ describe('emitter round-trip', () => {
277
275
  targetFamily: contractJson1['targetFamily'] as string,
278
276
  target: contractJson1['target'] as string,
279
277
  models: contractJson1['models'] as Record<string, unknown>,
280
- relations: (contractJson1['relations'] as Record<string, unknown>) || {},
281
278
  storage: contractJson1['storage'] as Record<string, unknown>,
282
279
  extensionPacks: contractJson1['extensionPacks'] as Record<string, unknown>,
283
280
  capabilities:
@@ -352,7 +349,6 @@ describe('emitter round-trip', () => {
352
349
  targetFamily: contractJson1['targetFamily'] as string,
353
350
  target: contractJson1['target'] as string,
354
351
  models: contractJson1['models'] as Record<string, unknown>,
355
- relations: (contractJson1['relations'] as Record<string, unknown>) || {},
356
352
  storage: contractJson1['storage'] as Record<string, unknown>,
357
353
  extensionPacks: contractJson1['extensionPacks'] as Record<string, unknown>,
358
354
  capabilities:
@@ -428,25 +428,6 @@ describe('emitter', () => {
428
428
  await expect(emit(ir, options, mockSqlHook)).rejects.toThrow('ContractIR must have storage');
429
429
  });
430
430
 
431
- it('throws error when relations is not an object', async () => {
432
- const ir = createContractIR({
433
- relations: 'not-an-object' as unknown as Record<string, unknown>,
434
- }) as ContractIR;
435
-
436
- const operationRegistry = createOperationRegistry();
437
- const options: EmitOptions = {
438
- outputDir: '',
439
- operationRegistry,
440
- codecTypeImports: [],
441
- operationTypeImports: [],
442
- extensionIds: [],
443
- };
444
-
445
- await expect(emit(ir, options, mockSqlHook)).rejects.toThrow(
446
- 'ContractIR relations must be an object when provided',
447
- );
448
- });
449
-
450
431
  it('throws error when extension packs are missing', async () => {
451
432
  const ir = createContractIR({
452
433
  extensionPacks: undefined as unknown as Record<string, unknown>,
@@ -8,7 +8,6 @@ describe('hashing', () => {
8
8
  targetFamily: 'sql',
9
9
  target: 'postgres',
10
10
  models: {},
11
- relations: {},
12
11
  storage: { tables: {} },
13
12
  extensionPacks: {},
14
13
  capabilities: {},
@@ -26,7 +25,6 @@ describe('hashing', () => {
26
25
  targetFamily: 'sql',
27
26
  target: 'postgres',
28
27
  models: {},
29
- relations: {},
30
28
  storage: { tables: {} },
31
29
  extensionPacks: {},
32
30
  capabilities: { postgres: { jsonAgg: true } },
@@ -44,7 +42,6 @@ describe('hashing', () => {
44
42
  targetFamily: 'sql',
45
43
  target: 'postgres',
46
44
  models: {},
47
- relations: {},
48
45
  storage: { tables: {} },
49
46
  extensionPacks: {},
50
47
  capabilities: {},
package/test/utils.ts CHANGED
@@ -17,7 +17,6 @@ export function createContractIR(
17
17
  const hasStorageHash = 'storageHash' in overrides;
18
18
  const hasSchemaVersion = 'schemaVersion' in overrides;
19
19
  const hasModels = 'models' in overrides;
20
- const hasRelations = 'relations' in overrides;
21
20
  const hasStorage = 'storage' in overrides;
22
21
  const hasCapabilities = 'capabilities' in overrides;
23
22
  const hasExtensionPacks = 'extensionPacks' in overrides;
@@ -152,14 +151,6 @@ export function createContractIR(
152
151
  : !hasModels
153
152
  ? {}
154
153
  : ({} as Record<string, unknown>),
155
- relations:
156
- hasRelations && overrides.relations === undefined
157
- ? (undefined as unknown as Record<string, unknown>)
158
- : hasRelations && overrides.relations !== undefined
159
- ? (overrides.relations as Record<string, unknown>)
160
- : !hasRelations
161
- ? {}
162
- : ({} as Record<string, unknown>),
163
154
  } as ContractIR;
164
155
 
165
156
  return result;