@prisma-next/cli 0.3.0-dev.6 → 0.3.0-dev.64

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.
Files changed (180) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +314 -80
  3. package/dist/cli-errors-JlPTsazx.mjs +3 -0
  4. package/dist/cli.d.mts +1 -0
  5. package/dist/cli.js +1 -2376
  6. package/dist/cli.mjs +203 -0
  7. package/dist/cli.mjs.map +1 -0
  8. package/dist/client-PimzSD1f.mjs +981 -0
  9. package/dist/client-PimzSD1f.mjs.map +1 -0
  10. package/dist/commands/contract-emit.d.mts +7 -0
  11. package/dist/commands/contract-emit.d.mts.map +1 -0
  12. package/dist/commands/contract-emit.mjs +151 -0
  13. package/dist/commands/contract-emit.mjs.map +1 -0
  14. package/dist/commands/db-init.d.mts +7 -0
  15. package/dist/commands/db-init.d.mts.map +1 -0
  16. package/dist/commands/db-init.mjs +134 -0
  17. package/dist/commands/db-init.mjs.map +1 -0
  18. package/dist/commands/db-introspect.d.mts +7 -0
  19. package/dist/commands/db-introspect.d.mts.map +1 -0
  20. package/dist/commands/db-introspect.mjs +118 -0
  21. package/dist/commands/db-introspect.mjs.map +1 -0
  22. package/dist/commands/db-schema-verify.d.mts +7 -0
  23. package/dist/commands/db-schema-verify.d.mts.map +1 -0
  24. package/dist/commands/db-schema-verify.mjs +120 -0
  25. package/dist/commands/db-schema-verify.mjs.map +1 -0
  26. package/dist/commands/db-sign.d.mts +7 -0
  27. package/dist/commands/db-sign.d.mts.map +1 -0
  28. package/dist/commands/db-sign.mjs +142 -0
  29. package/dist/commands/db-sign.mjs.map +1 -0
  30. package/dist/commands/db-update.d.mts +7 -0
  31. package/dist/commands/db-update.d.mts.map +1 -0
  32. package/dist/commands/db-update.mjs +123 -0
  33. package/dist/commands/db-update.mjs.map +1 -0
  34. package/dist/commands/db-verify.d.mts +7 -0
  35. package/dist/commands/db-verify.d.mts.map +1 -0
  36. package/dist/commands/db-verify.mjs +133 -0
  37. package/dist/commands/db-verify.mjs.map +1 -0
  38. package/dist/commands/migration-apply.d.mts +23 -0
  39. package/dist/commands/migration-apply.d.mts.map +1 -0
  40. package/dist/commands/migration-apply.mjs +250 -0
  41. package/dist/commands/migration-apply.mjs.map +1 -0
  42. package/dist/commands/migration-plan.d.mts +25 -0
  43. package/dist/commands/migration-plan.d.mts.map +1 -0
  44. package/dist/commands/migration-plan.mjs +266 -0
  45. package/dist/commands/migration-plan.mjs.map +1 -0
  46. package/dist/commands/migration-show.d.mts +28 -0
  47. package/dist/commands/migration-show.d.mts.map +1 -0
  48. package/dist/commands/migration-show.mjs +138 -0
  49. package/dist/commands/migration-show.mjs.map +1 -0
  50. package/dist/commands/migration-status.d.mts +35 -0
  51. package/dist/commands/migration-status.d.mts.map +1 -0
  52. package/dist/commands/migration-status.mjs +260 -0
  53. package/dist/commands/migration-status.mjs.map +1 -0
  54. package/dist/commands/migration-verify.d.mts +16 -0
  55. package/dist/commands/migration-verify.d.mts.map +1 -0
  56. package/dist/commands/migration-verify.mjs +86 -0
  57. package/dist/commands/migration-verify.mjs.map +1 -0
  58. package/dist/config-loader-PPf4CtDj.mjs +43 -0
  59. package/dist/config-loader-PPf4CtDj.mjs.map +1 -0
  60. package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
  61. package/dist/config-loader.d.mts.map +1 -0
  62. package/dist/config-loader.mjs +3 -0
  63. package/dist/exports/config-types.d.mts +2 -0
  64. package/dist/exports/config-types.mjs +3 -0
  65. package/dist/exports/control-api.d.mts +621 -0
  66. package/dist/exports/control-api.d.mts.map +1 -0
  67. package/dist/exports/control-api.mjs +98 -0
  68. package/dist/exports/control-api.mjs.map +1 -0
  69. package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +10 -5
  70. package/dist/exports/index.d.mts.map +1 -0
  71. package/dist/exports/index.mjs +135 -0
  72. package/dist/exports/index.mjs.map +1 -0
  73. package/dist/extract-sql-ddl-BmlKvk4o.mjs +26 -0
  74. package/dist/extract-sql-ddl-BmlKvk4o.mjs.map +1 -0
  75. package/dist/framework-components-CjV_jD8f.mjs +59 -0
  76. package/dist/framework-components-CjV_jD8f.mjs.map +1 -0
  77. package/dist/migration-command-scaffold-DfY_F3ev.mjs +97 -0
  78. package/dist/migration-command-scaffold-DfY_F3ev.mjs.map +1 -0
  79. package/dist/progress-adapter-DENrzF6I.mjs +49 -0
  80. package/dist/progress-adapter-DENrzF6I.mjs.map +1 -0
  81. package/dist/result-handler-iA9JtUC7.mjs +1186 -0
  82. package/dist/result-handler-iA9JtUC7.mjs.map +1 -0
  83. package/package.json +75 -38
  84. package/src/cli.ts +43 -0
  85. package/src/commands/contract-emit.ts +221 -111
  86. package/src/commands/db-init.ts +217 -426
  87. package/src/commands/db-introspect.ts +148 -185
  88. package/src/commands/db-schema-verify.ts +162 -149
  89. package/src/commands/db-sign.ts +215 -202
  90. package/src/commands/db-update.ts +220 -0
  91. package/src/commands/db-verify.ts +193 -156
  92. package/src/commands/migration-apply.ts +431 -0
  93. package/src/commands/migration-plan.ts +446 -0
  94. package/src/commands/migration-show.ts +255 -0
  95. package/src/commands/migration-status.ts +436 -0
  96. package/src/commands/migration-verify.ts +151 -0
  97. package/src/config-loader.ts +13 -3
  98. package/src/control-api/client.ts +605 -0
  99. package/src/control-api/errors.ts +9 -0
  100. package/src/control-api/operations/contract-emit.ts +161 -0
  101. package/src/control-api/operations/db-init.ts +286 -0
  102. package/src/control-api/operations/db-update.ts +221 -0
  103. package/src/control-api/operations/extract-sql-ddl.ts +47 -0
  104. package/src/control-api/operations/migration-apply.ts +195 -0
  105. package/src/control-api/operations/migration-helpers.ts +49 -0
  106. package/src/control-api/types.ts +687 -0
  107. package/src/exports/config-types.ts +3 -3
  108. package/src/exports/control-api.ts +53 -0
  109. package/src/load-ts-contract.ts +16 -11
  110. package/src/utils/cli-errors.ts +3 -1
  111. package/src/utils/command-helpers.ts +92 -3
  112. package/src/utils/framework-components.ts +11 -30
  113. package/src/utils/migration-command-scaffold.ts +190 -0
  114. package/src/utils/output.ts +363 -25
  115. package/src/utils/progress-adapter.ts +86 -0
  116. package/dist/chunk-464LNZCE.js +0 -134
  117. package/dist/chunk-464LNZCE.js.map +0 -1
  118. package/dist/chunk-BZMBKEEQ.js +0 -997
  119. package/dist/chunk-BZMBKEEQ.js.map +0 -1
  120. package/dist/chunk-HWYQOCAJ.js +0 -47
  121. package/dist/chunk-HWYQOCAJ.js.map +0 -1
  122. package/dist/chunk-ZKYEJROM.js +0 -94
  123. package/dist/chunk-ZKYEJROM.js.map +0 -1
  124. package/dist/cli.d.ts +0 -2
  125. package/dist/cli.d.ts.map +0 -1
  126. package/dist/cli.js.map +0 -1
  127. package/dist/commands/contract-emit.d.ts +0 -3
  128. package/dist/commands/contract-emit.d.ts.map +0 -1
  129. package/dist/commands/contract-emit.js +0 -9
  130. package/dist/commands/contract-emit.js.map +0 -1
  131. package/dist/commands/db-init.d.ts +0 -3
  132. package/dist/commands/db-init.d.ts.map +0 -1
  133. package/dist/commands/db-init.js +0 -341
  134. package/dist/commands/db-init.js.map +0 -1
  135. package/dist/commands/db-introspect.d.ts +0 -3
  136. package/dist/commands/db-introspect.d.ts.map +0 -1
  137. package/dist/commands/db-introspect.js +0 -190
  138. package/dist/commands/db-introspect.js.map +0 -1
  139. package/dist/commands/db-schema-verify.d.ts +0 -3
  140. package/dist/commands/db-schema-verify.d.ts.map +0 -1
  141. package/dist/commands/db-schema-verify.js +0 -164
  142. package/dist/commands/db-schema-verify.js.map +0 -1
  143. package/dist/commands/db-sign.d.ts +0 -3
  144. package/dist/commands/db-sign.d.ts.map +0 -1
  145. package/dist/commands/db-sign.js +0 -199
  146. package/dist/commands/db-sign.js.map +0 -1
  147. package/dist/commands/db-verify.d.ts +0 -3
  148. package/dist/commands/db-verify.d.ts.map +0 -1
  149. package/dist/commands/db-verify.js +0 -173
  150. package/dist/commands/db-verify.js.map +0 -1
  151. package/dist/config-loader.d.ts.map +0 -1
  152. package/dist/config-loader.js +0 -7
  153. package/dist/config-loader.js.map +0 -1
  154. package/dist/exports/config-types.d.ts +0 -3
  155. package/dist/exports/config-types.d.ts.map +0 -1
  156. package/dist/exports/config-types.js +0 -6
  157. package/dist/exports/config-types.js.map +0 -1
  158. package/dist/exports/index.d.ts +0 -4
  159. package/dist/exports/index.d.ts.map +0 -1
  160. package/dist/exports/index.js +0 -175
  161. package/dist/exports/index.js.map +0 -1
  162. package/dist/load-ts-contract.d.ts.map +0 -1
  163. package/dist/utils/action.d.ts +0 -16
  164. package/dist/utils/action.d.ts.map +0 -1
  165. package/dist/utils/cli-errors.d.ts +0 -7
  166. package/dist/utils/cli-errors.d.ts.map +0 -1
  167. package/dist/utils/command-helpers.d.ts +0 -12
  168. package/dist/utils/command-helpers.d.ts.map +0 -1
  169. package/dist/utils/framework-components.d.ts +0 -81
  170. package/dist/utils/framework-components.d.ts.map +0 -1
  171. package/dist/utils/global-flags.d.ts +0 -25
  172. package/dist/utils/global-flags.d.ts.map +0 -1
  173. package/dist/utils/output.d.ts +0 -142
  174. package/dist/utils/output.d.ts.map +0 -1
  175. package/dist/utils/result-handler.d.ts +0 -15
  176. package/dist/utils/result-handler.d.ts.map +0 -1
  177. package/dist/utils/spinner.d.ts +0 -29
  178. package/dist/utils/spinner.d.ts.map +0 -1
  179. package/src/utils/action.ts +0 -43
  180. package/src/utils/spinner.ts +0 -67
@@ -1,20 +1,29 @@
1
1
  import { mkdirSync, writeFileSync } from 'node:fs';
2
- import { dirname, relative, resolve } from 'node:path';
3
2
  import { errorContractConfigMissing } from '@prisma-next/core-control-plane/errors';
3
+ import { notOk, ok, type Result } from '@prisma-next/utils/result';
4
4
  import { Command } from 'commander';
5
+ import { dirname, isAbsolute, join, relative, resolve } from 'pathe';
5
6
  import { loadConfig } from '../config-loader';
6
- import { performAction } from '../utils/action';
7
+ import { createControlClient } from '../control-api/client';
8
+ import type { EmitFailure } from '../control-api/types';
9
+ import {
10
+ CliStructuredError,
11
+ errorContractValidationFailed,
12
+ errorRuntime,
13
+ errorUnexpected,
14
+ } from '../utils/cli-errors';
7
15
  import { setCommandDescriptions } from '../utils/command-helpers';
8
- import { parseGlobalFlags } from '../utils/global-flags';
16
+ import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
9
17
  import {
18
+ type EmitContractResult,
10
19
  formatCommandHelp,
11
20
  formatEmitJson,
12
21
  formatEmitOutput,
13
22
  formatStyledHeader,
14
23
  formatSuccessMessage,
15
24
  } from '../utils/output';
25
+ import { createProgressAdapter } from '../utils/progress-adapter';
16
26
  import { handleResult } from '../utils/result-handler';
17
- import { withSpinner } from '../utils/spinner';
18
27
 
19
28
  interface ContractEmitOptions {
20
29
  readonly config?: string;
@@ -30,11 +39,216 @@ interface ContractEmitOptions {
30
39
  readonly 'no-color'?: boolean;
31
40
  }
32
41
 
42
+ function mapDiagnosticsToIssues(
43
+ failure: EmitFailure,
44
+ ): ReadonlyArray<{ kind: string; message: string }> {
45
+ const diagnostics = failure.diagnostics?.diagnostics ?? [];
46
+ return diagnostics.map((diagnostic) => {
47
+ const location =
48
+ diagnostic.sourceId && diagnostic.span
49
+ ? ` (${diagnostic.sourceId}:${diagnostic.span.start.line}:${diagnostic.span.start.column})`
50
+ : diagnostic.sourceId
51
+ ? ` (${diagnostic.sourceId})`
52
+ : '';
53
+ return {
54
+ kind: diagnostic.code,
55
+ message: `${diagnostic.message}${location}`,
56
+ };
57
+ });
58
+ }
59
+
60
+ /**
61
+ * Maps an EmitFailure to a CliStructuredError for consistent error handling.
62
+ */
63
+ function mapEmitFailure(
64
+ failure: EmitFailure,
65
+ context?: { readonly configPath?: string },
66
+ ): CliStructuredError {
67
+ if (failure.code === 'CONTRACT_SOURCE_INVALID') {
68
+ const issues = mapDiagnosticsToIssues(failure);
69
+ return errorRuntime(failure.summary, {
70
+ why: failure.why ?? 'Contract source provider failed',
71
+ fix: 'Check your contract source provider in prisma-next.config.ts and ensure it returns Result<ContractIR, Diagnostics>',
72
+ ...(issues.length > 0 ? { meta: { issues } } : {}),
73
+ });
74
+ }
75
+
76
+ if (failure.code === 'CONTRACT_VALIDATION_FAILED') {
77
+ return errorContractValidationFailed(
78
+ failure.why ?? 'Contract validation failed while emitting',
79
+ context?.configPath ? { where: { path: context.configPath } } : undefined,
80
+ );
81
+ }
82
+
83
+ if (failure.code === 'EMIT_FAILED') {
84
+ return errorRuntime(failure.summary, {
85
+ why: failure.why ?? 'Failed to emit contract',
86
+ fix: 'Check your contract configuration and ensure the source is valid',
87
+ });
88
+ }
89
+
90
+ // Exhaustive check - TypeScript will error if a new code is added but not handled
91
+ const exhaustive: never = failure.code;
92
+ throw new Error(`Unhandled EmitFailure code: ${exhaustive}`);
93
+ }
94
+
95
+ /**
96
+ * Executes the contract emit command and returns a structured Result.
97
+ */
98
+ async function executeContractEmitCommand(
99
+ options: ContractEmitOptions,
100
+ flags: GlobalFlags,
101
+ startTime: number,
102
+ ): Promise<Result<EmitContractResult, CliStructuredError>> {
103
+ // Load config
104
+ let config: Awaited<ReturnType<typeof loadConfig>>;
105
+ try {
106
+ config = await loadConfig(options.config);
107
+ } catch (error) {
108
+ // Convert thrown CliStructuredError to Result
109
+ if (error instanceof CliStructuredError) {
110
+ return notOk(error);
111
+ }
112
+ return notOk(
113
+ errorUnexpected(error instanceof Error ? error.message : String(error), {
114
+ why: 'Failed to load config',
115
+ }),
116
+ );
117
+ }
118
+
119
+ const configPath = options.config
120
+ ? relative(process.cwd(), resolve(options.config))
121
+ : 'prisma-next.config.ts';
122
+
123
+ // Resolve contract from config
124
+ if (!config.contract) {
125
+ return notOk(
126
+ errorContractConfigMissing({
127
+ why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',
128
+ }),
129
+ );
130
+ }
131
+
132
+ // Contract config is already normalized by defineConfig() with defaults applied
133
+ const contractConfig = config.contract;
134
+
135
+ // Resolve artifact paths from config (already normalized by defineConfig() with defaults)
136
+ if (!contractConfig.output) {
137
+ return notOk(
138
+ errorContractConfigMissing({
139
+ why: 'Contract config must have output path. This should not happen if defineConfig() was used.',
140
+ }),
141
+ );
142
+ }
143
+ if (!contractConfig.output.endsWith('.json')) {
144
+ return notOk(
145
+ errorContractConfigMissing({
146
+ why: 'Contract config output path must end with .json (e.g., "src/prisma/contract.json")',
147
+ }),
148
+ );
149
+ }
150
+ const configDir = options.config ? dirname(resolve(options.config)) : process.cwd();
151
+ const outputJsonPath = isAbsolute(contractConfig.output)
152
+ ? contractConfig.output
153
+ : join(configDir, contractConfig.output);
154
+ // Colocate .d.ts with .json (contract.json → contract.d.ts)
155
+ const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;
156
+
157
+ // Output header (only for human-readable output)
158
+ if (flags.json !== 'object' && !flags.quiet) {
159
+ // Normalize config path for display (match contract path format - no ./ prefix)
160
+ // Convert absolute paths to relative paths for display
161
+ const contractPath = relative(process.cwd(), outputJsonPath);
162
+ const typesPath = relative(process.cwd(), outputDtsPath);
163
+ const header = formatStyledHeader({
164
+ command: 'contract emit',
165
+ description: 'Emit your contract artifacts',
166
+ url: 'https://pris.ly/contract-emit',
167
+ details: [
168
+ { label: 'config', value: configPath },
169
+ { label: 'contract', value: contractPath },
170
+ { label: 'types', value: typesPath },
171
+ ],
172
+ flags,
173
+ });
174
+ console.log(header);
175
+ }
176
+
177
+ // Create control client (no driver needed for emit)
178
+ const client = createControlClient({
179
+ family: config.family,
180
+ target: config.target,
181
+ adapter: config.adapter,
182
+ extensionPacks: config.extensionPacks ?? [],
183
+ });
184
+
185
+ // Create progress adapter
186
+ const onProgress = createProgressAdapter({ flags });
187
+
188
+ try {
189
+ // Call emit with progress callback
190
+ const result = await client.emit({
191
+ contractConfig: {
192
+ sourceProvider: contractConfig.source,
193
+ output: outputJsonPath,
194
+ },
195
+ onProgress,
196
+ });
197
+
198
+ // Handle failures by mapping to CLI structured error
199
+ if (!result.ok) {
200
+ return notOk(mapEmitFailure(result.failure, { configPath }));
201
+ }
202
+
203
+ // Create directories if needed
204
+ mkdirSync(dirname(outputJsonPath), { recursive: true });
205
+ mkdirSync(dirname(outputDtsPath), { recursive: true });
206
+
207
+ // Write the results to files
208
+ writeFileSync(outputJsonPath, result.value.contractJson, 'utf-8');
209
+ writeFileSync(outputDtsPath, result.value.contractDts, 'utf-8');
210
+
211
+ // Add blank line after all async operations if spinners were shown
212
+ if (!flags.quiet && flags.json !== 'object' && process.stdout.isTTY) {
213
+ console.log('');
214
+ }
215
+
216
+ // Convert success result to CLI output format
217
+ const emitResult: EmitContractResult = {
218
+ storageHash: result.value.storageHash,
219
+ ...(result.value.executionHash ? { executionHash: result.value.executionHash } : {}),
220
+ profileHash: result.value.profileHash,
221
+ outDir: dirname(outputJsonPath),
222
+ files: {
223
+ json: outputJsonPath,
224
+ dts: outputDtsPath,
225
+ },
226
+ timings: { total: Date.now() - startTime },
227
+ };
228
+
229
+ return ok(emitResult);
230
+ } catch (error) {
231
+ // Use static type guard to work across module boundaries
232
+ if (CliStructuredError.is(error)) {
233
+ return notOk(error);
234
+ }
235
+
236
+ // Wrap unexpected errors
237
+ return notOk(
238
+ errorUnexpected('Unexpected error during contract emit', {
239
+ why: error instanceof Error ? error.message : String(error),
240
+ }),
241
+ );
242
+ } finally {
243
+ await client.close();
244
+ }
245
+ }
246
+
33
247
  export function createContractEmitCommand(): Command {
34
248
  const command = new Command('emit');
35
249
  setCommandDescriptions(
36
250
  command,
37
- 'Write your contract to JSON and sign it',
251
+ 'Emit your contract artifacts',
38
252
  'Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\n' +
39
253
  'contract.d.ts. The contract.json contains the canonical contract structure, and\n' +
40
254
  'contract.d.ts provides TypeScript types for type-safe query building.',
@@ -56,113 +270,9 @@ export function createContractEmitCommand(): Command {
56
270
  .option('--no-color', 'Disable color output')
57
271
  .action(async (options: ContractEmitOptions) => {
58
272
  const flags = parseGlobalFlags(options);
273
+ const startTime = Date.now();
59
274
 
60
- const result = await performAction(async () => {
61
- // Load config
62
- const config = await loadConfig(options.config);
63
-
64
- // Resolve contract from config
65
- if (!config.contract) {
66
- throw errorContractConfigMissing({
67
- why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ..., types: ... }',
68
- });
69
- }
70
-
71
- // Contract config is already normalized by defineConfig() with defaults applied
72
- const contractConfig = config.contract;
73
-
74
- // Resolve artifact paths from config (already normalized by defineConfig() with defaults)
75
- if (!contractConfig.output || !contractConfig.types) {
76
- throw errorContractConfigMissing({
77
- why: 'Contract config must have output and types paths. This should not happen if defineConfig() was used.',
78
- });
79
- }
80
- const outputJsonPath = resolve(contractConfig.output);
81
- const outputDtsPath = resolve(contractConfig.types);
82
-
83
- // Output header (only for human-readable output)
84
- if (flags.json !== 'object' && !flags.quiet) {
85
- // Normalize config path for display (match contract path format - no ./ prefix)
86
- const configPath = options.config
87
- ? relative(process.cwd(), resolve(options.config))
88
- : 'prisma-next.config.ts';
89
- // Convert absolute paths to relative paths for display
90
- const contractPath = relative(process.cwd(), outputJsonPath);
91
- const typesPath = relative(process.cwd(), outputDtsPath);
92
- const header = formatStyledHeader({
93
- command: 'contract emit',
94
- description: 'Write your contract to JSON and sign it',
95
- url: 'https://pris.ly/contract-emit',
96
- details: [
97
- { label: 'config', value: configPath },
98
- { label: 'contract', value: contractPath },
99
- { label: 'types', value: typesPath },
100
- ],
101
- flags,
102
- });
103
- console.log(header);
104
- }
105
-
106
- // Create family instance (assembles operation registry, type imports, extension IDs)
107
- // Note: emit command doesn't need driver, but ControlFamilyDescriptor.create() requires it
108
- // We'll need to provide a minimal driver descriptor or make driver optional for emit
109
- // For now, we'll require driver to be present in config even for emit
110
- if (!config.driver) {
111
- throw errorContractConfigMissing({
112
- why: 'Config.driver is required. Even though emit does not use the driver, it is required by ControlFamilyDescriptor.create()',
113
- });
114
- }
115
- const familyInstance = config.family.create({
116
- target: config.target,
117
- adapter: config.adapter,
118
- driver: config.driver,
119
- extensionPacks: config.extensionPacks ?? [],
120
- });
121
-
122
- // Resolve contract source from config (user's config handles loading)
123
- let contractRaw: unknown;
124
- if (typeof contractConfig.source === 'function') {
125
- contractRaw = await contractConfig.source();
126
- } else {
127
- contractRaw = contractConfig.source;
128
- }
129
-
130
- // Call emitContract on family instance (handles stripping mappings and validation internally)
131
- const emitResult = await withSpinner(
132
- () => familyInstance.emitContract({ contractIR: contractRaw }),
133
- {
134
- message: 'Emitting contract...',
135
- flags,
136
- },
137
- );
138
-
139
- // Create directories if needed
140
- mkdirSync(dirname(outputJsonPath), { recursive: true });
141
- mkdirSync(dirname(outputDtsPath), { recursive: true });
142
-
143
- // Write the results to files
144
- writeFileSync(outputJsonPath, emitResult.contractJson, 'utf-8');
145
- writeFileSync(outputDtsPath, emitResult.contractDts, 'utf-8');
146
-
147
- // Add blank line after all async operations if spinners were shown
148
- if (!flags.quiet && flags.json !== 'object' && process.stdout.isTTY) {
149
- console.log('');
150
- }
151
-
152
- // Return result with file paths for output formatting
153
- return {
154
- coreHash: emitResult.coreHash,
155
- profileHash: emitResult.profileHash,
156
- outDir: dirname(outputJsonPath),
157
- files: {
158
- json: outputJsonPath,
159
- dts: outputDtsPath,
160
- },
161
- timings: {
162
- total: 0, // Timing is handled by emitContract internally if needed
163
- },
164
- };
165
- });
275
+ const result = await executeContractEmitCommand(options, flags, startTime);
166
276
 
167
277
  // Handle result - formats output and returns exit code
168
278
  const exitCode = handleResult(result, flags, (emitResult) => {