@prisma-next/emitter 0.4.0-dev.11 → 0.4.0-dev.13

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.
@@ -3,8 +3,14 @@ import { Contract } from "@prisma-next/contract/types";
3
3
  import { CodecLookup } from "@prisma-next/framework-components/codec";
4
4
  import { EmissionSpi, GenerateContractTypesOptions, TypesImportSpec } from "@prisma-next/framework-components/emission";
5
5
 
6
+ //#region src/artifact-paths.d.ts
7
+ interface EmittedArtifactPaths {
8
+ readonly jsonPath: string;
9
+ readonly dtsPath: string;
10
+ }
11
+ declare function getEmittedArtifactPaths(outputJsonPath: string): EmittedArtifactPaths;
12
+ //#endregion
6
13
  //#region src/emit-types.d.ts
7
-
8
14
  /**
9
15
  * The subset of ControlStack that emit() reads.
10
16
  * All fields are optional so tests can pass minimal objects.
@@ -17,6 +23,9 @@ interface EmitStackInput {
17
23
  readonly extensionIds?: ReadonlyArray<string>;
18
24
  readonly codecLookup?: CodecLookup;
19
25
  }
26
+ interface EmitOptions {
27
+ readonly outputJsonPath?: string;
28
+ }
20
29
  interface EmitResult {
21
30
  readonly contractJson: string;
22
31
  readonly contractDts: string;
@@ -26,7 +35,7 @@ interface EmitResult {
26
35
  }
27
36
  //#endregion
28
37
  //#region src/emit.d.ts
29
- declare function emit(contract: Contract, stack: EmitStackInput, targetFamily: EmissionSpi): Promise<EmitResult>;
38
+ declare function emit(contract: Contract, stack: EmitStackInput, targetFamily: EmissionSpi, options?: EmitOptions): Promise<EmitResult>;
30
39
  //#endregion
31
40
  //#region src/generate-contract-dts.d.ts
32
41
  declare function generateContractDts(contract: Contract, emitter: EmissionSpi, codecTypeImports: ReadonlyArray<TypesImportSpec>, operationTypeImports: ReadonlyArray<TypesImportSpec>, hashes: {
@@ -35,5 +44,5 @@ declare function generateContractDts(contract: Contract, emitter: EmissionSpi, c
35
44
  readonly profileHash: string;
36
45
  }, options?: GenerateContractTypesOptions, codecLookup?: CodecLookup): string;
37
46
  //#endregion
38
- export { type EmitResult, type EmitStackInput, deduplicateImports, emit, generateCodecTypeIntersection, generateContractDts, generateFieldOutputTypesMap, generateHashTypeAliases, generateImportLines, generateModelRelationsType, generateRootsType, serializeObjectKey, serializeValue };
47
+ export { type EmitResult, type EmitStackInput, type EmittedArtifactPaths, deduplicateImports, emit, generateCodecTypeIntersection, generateContractDts, generateFieldOutputTypesMap, generateHashTypeAliases, generateImportLines, generateModelRelationsType, generateRootsType, getEmittedArtifactPaths, serializeObjectKey, serializeValue };
39
48
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/emit-types.ts","../../src/emit.ts","../../src/generate-contract-dts.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAQA;AAC4C,UAD3B,cAAA,CAC2B;EAAd,SAAA,gBAAA,CAAA,EAAA,aAAA,CAAc,eAAd,CAAA;EACkB,SAAA,oBAAA,CAAA,EAAd,aAAc,CAAA,eAAA,CAAA;EAAd,SAAA,yBAAA,CAAA,EACK,aADL,CACmB,eADnB,CAAA;EACmB,SAAA,YAAA,CAAA,EAC3B,aAD2B,CAAA,MAAA,CAAA;EAAd,SAAA,WAAA,CAAA,EAEd,WAFc;;AAEd,UAGR,UAAA,CAHQ;EAAW,SAAA,YAAA,EAAA,MAAA;EAGnB,SAAA,WAAU,EAAA,MAAA;;;;ACN3B;;;iBAAsB,IAAA,WACV,iBACH,8BACO,cACb,QAAQ;;;iBCOK,mBAAA,WACJ,mBACD,+BACS,cAAc,wCACV,cAAc;;;EFjBrB,SAAA,WAAc,EAAA,MAAA;CACa,EAAA,OAAA,CAAA,EEsBhC,4BFtBgC,EAAA,WAAA,CAAA,EEuB5B,WFvB4B,CAAA,EAAA,MAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/artifact-paths.ts","../../src/emit-types.ts","../../src/emit.ts","../../src/generate-contract-dts.ts"],"sourcesContent":[],"mappings":";;;;;;UAEiB,oBAAA;;;;iBAKD,uBAAA,0BAAiD;;;;;;;AALjE;AAKgB,UCCC,cAAA,CDDsB;8BCET,cAAc;kCACV,cAAc;uCACT,cAAc;EAHpC,SAAA,YAAc,CAAA,EAIL,aAJK,CAAA,MAAA,CAAA;EACa,SAAA,WAAA,CAAA,EAInB,WAJmB;;AACI,UAM/B,WAAA,CAN+B;EAAd,SAAA,cAAA,CAAA,EAAA,MAAA;;AACK,UAStB,UAAA,CATsB;EACb,SAAA,YAAA,EAAA,MAAA;EACD,SAAA,WAAA,EAAA,MAAA;EAAW,SAAA,WAAA,EAAA,MAAA;EAGnB,SAAA,aAAW,CAAA,EAAA,MAAA;EAIX,SAAA,WAAU,EAAA,MAAA;;;;iBCTL,IAAA,WACV,iBACH,8BACO,uBACJ,cACT,QAAQ;;;iBCKK,mBAAA,WACJ,mBACD,+BACS,cAAc,wCACV,cAAc;;;EHvBrB,SAAA,WAAA,EAAA,MAAoB;AAKrC,CAAA,EAAA,OAAuC,CAAvB,EGwBJ,4BHxB2B,EAA0B,WAAoB,CAApB,EGyBjD,WHzBqE,CAAA,EAAA,MAAA"}
@@ -3,6 +3,17 @@ import { canonicalizeContractToObject } from "@prisma-next/contract/hashing";
3
3
  import { ifDefined } from "@prisma-next/utils/defined";
4
4
  import { format } from "prettier";
5
5
 
6
+ //#region src/artifact-paths.ts
7
+ const JSON_EXTENSION = ".json";
8
+ function getEmittedArtifactPaths(outputJsonPath) {
9
+ if (!outputJsonPath.endsWith(JSON_EXTENSION)) throw new Error("Contract output path must end with .json");
10
+ return {
11
+ jsonPath: outputJsonPath,
12
+ dtsPath: `${outputJsonPath.slice(0, -5)}.d.ts`
13
+ };
14
+ }
15
+
16
+ //#endregion
6
17
  //#region src/generate-contract-dts.ts
7
18
  function generateContractDts(contract, emitter, codecTypeImports, operationTypeImports, hashes, options, codecLookup) {
8
19
  const allImports = [...codecTypeImports, ...operationTypeImports];
@@ -67,7 +78,8 @@ ${contractWrapper}
67
78
  //#endregion
68
79
  //#region src/emit.ts
69
80
  const SCHEMA_VERSION = "1";
70
- async function emit(contract, stack, targetFamily) {
81
+ async function emit(contract, stack, targetFamily, options) {
82
+ if (options?.outputJsonPath !== void 0) getEmittedArtifactPaths(options.outputJsonPath);
71
83
  const { codecTypeImports, operationTypeImports, queryOperationTypeImports } = stack;
72
84
  const { storageHash } = contract.storage;
73
85
  const executionHash = contract.execution?.executionHash;
@@ -102,5 +114,5 @@ async function emit(contract, stack, targetFamily) {
102
114
  }
103
115
 
104
116
  //#endregion
105
- export { deduplicateImports, emit, generateCodecTypeIntersection, generateContractDts, generateFieldOutputTypesMap, generateHashTypeAliases, generateImportLines, generateModelRelationsType, generateRootsType, serializeObjectKey, serializeValue };
117
+ export { deduplicateImports, emit, generateCodecTypeIntersection, generateContractDts, generateFieldOutputTypesMap, generateHashTypeAliases, generateImportLines, generateModelRelationsType, generateRootsType, getEmittedArtifactPaths, serializeObjectKey, serializeValue };
106
118
  //# sourceMappingURL=index.mjs.map
@@ -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 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"}
1
+ {"version":3,"file":"index.mjs","names":["allImports: TypesImportSpec[]"],"sources":["../../src/artifact-paths.ts","../../src/generate-contract-dts.ts","../../src/emit.ts"],"sourcesContent":["const JSON_EXTENSION = '.json';\n\nexport interface EmittedArtifactPaths {\n readonly jsonPath: string;\n readonly dtsPath: string;\n}\n\nexport function getEmittedArtifactPaths(outputJsonPath: string): EmittedArtifactPaths {\n if (!outputJsonPath.endsWith(JSON_EXTENSION)) {\n throw new Error('Contract output path must end with .json');\n }\n\n return {\n jsonPath: outputJsonPath,\n dtsPath: `${outputJsonPath.slice(0, -JSON_EXTENSION.length)}.d.ts`,\n };\n}\n","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 { getEmittedArtifactPaths } from './artifact-paths';\nimport type { EmitOptions, 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 options?: EmitOptions,\n): Promise<EmitResult> {\n if (options?.outputJsonPath !== undefined) {\n getEmittedArtifactPaths(options.outputJsonPath);\n }\n\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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma-next/emitter",
3
- "version": "0.4.0-dev.11",
3
+ "version": "0.4.0-dev.13",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "files": [
@@ -11,10 +11,10 @@
11
11
  "dependencies": {
12
12
  "arktype": "^2.0.0",
13
13
  "prettier": "^3.3.3",
14
- "@prisma-next/contract": "0.4.0-dev.11",
15
- "@prisma-next/framework-components": "0.4.0-dev.11",
16
- "@prisma-next/utils": "0.4.0-dev.11",
17
- "@prisma-next/operations": "0.4.0-dev.11"
14
+ "@prisma-next/contract": "0.4.0-dev.13",
15
+ "@prisma-next/operations": "0.4.0-dev.13",
16
+ "@prisma-next/utils": "0.4.0-dev.13",
17
+ "@prisma-next/framework-components": "0.4.0-dev.13"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/node": "24.10.4",
@@ -22,8 +22,8 @@
22
22
  "typescript": "5.9.3",
23
23
  "vitest": "4.0.17",
24
24
  "@prisma-next/test-utils": "0.0.1",
25
- "@prisma-next/tsconfig": "0.0.0",
26
- "@prisma-next/tsdown": "0.0.0"
25
+ "@prisma-next/tsdown": "0.0.0",
26
+ "@prisma-next/tsconfig": "0.0.0"
27
27
  },
28
28
  "exports": {
29
29
  ".": {
@@ -0,0 +1,17 @@
1
+ const JSON_EXTENSION = '.json';
2
+
3
+ export interface EmittedArtifactPaths {
4
+ readonly jsonPath: string;
5
+ readonly dtsPath: string;
6
+ }
7
+
8
+ export function getEmittedArtifactPaths(outputJsonPath: string): EmittedArtifactPaths {
9
+ if (!outputJsonPath.endsWith(JSON_EXTENSION)) {
10
+ throw new Error('Contract output path must end with .json');
11
+ }
12
+
13
+ return {
14
+ jsonPath: outputJsonPath,
15
+ dtsPath: `${outputJsonPath.slice(0, -JSON_EXTENSION.length)}.d.ts`,
16
+ };
17
+ }
package/src/emit-types.ts CHANGED
@@ -14,6 +14,10 @@ export interface EmitStackInput {
14
14
  readonly codecLookup?: CodecLookup;
15
15
  }
16
16
 
17
+ export interface EmitOptions {
18
+ readonly outputJsonPath?: string;
19
+ }
20
+
17
21
  export interface EmitResult {
18
22
  readonly contractJson: string;
19
23
  readonly contractDts: string;
package/src/emit.ts CHANGED
@@ -3,7 +3,8 @@ import type { Contract } from '@prisma-next/contract/types';
3
3
  import type { EmissionSpi } from '@prisma-next/framework-components/emission';
4
4
  import { ifDefined } from '@prisma-next/utils/defined';
5
5
  import { format } from 'prettier';
6
- import type { EmitResult, EmitStackInput } from './emit-types';
6
+ import { getEmittedArtifactPaths } from './artifact-paths';
7
+ import type { EmitOptions, EmitResult, EmitStackInput } from './emit-types';
7
8
  import { generateContractDts } from './generate-contract-dts';
8
9
 
9
10
  const SCHEMA_VERSION = '1';
@@ -12,7 +13,12 @@ export async function emit(
12
13
  contract: Contract,
13
14
  stack: EmitStackInput,
14
15
  targetFamily: EmissionSpi,
16
+ options?: EmitOptions,
15
17
  ): Promise<EmitResult> {
18
+ if (options?.outputJsonPath !== undefined) {
19
+ getEmittedArtifactPaths(options.outputJsonPath);
20
+ }
21
+
16
22
  const { codecTypeImports, operationTypeImports, queryOperationTypeImports } = stack;
17
23
 
18
24
  const { storageHash } = contract.storage;
@@ -1,3 +1,5 @@
1
+ export type { EmittedArtifactPaths } from '../artifact-paths';
2
+ export { getEmittedArtifactPaths } from '../artifact-paths';
1
3
  export {
2
4
  deduplicateImports,
3
5
  generateCodecTypeIntersection,
@@ -2,13 +2,44 @@ import type { TypesImportSpec } from '@prisma-next/framework-components/emission
2
2
  import { timeouts } from '@prisma-next/test-utils';
3
3
  import { describe, expect, it } from 'vitest';
4
4
  import type { EmitStackInput } from '../src/exports';
5
- import { emit } from '../src/exports';
5
+ import { emit, getEmittedArtifactPaths } from '../src/exports';
6
6
  import { createMockSpi } from './mock-spi';
7
7
  import { createTestContract } from './utils';
8
8
 
9
9
  const mockSqlHook = createMockSpi();
10
10
 
11
11
  describe('emitter', () => {
12
+ it('derives colocated artifact paths from contract.json output', () => {
13
+ expect(getEmittedArtifactPaths('/abs/contract.json')).toEqual({
14
+ jsonPath: '/abs/contract.json',
15
+ dtsPath: '/abs/contract.d.ts',
16
+ });
17
+ });
18
+
19
+ it('rejects non-json output paths when deriving artifact paths', () => {
20
+ expect(() => getEmittedArtifactPaths('/abs/contract.ts')).toThrow(
21
+ 'Contract output path must end with .json',
22
+ );
23
+ });
24
+
25
+ it(
26
+ 'rejects non-json output paths when emit receives an output path',
27
+ async () => {
28
+ const ir = createTestContract();
29
+ const options: EmitStackInput = {
30
+ codecTypeImports: [],
31
+ operationTypeImports: [],
32
+ };
33
+
34
+ await expect(
35
+ emit(ir, options, mockSqlHook, {
36
+ outputJsonPath: '/abs/contract.ts',
37
+ }),
38
+ ).rejects.toThrow('Contract output path must end with .json');
39
+ },
40
+ timeouts.typeScriptCompilation,
41
+ );
42
+
12
43
  it(
13
44
  'emits contract.json and contract.d.ts',
14
45
  async () => {
@@ -182,23 +213,27 @@ describe('emitter', () => {
182
213
  expect(result.contractDts).toBeDefined();
183
214
  });
184
215
 
185
- it('omits sources from emitted contract artifact', async () => {
186
- const ir = createTestContract({
187
- sources: {
188
- schema: { sourceId: 'schema.prisma' },
189
- },
190
- });
216
+ it(
217
+ 'omits sources from emitted contract artifact',
218
+ async () => {
219
+ const ir = createTestContract({
220
+ sources: {
221
+ schema: { sourceId: 'schema.prisma' },
222
+ },
223
+ });
191
224
 
192
- const options: EmitStackInput = {
193
- codecTypeImports: [],
194
- operationTypeImports: [],
195
- extensionIds: [],
196
- };
225
+ const options: EmitStackInput = {
226
+ codecTypeImports: [],
227
+ operationTypeImports: [],
228
+ extensionIds: [],
229
+ };
197
230
 
198
- const result = await emit(ir, options, mockSqlHook);
199
- const contractJson = JSON.parse(result.contractJson) as Record<string, unknown>;
200
- expect(contractJson).not.toHaveProperty('sources');
201
- });
231
+ const result = await emit(ir, options, mockSqlHook);
232
+ const contractJson = JSON.parse(result.contractJson) as Record<string, unknown>;
233
+ expect(contractJson).not.toHaveProperty('sources');
234
+ },
235
+ timeouts.typeScriptCompilation,
236
+ );
202
237
 
203
238
  it('accepts meta keys when family validation allows them', async () => {
204
239
  const ir = createTestContract({