@prisma-next/cli 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -9
- package/dist/cli.mjs +259 -12
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-oXO2WCPD.mjs → client-KgJorIvG.mjs} +72 -60
- package/dist/client-KgJorIvG.mjs.map +1 -0
- package/dist/{command-helpers-BSb0tRC8.mjs → command-helpers-Bbw1GbwL.mjs} +646 -46
- package/dist/command-helpers-Bbw1GbwL.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +32 -7
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +3 -4
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +12 -10
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +41 -11
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +6 -2
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +75 -40
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +4 -3
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +1 -280
- package/dist/commands/migration-graph.d.mts +13 -2
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +2 -137
- package/dist/commands/migration-list.d.mts +64 -4
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +143 -56
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts +10 -1
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +10 -15
- package/dist/commands/migration-log.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +32 -38
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +3 -2
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +4 -55
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +61 -153
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +12 -49
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +85 -81
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +38 -10
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/config-loader-B6sJjXTv.mjs.map +1 -1
- package/dist/config-loader.d.mts.map +1 -1
- package/dist/contract-at-errors-BxP-TOMl.mjs +42 -0
- package/dist/contract-at-errors-BxP-TOMl.mjs.map +1 -0
- package/dist/{contract-emit-bcrpT-wD.mjs → contract-emit-D-4jrNve.mjs} +25 -10
- package/dist/contract-emit-D-4jrNve.mjs.map +1 -0
- package/dist/{contract-emit-r4y8Zhf1.mjs → contract-emit-DxcGl4Uq.mjs} +19 -14
- package/dist/contract-emit-DxcGl4Uq.mjs.map +1 -0
- package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-a0V5Y_mL.mjs} +4 -25
- package/dist/contract-enrichment-a0V5Y_mL.mjs.map +1 -0
- package/dist/{contract-infer-BmySmqVT.mjs → contract-infer-D8uEbJuu.mjs} +4 -5
- package/dist/{contract-infer-BmySmqVT.mjs.map → contract-infer-D8uEbJuu.mjs.map} +1 -1
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs +247 -0
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs.map +1 -0
- package/dist/{db-verify-BClPs3ph.mjs → db-verify-v_vUKXTU.mjs} +5 -7
- package/dist/{db-verify-BClPs3ph.mjs.map → db-verify-v_vUKXTU.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -3
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/extension-pack-inputs-IDvjRCi3.mjs +62 -0
- package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +1 -0
- package/dist/{framework-components-65gOHkHB.mjs → framework-components-fYXjz_in.mjs} +2 -2
- package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-fYXjz_in.mjs.map} +1 -1
- package/dist/global-flags-DEHjV8_s.d.mts +34 -0
- package/dist/global-flags-DEHjV8_s.d.mts.map +1 -0
- package/dist/{graph-render-DJVv0_uf.mjs → graph-render-rFAqZujX.mjs} +2 -2
- package/dist/{graph-render-DJVv0_uf.mjs.map → graph-render-rFAqZujX.mjs.map} +1 -1
- package/dist/{init-BCJZPWE1.mjs → init-Cv9UzWL5.mjs} +20 -269
- package/dist/init-Cv9UzWL5.mjs.map +1 -0
- package/dist/{inspect-live-schema-DSRbFoOL.mjs → inspect-live-schema-C6ohV_oQ.mjs} +4 -5
- package/dist/{inspect-live-schema-DSRbFoOL.mjs.map → inspect-live-schema-C6ohV_oQ.mjs.map} +1 -1
- package/dist/migration-check-BiBJoYYW.mjs +341 -0
- package/dist/migration-check-BiBJoYYW.mjs.map +1 -0
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +4 -4
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-Bzd9La5c.mjs → migration-command-scaffold-CjvwO6at.mjs} +4 -5
- package/dist/{migration-command-scaffold-Bzd9La5c.mjs.map → migration-command-scaffold-CjvwO6at.mjs.map} +1 -1
- package/dist/migration-graph-D7DVUElV.mjs +1232 -0
- package/dist/migration-graph-D7DVUElV.mjs.map +1 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs +399 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +1 -0
- package/dist/{migration-plan-CFwqw3Gk.mjs → migration-plan-9DJ7q7_z.mjs} +372 -133
- package/dist/migration-plan-9DJ7q7_z.mjs.map +1 -0
- package/dist/{migration-types-BXWvz12q.d.mts → migration-types-D2FW63pr.d.mts} +1 -1
- package/dist/{migration-types-BXWvz12q.d.mts.map → migration-types-D2FW63pr.d.mts.map} +1 -1
- package/dist/{migrations-CwZMa1Ck.mjs → migrations-Cv2jxNNK.mjs} +12 -13
- package/dist/migrations-Cv2jxNNK.mjs.map +1 -0
- package/dist/{output-BlsrGMEF.mjs → output-B60Gw5fu.mjs} +1 -1
- package/dist/{output-BlsrGMEF.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-C644QK8l.mjs} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-C644QK8l.mjs.map} +1 -1
- package/dist/ref-advancement-DUZqsue6.mjs +50 -0
- package/dist/ref-advancement-DUZqsue6.mjs.map +1 -0
- package/dist/terminal-ui-5Y6mrg93.d.mts +133 -0
- package/dist/terminal-ui-5Y6mrg93.d.mts.map +1 -0
- package/dist/{types--CqjMdk0.d.mts → types-Dt_SfqFm.d.mts} +28 -28
- package/dist/types-Dt_SfqFm.d.mts.map +1 -0
- package/dist/{verify-Bom75OYI.mjs → verify-DCA9Sldu.mjs} +2 -2
- package/dist/{verify-Bom75OYI.mjs.map → verify-DCA9Sldu.mjs.map} +1 -1
- package/package.json +35 -24
- package/src/commands/contract-emit.ts +19 -7
- package/src/commands/contract-infer.ts +1 -1
- package/src/commands/db-init.ts +48 -2
- package/src/commands/db-sign.ts +9 -5
- package/src/commands/db-update.ts +54 -8
- package/src/commands/init/hygiene-gitattributes.ts +2 -2
- package/src/commands/init/index.ts +2 -1
- package/src/commands/init/templates/code-templates.ts +4 -2
- package/src/commands/init/templates/env.ts +13 -14
- package/src/commands/migrate.ts +125 -44
- package/src/commands/migration-check.ts +43 -83
- package/src/commands/migration-graph.ts +75 -60
- package/src/commands/migration-list.ts +220 -74
- package/src/commands/migration-log.ts +8 -14
- package/src/commands/migration-new.ts +44 -48
- package/src/commands/migration-plan.ts +412 -197
- package/src/commands/migration-show.ts +65 -284
- package/src/commands/migration-status.ts +127 -124
- package/src/commands/ref.ts +53 -8
- package/src/control-api/client.ts +0 -1
- package/src/control-api/contract-enrichment.ts +6 -42
- package/src/control-api/operations/{apply-aggregate.ts → apply.ts} +44 -75
- package/src/control-api/operations/contract-emit.ts +14 -6
- package/src/control-api/operations/{db-apply-aggregate.ts → db-apply.ts} +19 -19
- package/src/control-api/operations/db-init.ts +4 -4
- package/src/control-api/operations/db-update.ts +4 -4
- package/src/control-api/operations/db-verify.ts +15 -11
- package/src/control-api/operations/migration-apply.ts +56 -47
- package/src/control-api/types.ts +26 -27
- package/src/migration-cli.ts +4 -4
- package/src/utils/cli-errors.ts +234 -0
- package/src/utils/command-helpers.ts +9 -24
- package/src/utils/contract-at-errors.ts +96 -0
- package/src/utils/contract-space-aggregate-loader.ts +336 -117
- package/src/utils/formatters/migration-graph-layout.ts +1119 -0
- package/src/utils/formatters/migration-graph-rows.ts +336 -0
- package/src/utils/formatters/migration-graph-tree-render.ts +459 -0
- package/src/utils/formatters/migration-list-data-column.ts +115 -0
- package/src/utils/formatters/migration-list-graph-topology.ts +368 -0
- package/src/utils/formatters/migration-list-render.ts +191 -0
- package/src/utils/formatters/migration-list-styler.ts +63 -0
- package/src/utils/formatters/migration-list-types.ts +21 -0
- package/src/utils/formatters/migrations.ts +37 -46
- package/src/utils/glyph-mode.ts +22 -0
- package/src/utils/integrity-violation-to-check-failure.ts +130 -0
- package/src/utils/plan-resolution.ts +258 -0
- package/src/utils/ref-advancement.ts +68 -0
- package/src/utils/terminal-ui.ts +42 -1
- package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
- package/dist/cli-errors-Djtz98Vm.mjs +0 -71
- package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
- package/dist/client-oXO2WCPD.mjs.map +0 -1
- package/dist/command-helpers-BSb0tRC8.mjs.map +0 -1
- package/dist/commands/migration-check.mjs.map +0 -1
- package/dist/commands/migration-graph.mjs.map +0 -1
- package/dist/contract-emit-bcrpT-wD.mjs.map +0 -1
- package/dist/contract-emit-r4y8Zhf1.mjs.map +0 -1
- package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs +0 -160
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs.map +0 -1
- package/dist/global-flags-CdE7M0d9.d.mts +0 -15
- package/dist/global-flags-CdE7M0d9.d.mts.map +0 -1
- package/dist/init-BCJZPWE1.mjs.map +0 -1
- package/dist/migration-plan-CFwqw3Gk.mjs.map +0 -1
- package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
- package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
- package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
- package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
- package/dist/types--CqjMdk0.d.mts.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OperationPreview } from '@prisma-next/framework-components/control';
|
|
2
2
|
import { cyan, green, yellow } from 'colorette';
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { PerSpaceExecutionEntry } from '../../control-api/types';
|
|
5
5
|
import type { GlobalFlags } from '../global-flags';
|
|
6
6
|
import { createColorFormatter, formatDim, isVerbose } from './helpers';
|
|
7
7
|
|
|
@@ -79,9 +79,11 @@ export interface MigrationCommandResult {
|
|
|
79
79
|
* (extensions alphabetically, then app). Surfaces per-space markers
|
|
80
80
|
* and the ops grouped by space, so the CLI summary can name which
|
|
81
81
|
* space each op and marker belongs to instead of flattening them
|
|
82
|
-
* into a single ambiguous list. See {@link
|
|
82
|
+
* into a single ambiguous list. See {@link PerSpaceExecutionEntry}.
|
|
83
83
|
*/
|
|
84
|
-
readonly perSpace?: ReadonlyArray<
|
|
84
|
+
readonly perSpace?: ReadonlyArray<PerSpaceExecutionEntry>;
|
|
85
|
+
readonly advancedRef?: { readonly name: string; readonly hash: string } | null;
|
|
86
|
+
readonly plannedAdvanceRef?: { readonly name: string; readonly hash: string } | null;
|
|
85
87
|
readonly summary: string;
|
|
86
88
|
readonly timings: {
|
|
87
89
|
readonly total: number;
|
|
@@ -99,7 +101,7 @@ export interface MigrationCommandResult {
|
|
|
99
101
|
* entirely (no marker has been written yet).
|
|
100
102
|
*/
|
|
101
103
|
export function formatPerSpaceBlock(
|
|
102
|
-
perSpace: ReadonlyArray<
|
|
104
|
+
perSpace: ReadonlyArray<PerSpaceExecutionEntry>,
|
|
103
105
|
mode: 'plan' | 'apply',
|
|
104
106
|
useColor: boolean,
|
|
105
107
|
): readonly string[] {
|
|
@@ -180,7 +182,7 @@ export function formatMigrationPlanOutput(
|
|
|
180
182
|
);
|
|
181
183
|
}
|
|
182
184
|
} else if (result.plan?.operations && result.plan.operations.length > 0) {
|
|
183
|
-
//
|
|
185
|
+
// App-only / no-aggregate-breakdown fallback. Same flat tree
|
|
184
186
|
// we've always rendered.
|
|
185
187
|
lines.push(`${formatDimText('│')}`);
|
|
186
188
|
for (let i = 0; i < result.plan.operations.length; i++) {
|
|
@@ -208,6 +210,15 @@ export function formatMigrationPlanOutput(
|
|
|
208
210
|
lines.push(`${formatDimText(`Destination hash: ${result.plan.destination.storageHash}`)}`);
|
|
209
211
|
}
|
|
210
212
|
|
|
213
|
+
if (result.plannedAdvanceRef) {
|
|
214
|
+
lines.push('');
|
|
215
|
+
lines.push(
|
|
216
|
+
formatDimText(
|
|
217
|
+
`Would advance ref "${result.plannedAdvanceRef.name}" → ${result.plannedAdvanceRef.hash}`,
|
|
218
|
+
),
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
211
222
|
// Statement preview (any family that implements OperationPreviewCapable)
|
|
212
223
|
const preview = result.plan?.preview;
|
|
213
224
|
if (preview) {
|
|
@@ -256,10 +267,11 @@ export interface MigrationApplyCommandOutputResult {
|
|
|
256
267
|
* alphabetically, then app). Always present for the aggregate-walking
|
|
257
268
|
* `migrate` command.
|
|
258
269
|
*/
|
|
259
|
-
readonly perSpace: readonly
|
|
270
|
+
readonly perSpace: readonly PerSpaceExecutionEntry[];
|
|
260
271
|
readonly timings?: {
|
|
261
272
|
readonly total: number;
|
|
262
273
|
};
|
|
274
|
+
readonly advancedRef?: { readonly name: string; readonly hash: string } | null;
|
|
263
275
|
}
|
|
264
276
|
|
|
265
277
|
export function formatMigrationApplyCommandOutput(
|
|
@@ -284,6 +296,13 @@ export function formatMigrationApplyCommandOutput(
|
|
|
284
296
|
}
|
|
285
297
|
}
|
|
286
298
|
|
|
299
|
+
if (result.advancedRef) {
|
|
300
|
+
lines.push('');
|
|
301
|
+
lines.push(
|
|
302
|
+
formatDimText(`Advanced ref "${result.advancedRef.name}" → ${result.advancedRef.hash}`),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
287
306
|
lines.push('');
|
|
288
307
|
lines.push(formatDimText('Next: prisma-next migration status'));
|
|
289
308
|
|
|
@@ -295,9 +314,7 @@ export function formatMigrationApplyCommandOutput(
|
|
|
295
314
|
return lines.join('\n');
|
|
296
315
|
}
|
|
297
316
|
|
|
298
|
-
interface
|
|
299
|
-
readonly kind: 'present';
|
|
300
|
-
readonly spaceId: string;
|
|
317
|
+
interface MigrationShowPresent {
|
|
301
318
|
readonly dirName: string;
|
|
302
319
|
readonly dirPath: string;
|
|
303
320
|
readonly from: string | null;
|
|
@@ -313,22 +330,11 @@ interface MigrationShowSpacePresent {
|
|
|
313
330
|
readonly summary: string;
|
|
314
331
|
}
|
|
315
332
|
|
|
316
|
-
interface MigrationShowSpaceMissing {
|
|
317
|
-
readonly kind: 'missing';
|
|
318
|
-
readonly spaceId: string;
|
|
319
|
-
readonly summary: string;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
type MigrationShowSpaceResult = MigrationShowSpacePresent | MigrationShowSpaceMissing;
|
|
323
|
-
|
|
324
333
|
interface MigrationShowResult {
|
|
325
|
-
readonly
|
|
334
|
+
readonly migration: MigrationShowPresent;
|
|
326
335
|
}
|
|
327
336
|
|
|
328
|
-
function formatSpaceShowBlock(
|
|
329
|
-
space: MigrationShowSpacePresent,
|
|
330
|
-
useColor: boolean,
|
|
331
|
-
): readonly string[] {
|
|
337
|
+
function formatSpaceShowBlock(space: MigrationShowPresent, useColor: boolean): readonly string[] {
|
|
332
338
|
const formatGreen = createColorFormatter(useColor, green);
|
|
333
339
|
const formatYellow = createColorFormatter(useColor, yellow);
|
|
334
340
|
const formatDimText = (text: string) => formatDim(useColor, text);
|
|
@@ -384,28 +390,7 @@ export function formatMigrationShowOutput(result: MigrationShowResult, flags: Gl
|
|
|
384
390
|
}
|
|
385
391
|
|
|
386
392
|
const useColor = flags.color !== false;
|
|
387
|
-
|
|
388
|
-
const multipleSpaces = result.spaces.length > 1;
|
|
389
|
-
const lines: string[] = [];
|
|
390
|
-
|
|
391
|
-
for (let i = 0; i < result.spaces.length; i++) {
|
|
392
|
-
const space = result.spaces[i]!;
|
|
393
|
-
if (multipleSpaces) {
|
|
394
|
-
lines.push(formatDimText(`── ${space.spaceId} ──`));
|
|
395
|
-
}
|
|
396
|
-
if (space.kind === 'missing') {
|
|
397
|
-
lines.push(formatDimText(` ${space.summary}`));
|
|
398
|
-
} else {
|
|
399
|
-
for (const line of formatSpaceShowBlock(space, useColor)) {
|
|
400
|
-
lines.push(line);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
if (i < result.spaces.length - 1) {
|
|
404
|
-
lines.push('');
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
return lines.join('\n');
|
|
393
|
+
return formatSpaceShowBlock(result.migration, useColor).join('\n');
|
|
409
394
|
}
|
|
410
395
|
|
|
411
396
|
/**
|
|
@@ -456,8 +441,8 @@ export function formatMigrationApplyOutput(
|
|
|
456
441
|
),
|
|
457
442
|
);
|
|
458
443
|
} else if (result.marker) {
|
|
459
|
-
//
|
|
460
|
-
//
|
|
444
|
+
// App-only / no-aggregate-breakdown fallback (e.g. older callers
|
|
445
|
+
// / non-aggregate code paths). The label is
|
|
461
446
|
// `App-space marker` (not `Signature`) so that when only one
|
|
462
447
|
// marker is observable we still name what it covers explicitly.
|
|
463
448
|
lines.push(`${formatDimText(` App-space marker: ${result.marker.storageHash}`)}`);
|
|
@@ -470,6 +455,12 @@ export function formatMigrationApplyOutput(
|
|
|
470
455
|
if (isVerbose(flags, 1)) {
|
|
471
456
|
lines.push(`${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
472
457
|
}
|
|
458
|
+
|
|
459
|
+
if (result.advancedRef) {
|
|
460
|
+
lines.push(
|
|
461
|
+
formatDimText(`Advanced ref "${result.advancedRef.name}" → ${result.advancedRef.hash}`),
|
|
462
|
+
);
|
|
463
|
+
}
|
|
473
464
|
}
|
|
474
465
|
|
|
475
466
|
return lines.join('\n');
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type GlyphMode = 'unicode' | 'ascii';
|
|
2
|
+
|
|
3
|
+
export interface GlyphModeInput {
|
|
4
|
+
readonly isTTY: boolean;
|
|
5
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function localeString(env: Readonly<Record<string, string | undefined>>): string {
|
|
9
|
+
return env['LC_ALL'] ?? env['LC_CTYPE'] ?? env['LANG'] ?? '';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function isUtf8Locale(env: Readonly<Record<string, string | undefined>>): boolean {
|
|
13
|
+
const locale = localeString(env);
|
|
14
|
+
if (locale.length === 0) return false;
|
|
15
|
+
return /UTF-8|utf8/i.test(locale);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function detectGlyphMode(input: GlyphModeInput): GlyphMode {
|
|
19
|
+
if (!input.isTTY) return 'ascii';
|
|
20
|
+
if (!isUtf8Locale(input.env)) return 'ascii';
|
|
21
|
+
return 'unicode';
|
|
22
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { IntegrityViolation } from '@prisma-next/migration-tools/aggregate';
|
|
2
|
+
import { join, relative } from 'pathe';
|
|
3
|
+
|
|
4
|
+
export interface CheckFailure {
|
|
5
|
+
readonly pnCode: string;
|
|
6
|
+
readonly where: string;
|
|
7
|
+
readonly why: string;
|
|
8
|
+
readonly fix: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function migrationPathRelative(dirPath: string): string {
|
|
12
|
+
return relative(process.cwd(), dirPath);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function migrationFileRelative(dirPath: string, fileName: string): string {
|
|
16
|
+
return join(migrationPathRelative(dirPath), fileName);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Map one {@link IntegrityViolation} onto a `migration check` failure row.
|
|
21
|
+
* Sole catalogue mapping from integrity violations to `PN-MIG-CHECK-*`.
|
|
22
|
+
*/
|
|
23
|
+
export function integrityViolationToCheckFailure(
|
|
24
|
+
violation: IntegrityViolation,
|
|
25
|
+
migrationsDir: string,
|
|
26
|
+
): CheckFailure {
|
|
27
|
+
const spaceRelative = (spaceId: string): string =>
|
|
28
|
+
migrationPathRelative(join(migrationsDir, spaceId));
|
|
29
|
+
const packageRelative = (spaceId: string, dirName: string): string =>
|
|
30
|
+
migrationPathRelative(join(migrationsDir, spaceId, dirName));
|
|
31
|
+
const refRelative = (spaceId: string, refName: string): string =>
|
|
32
|
+
migrationPathRelative(join(migrationsDir, spaceId, 'refs', `${refName}.json`));
|
|
33
|
+
|
|
34
|
+
switch (violation.kind) {
|
|
35
|
+
case 'hashMismatch':
|
|
36
|
+
return {
|
|
37
|
+
pnCode: 'PN-MIG-CHECK-001',
|
|
38
|
+
where: migrationFileRelative(
|
|
39
|
+
join(migrationsDir, violation.spaceId, violation.dirName),
|
|
40
|
+
'migration.json',
|
|
41
|
+
),
|
|
42
|
+
why: `Stored hash ${violation.stored} does not match recomputed hash ${violation.computed}`,
|
|
43
|
+
fix: 'Re-emit the migration package or restore from version control.',
|
|
44
|
+
};
|
|
45
|
+
case 'providedInvariantsMismatch':
|
|
46
|
+
return {
|
|
47
|
+
pnCode: 'PN-MIG-CHECK-002',
|
|
48
|
+
where: packageRelative(violation.spaceId, violation.dirName),
|
|
49
|
+
why: `Migration "${violation.dirName}" providedInvariants in migration.json disagrees with ops.json.`,
|
|
50
|
+
fix: 'Re-emit the migration package so migration.json and ops.json agree.',
|
|
51
|
+
};
|
|
52
|
+
case 'packageUnloadable':
|
|
53
|
+
return {
|
|
54
|
+
pnCode: 'PN-MIG-CHECK-002',
|
|
55
|
+
where: packageRelative(violation.spaceId, violation.dirName),
|
|
56
|
+
why: `Migration "${violation.dirName}" could not be loaded: ${violation.detail}`,
|
|
57
|
+
fix: 'Re-emit the migration package or restore from version control.',
|
|
58
|
+
};
|
|
59
|
+
case 'sameSourceAndTarget':
|
|
60
|
+
return {
|
|
61
|
+
pnCode: 'PN-MIG-CHECK-007',
|
|
62
|
+
where: packageRelative(violation.spaceId, violation.dirName),
|
|
63
|
+
why: `Migration "${violation.dirName}" in space "${violation.spaceId}" has source equal to target (${violation.hash}) with no data invariant — a true no-op self-edge.`,
|
|
64
|
+
fix: 'Add a data operation if this self-edge was meant to carry a data invariant, or delete the migration if it is a true no-op.',
|
|
65
|
+
};
|
|
66
|
+
case 'orphanSpaceDir':
|
|
67
|
+
return {
|
|
68
|
+
pnCode: 'PN-MIG-CHECK-008',
|
|
69
|
+
where: spaceRelative(violation.spaceId),
|
|
70
|
+
why: `Contract-space directory "${violation.spaceId}" exists on disk but no extension declares it.`,
|
|
71
|
+
fix: 'Remove the orphan directory, or declare the extension in `extensionPacks`.',
|
|
72
|
+
};
|
|
73
|
+
case 'declaredButUnmigrated':
|
|
74
|
+
return {
|
|
75
|
+
pnCode: 'PN-MIG-CHECK-009',
|
|
76
|
+
where: spaceRelative(violation.spaceId),
|
|
77
|
+
why: `Extension "${violation.spaceId}" is declared in \`extensionPacks\` but has no on-disk migrations directory.`,
|
|
78
|
+
fix: 'Re-emit the extension contract-space artefacts with `prisma-next contract emit` and migration planning, or remove the extension from `extensionPacks` if it is unused.',
|
|
79
|
+
};
|
|
80
|
+
case 'headRefMissing':
|
|
81
|
+
return {
|
|
82
|
+
pnCode: 'PN-MIG-CHECK-010',
|
|
83
|
+
where: refRelative(violation.spaceId, 'head'),
|
|
84
|
+
why: `Head ref \`refs/head.json\` is missing for contract space "${violation.spaceId}".`,
|
|
85
|
+
fix: 'Re-emit the contract-space migrations and head ref artefacts, or restore `refs/head.json` from version control.',
|
|
86
|
+
};
|
|
87
|
+
case 'headRefNotInGraph':
|
|
88
|
+
return {
|
|
89
|
+
pnCode: 'PN-MIG-CHECK-011',
|
|
90
|
+
where: refRelative(violation.spaceId, 'head'),
|
|
91
|
+
why: `Head ref ${violation.hash} for contract space "${violation.spaceId}" is not present in its migration graph.`,
|
|
92
|
+
fix: 'Re-emit the contract space migrations, or restore the missing migration package.',
|
|
93
|
+
};
|
|
94
|
+
case 'refUnreadable':
|
|
95
|
+
return {
|
|
96
|
+
pnCode: 'PN-MIG-CHECK-012',
|
|
97
|
+
where: refRelative(violation.spaceId, violation.refName),
|
|
98
|
+
why: `Ref "${violation.refName}" for contract space "${violation.spaceId}" is unreadable: ${violation.detail}`,
|
|
99
|
+
fix: 'Repair or remove the corrupt ref file.',
|
|
100
|
+
};
|
|
101
|
+
case 'targetMismatch':
|
|
102
|
+
return {
|
|
103
|
+
pnCode: 'PN-MIG-CHECK-013',
|
|
104
|
+
where: spaceRelative(violation.spaceId),
|
|
105
|
+
why: `Contract space "${violation.spaceId}" targets "${violation.actual}" but the project targets "${violation.expected}".`,
|
|
106
|
+
fix: 'Update the extension to target the configured database, or change the project target.',
|
|
107
|
+
};
|
|
108
|
+
case 'disjointness':
|
|
109
|
+
return {
|
|
110
|
+
pnCode: 'PN-MIG-CHECK-014',
|
|
111
|
+
where: migrationPathRelative(migrationsDir),
|
|
112
|
+
why: `Storage element "${violation.element}" is claimed by multiple contract spaces: ${violation.claimedBy.join(', ')}.`,
|
|
113
|
+
fix: 'Update the contracts so each storage element is owned by exactly one contract space.',
|
|
114
|
+
};
|
|
115
|
+
case 'contractUnreadable':
|
|
116
|
+
return {
|
|
117
|
+
pnCode: 'PN-MIG-CHECK-015',
|
|
118
|
+
where: migrationFileRelative(join(migrationsDir, violation.spaceId), 'contract.json'),
|
|
119
|
+
why: `Contract for space "${violation.spaceId}" is unreadable: ${violation.detail}`,
|
|
120
|
+
fix: 'Re-emit the extension contract artefacts, or fix the descriptor producing the invalid contract.',
|
|
121
|
+
};
|
|
122
|
+
case 'duplicateMigrationHash':
|
|
123
|
+
return {
|
|
124
|
+
pnCode: 'PN-MIG-CHECK-016',
|
|
125
|
+
where: spaceRelative(violation.spaceId),
|
|
126
|
+
why: `Multiple migrations in space "${violation.spaceId}" share migrationHash "${violation.migrationHash}" (${violation.dirNames.join(', ')}).`,
|
|
127
|
+
fix: 'Re-emit one of the conflicting packages so each migrationHash is unique.',
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
+
import type { ContractSpaceMember } from '@prisma-next/migration-tools/aggregate';
|
|
3
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
4
|
+
import type { MigrationGraph } from '@prisma-next/migration-tools/graph';
|
|
5
|
+
import {
|
|
6
|
+
assertHashIsGraphNode,
|
|
7
|
+
findLatestMigration,
|
|
8
|
+
isGraphNode,
|
|
9
|
+
} from '@prisma-next/migration-tools/migration-graph';
|
|
10
|
+
import type { ContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
11
|
+
import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
12
|
+
import type { Refs } from '@prisma-next/migration-tools/refs';
|
|
13
|
+
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
14
|
+
import {
|
|
15
|
+
CliStructuredError,
|
|
16
|
+
errorPlanForgotTheFlag,
|
|
17
|
+
errorSnapshotMissing,
|
|
18
|
+
mapRefResolutionError,
|
|
19
|
+
} from './cli-errors';
|
|
20
|
+
import { mapContractAtError } from './contract-at-errors';
|
|
21
|
+
|
|
22
|
+
const FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;
|
|
23
|
+
|
|
24
|
+
export function looksLikeFullHash(input: string): boolean {
|
|
25
|
+
return FULL_HASH_PATTERN.test(input);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type FromResolution =
|
|
29
|
+
| { kind: 'greenfield'; fromHash: null; fromContract: null }
|
|
30
|
+
| { kind: 'graph-node'; fromHash: string; fromContract: Contract; sourceDir: string }
|
|
31
|
+
| {
|
|
32
|
+
kind: 'snapshot';
|
|
33
|
+
fromHash: string;
|
|
34
|
+
fromContract: Contract;
|
|
35
|
+
contractDts: string;
|
|
36
|
+
contractJson: unknown;
|
|
37
|
+
}
|
|
38
|
+
| {
|
|
39
|
+
kind: 'auto-baseline';
|
|
40
|
+
fromHash: string;
|
|
41
|
+
fromContract: Contract;
|
|
42
|
+
contractDts: string;
|
|
43
|
+
contractJson: unknown;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export interface ResolveFromForPlanInput {
|
|
47
|
+
readonly optionsFrom?: string | undefined;
|
|
48
|
+
readonly member: ContractSpaceMember;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function graphIsEmpty(member: ContractSpaceMember): boolean {
|
|
52
|
+
return member.packages.length === 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getReachableRefs(
|
|
56
|
+
refs: Refs,
|
|
57
|
+
graph: MigrationGraph,
|
|
58
|
+
): ReadonlyArray<{ name: string; hash: string }> {
|
|
59
|
+
return Object.entries(refs)
|
|
60
|
+
.flatMap(([name, entry]) =>
|
|
61
|
+
entry && isGraphNode(entry.hash, graph) ? [{ name, hash: entry.hash }] : [],
|
|
62
|
+
)
|
|
63
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function assertFromIsGraphNode(
|
|
67
|
+
fromHash: string,
|
|
68
|
+
graph: MigrationGraph,
|
|
69
|
+
refs: Refs,
|
|
70
|
+
graphTipHash: string | null,
|
|
71
|
+
): void {
|
|
72
|
+
try {
|
|
73
|
+
assertHashIsGraphNode(fromHash, graph);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (MigrationToolsError.is(error) && error.code === 'MIGRATION.HASH_NOT_IN_GRAPH') {
|
|
76
|
+
throw errorPlanForgotTheFlag(fromHash, getReachableRefs(refs, graph), graphTipHash);
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type RefContractResolution =
|
|
83
|
+
| {
|
|
84
|
+
kind: 'snapshot';
|
|
85
|
+
hash: string;
|
|
86
|
+
contract: Contract;
|
|
87
|
+
contractJson: unknown;
|
|
88
|
+
contractDts: string;
|
|
89
|
+
}
|
|
90
|
+
| {
|
|
91
|
+
kind: 'graph-node';
|
|
92
|
+
hash: string;
|
|
93
|
+
contract: Contract;
|
|
94
|
+
contractJson: unknown;
|
|
95
|
+
contractDts: string;
|
|
96
|
+
sourceDir: string;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
async function resolveContractRef(
|
|
100
|
+
parsed: ContractRef,
|
|
101
|
+
member: ContractSpaceMember,
|
|
102
|
+
options?: { readonly explicitLabel?: string; readonly artifactRole?: 'from' | 'to' },
|
|
103
|
+
): Promise<Result<RefContractResolution, CliStructuredError>> {
|
|
104
|
+
const { hash, provenance } = parsed;
|
|
105
|
+
const refName = provenance.kind === 'ref' ? provenance.refName : undefined;
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const at = await member.contractAt(hash, refName !== undefined ? { refName } : undefined);
|
|
109
|
+
|
|
110
|
+
if (at.provenance === 'snapshot') {
|
|
111
|
+
return ok({
|
|
112
|
+
kind: 'snapshot',
|
|
113
|
+
hash: at.hash,
|
|
114
|
+
contract: at.contract,
|
|
115
|
+
contractJson: at.contractJson,
|
|
116
|
+
contractDts: at.contractDts,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return ok({
|
|
121
|
+
kind: 'graph-node',
|
|
122
|
+
hash: at.hash,
|
|
123
|
+
contract: at.contract,
|
|
124
|
+
contractJson: at.contractJson,
|
|
125
|
+
contractDts: at.contractDts,
|
|
126
|
+
sourceDir: at.sourceDir,
|
|
127
|
+
});
|
|
128
|
+
} catch (error) {
|
|
129
|
+
return mapContractAtError(
|
|
130
|
+
error,
|
|
131
|
+
options?.artifactRole !== undefined ? { artifactRole: options.artifactRole } : undefined,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function resolveFromPolicy(
|
|
137
|
+
parsed: ContractRef,
|
|
138
|
+
input: ResolveFromForPlanInput,
|
|
139
|
+
refs: Refs,
|
|
140
|
+
explicitFromLabel?: string,
|
|
141
|
+
): Promise<Result<FromResolution, CliStructuredError>> {
|
|
142
|
+
const resolution = await resolveContractRef(parsed, input.member, {
|
|
143
|
+
...(explicitFromLabel !== undefined ? { explicitLabel: explicitFromLabel } : {}),
|
|
144
|
+
artifactRole: 'from',
|
|
145
|
+
});
|
|
146
|
+
if (!resolution.ok) {
|
|
147
|
+
return resolution;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (resolution.value.kind === 'graph-node') {
|
|
151
|
+
return ok({
|
|
152
|
+
kind: 'graph-node',
|
|
153
|
+
fromHash: resolution.value.hash,
|
|
154
|
+
fromContract: resolution.value.contract,
|
|
155
|
+
sourceDir: resolution.value.sourceDir,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const { hash, contract, contractJson, contractDts } = resolution.value;
|
|
160
|
+
if (graphIsEmpty(input.member)) {
|
|
161
|
+
return ok({
|
|
162
|
+
kind: 'auto-baseline',
|
|
163
|
+
fromHash: hash,
|
|
164
|
+
fromContract: contract,
|
|
165
|
+
contractDts,
|
|
166
|
+
contractJson,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const graph = input.member.graph();
|
|
171
|
+
const graphTip = findLatestMigration(graph)?.to ?? null;
|
|
172
|
+
try {
|
|
173
|
+
assertFromIsGraphNode(hash, graph, refs, graphTip);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if (CliStructuredError.is(error)) {
|
|
176
|
+
return notOk(error);
|
|
177
|
+
}
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
return ok({
|
|
181
|
+
kind: 'snapshot',
|
|
182
|
+
fromHash: hash,
|
|
183
|
+
fromContract: contract,
|
|
184
|
+
contractDts,
|
|
185
|
+
contractJson,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export async function resolveFromForPlan(
|
|
190
|
+
input: ResolveFromForPlanInput,
|
|
191
|
+
): Promise<Result<FromResolution, CliStructuredError>> {
|
|
192
|
+
const { optionsFrom, member } = input;
|
|
193
|
+
const graph = member.graph();
|
|
194
|
+
const refs = member.refs;
|
|
195
|
+
|
|
196
|
+
if (optionsFrom === undefined) {
|
|
197
|
+
const dbRef = refs['db'];
|
|
198
|
+
if (!dbRef) {
|
|
199
|
+
return ok({ kind: 'greenfield', fromHash: null, fromContract: null });
|
|
200
|
+
}
|
|
201
|
+
return resolveFromPolicy(
|
|
202
|
+
{ hash: dbRef.hash, provenance: { kind: 'ref', refName: 'db' } },
|
|
203
|
+
input,
|
|
204
|
+
refs,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const refResult = parseContractRef(optionsFrom, { graph, refs });
|
|
209
|
+
if (!refResult.ok) {
|
|
210
|
+
if (looksLikeFullHash(optionsFrom)) {
|
|
211
|
+
const empty = graphIsEmpty(member);
|
|
212
|
+
const graphTip = findLatestMigration(graph)?.to ?? null;
|
|
213
|
+
if (empty) {
|
|
214
|
+
return notOk(errorSnapshotMissing(optionsFrom, { viaRef: false }));
|
|
215
|
+
}
|
|
216
|
+
return notOk(errorPlanForgotTheFlag(optionsFrom, getReachableRefs(refs, graph), graphTip));
|
|
217
|
+
}
|
|
218
|
+
return notOk(mapRefResolutionError(refResult.failure));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return resolveFromPolicy(refResult.value, input, refs, optionsFrom);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface ResolveToForPlanInput {
|
|
225
|
+
readonly member: ContractSpaceMember;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export interface ResolvedContractRef {
|
|
229
|
+
readonly hash: string;
|
|
230
|
+
readonly contract: Contract;
|
|
231
|
+
readonly contractJson: unknown;
|
|
232
|
+
readonly contractDts: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export async function resolveToForPlan(
|
|
236
|
+
optionsTo: string,
|
|
237
|
+
input: ResolveToForPlanInput,
|
|
238
|
+
): Promise<Result<ResolvedContractRef, CliStructuredError>> {
|
|
239
|
+
const { member } = input;
|
|
240
|
+
const graph = member.graph();
|
|
241
|
+
const refs = member.refs;
|
|
242
|
+
|
|
243
|
+
const refResult = parseContractRef(optionsTo, { graph, refs });
|
|
244
|
+
if (!refResult.ok) {
|
|
245
|
+
return notOk(mapRefResolutionError(refResult.failure));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const resolution = await resolveContractRef(refResult.value, member, {
|
|
249
|
+
explicitLabel: optionsTo,
|
|
250
|
+
artifactRole: 'to',
|
|
251
|
+
});
|
|
252
|
+
if (!resolution.ok) {
|
|
253
|
+
return resolution;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const { hash, contract, contractJson, contractDts } = resolution.value;
|
|
257
|
+
return ok({ hash, contract, contractJson, contractDts });
|
|
258
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import type { ContractIR } from '@prisma-next/migration-tools/refs';
|
|
3
|
+
import { writeRefPaired } from '@prisma-next/migration-tools/refs';
|
|
4
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
5
|
+
|
|
6
|
+
export interface RefAdvancementFields {
|
|
7
|
+
readonly advancedRef: { readonly name: string; readonly hash: string } | null;
|
|
8
|
+
readonly plannedAdvanceRef: { readonly name: string; readonly hash: string } | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function computeRefAdvancementName(options: {
|
|
12
|
+
readonly advanceRef?: string;
|
|
13
|
+
readonly db?: string;
|
|
14
|
+
}): string | null {
|
|
15
|
+
if (options.advanceRef !== undefined) {
|
|
16
|
+
return options.advanceRef;
|
|
17
|
+
}
|
|
18
|
+
if (options.db === undefined) {
|
|
19
|
+
return 'db';
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function readContractIR(
|
|
25
|
+
contractJson: Record<string, unknown>,
|
|
26
|
+
contractJsonPath: string,
|
|
27
|
+
): Promise<ContractIR> {
|
|
28
|
+
const contractDtsPath = contractJsonPath.replace(/\.json$/i, '.d.ts');
|
|
29
|
+
const contractDts = await readFile(contractDtsPath, 'utf-8');
|
|
30
|
+
return { contract: contractJson, contractDts };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function executeRefAdvancement(
|
|
34
|
+
refsDir: string,
|
|
35
|
+
name: string,
|
|
36
|
+
hash: string,
|
|
37
|
+
contractIR: ContractIR,
|
|
38
|
+
): Promise<{ name: string; hash: string }> {
|
|
39
|
+
await writeRefPaired(refsDir, name, { hash, invariants: [] }, contractIR);
|
|
40
|
+
return { name, hash };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function buildRefAdvancementFields(options: {
|
|
44
|
+
readonly advanceRef?: string;
|
|
45
|
+
readonly db?: string;
|
|
46
|
+
readonly refsDir: string;
|
|
47
|
+
readonly contractIR: ContractIR;
|
|
48
|
+
readonly mode: 'plan' | 'apply';
|
|
49
|
+
readonly hash: string;
|
|
50
|
+
}): Promise<RefAdvancementFields> {
|
|
51
|
+
const name = computeRefAdvancementName({
|
|
52
|
+
...ifDefined('advanceRef', options.advanceRef),
|
|
53
|
+
...ifDefined('db', options.db),
|
|
54
|
+
});
|
|
55
|
+
if (name === null) {
|
|
56
|
+
return { advancedRef: null, plannedAdvanceRef: null };
|
|
57
|
+
}
|
|
58
|
+
if (options.mode === 'plan') {
|
|
59
|
+
return { advancedRef: null, plannedAdvanceRef: { name, hash: options.hash } };
|
|
60
|
+
}
|
|
61
|
+
const advancedRef = await executeRefAdvancement(
|
|
62
|
+
options.refsDir,
|
|
63
|
+
name,
|
|
64
|
+
options.hash,
|
|
65
|
+
options.contractIR,
|
|
66
|
+
);
|
|
67
|
+
return { advancedRef, plannedAdvanceRef: null };
|
|
68
|
+
}
|