prisma-next 0.12.0-dev.21 → 0.12.0-dev.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +5 -5
- package/dist/{client-Cdxcme1x.mjs → client-BHe8szOW.mjs} +4 -4
- package/dist/{client-Cdxcme1x.mjs.map → client-BHe8szOW.mjs.map} +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +2 -2
- package/dist/commands/db-schema.mjs +1 -1
- package/dist/commands/db-sign.mjs +1 -1
- package/dist/commands/db-update.mjs +2 -2
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.mjs +1 -1
- package/dist/commands/migration-graph.mjs +164 -1
- package/dist/commands/migration-graph.mjs.map +1 -0
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +4 -6
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts +4 -16
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +1 -137
- package/dist/commands/migration-show.mjs +1 -1
- package/dist/commands/migration-status.mjs +1 -1
- package/dist/{contract-infer-DaFPNrZH.mjs → contract-infer-OCn12Zvn.mjs} +2 -2
- package/dist/{contract-infer-DaFPNrZH.mjs.map → contract-infer-OCn12Zvn.mjs.map} +1 -1
- package/dist/{db-verify-BSA1a_W_.mjs → db-verify-DJxengYP.mjs} +2 -2
- package/dist/{db-verify-BSA1a_W_.mjs.map → db-verify-DJxengYP.mjs.map} +1 -1
- package/dist/exports/control-api.mjs +1 -1
- package/dist/{inspect-live-schema-Dn56wDhG.mjs → inspect-live-schema-DVZlDlnF.mjs} +2 -2
- package/dist/{inspect-live-schema-Dn56wDhG.mjs.map → inspect-live-schema-DVZlDlnF.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-V52dV2Tv.mjs → migration-command-scaffold-Cs7Ky-m5.mjs} +2 -2
- package/dist/{migration-command-scaffold-V52dV2Tv.mjs.map → migration-command-scaffold-Cs7Ky-m5.mjs.map} +1 -1
- package/dist/{migration-graph-DKl_IYsF.mjs → migration-graph-tree-render-BQdhKBO8.mjs} +405 -165
- package/dist/migration-graph-tree-render-BQdhKBO8.mjs.map +1 -0
- package/dist/migration-log-BzPmks3c.mjs +203 -0
- package/dist/migration-log-BzPmks3c.mjs.map +1 -0
- package/package.json +11 -11
- package/dist/commands/migration-log.mjs.map +0 -1
- package/dist/migration-graph-DKl_IYsF.mjs.map +0 -1
- package/dist/migration-list-styler-COQbZmXk.mjs +0 -414
- package/dist/migration-list-styler-COQbZmXk.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _ as parseGlobalFlagsOrExit, b as handleResult, l as setCommandDescriptions, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI } from "../command-helpers-Cmdqyhz9.mjs";
|
|
2
|
-
import { t as inspectLiveSchema } from "../inspect-live-schema-
|
|
2
|
+
import { t as inspectLiveSchema } from "../inspect-live-schema-DVZlDlnF.mjs";
|
|
3
3
|
import { n as formatIntrospectOutput, t as formatIntrospectJson } from "../verify-CreSJ1Mz.mjs";
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
//#region src/commands/db-schema.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { E as formatStyledHeader, F as errorContractValidationFailed, I as errorDatabaseConnectionRequired, R as errorDriverRequired, Z as errorRuntime, _ as parseGlobalFlagsOrExit, b as handleResult, i as maskConnectionUrl, it as mapRefResolutionError, j as CliStructuredError, l as setCommandDescriptions, nt as errorUnexpected, o as resolveContractPath, rt as mapMigrationToolsError, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI, z as errorFileNotFound } from "../command-helpers-Cmdqyhz9.mjs";
|
|
3
3
|
import { t as createProgressAdapter } from "../progress-adapter-C644QK8l.mjs";
|
|
4
|
-
import { a as ContractValidationError, t as createControlClient } from "../client-
|
|
4
|
+
import { a as ContractValidationError, t as createControlClient } from "../client-BHe8szOW.mjs";
|
|
5
5
|
import { r as buildReadAggregate } from "../contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
6
6
|
import { a as formatSignJson, i as formatSchemaVerifyOutput, o as formatSignOutput, r as formatSchemaVerifyJson } from "../verify-CreSJ1Mz.mjs";
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { F as errorContractValidationFailed, L as errorDestructiveChanges, M as ERROR_CODE_DESTRUCTIVE_CHANGES, W as errorMigrationPlanningFailed, X as errorRunnerFailed, _ as parseGlobalFlagsOrExit, b as handleResult, c as sanitizeErrorMessage, it as mapRefResolutionError, j as CliStructuredError, l as setCommandDescriptions, nt as errorUnexpected, rt as mapMigrationToolsError, s as resolveMigrationPaths, u as setCommandExamples, v as createTerminalUI } from "../command-helpers-Cmdqyhz9.mjs";
|
|
2
|
-
import { a as ContractValidationError } from "../client-
|
|
2
|
+
import { a as ContractValidationError } from "../client-BHe8szOW.mjs";
|
|
3
3
|
import { r as buildReadAggregate } from "../contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
4
4
|
import { i as formatMigrationPlanOutput, n as formatMigrationApplyOutput, r as formatMigrationJson } from "../migrations-DQ1t3XFL.mjs";
|
|
5
|
-
import { n as prepareMigrationContext, t as addMigrationCommandOptions } from "../migration-command-scaffold-
|
|
5
|
+
import { n as prepareMigrationContext, t as addMigrationCommandOptions } from "../migration-command-scaffold-Cs7Ky-m5.mjs";
|
|
6
6
|
import { i as readContractIR, n as computeRefAdvancementName, t as buildRefAdvancementFields } from "../ref-advancement-DUZqsue6.mjs";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createDbVerifyCommand } from "../db-verify-
|
|
1
|
+
import { t as createDbVerifyCommand } from "../db-verify-DJxengYP.mjs";
|
|
2
2
|
export { createDbVerifyCommand };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { E as formatStyledHeader, F as errorContractValidationFailed, G as errorPathUnreachable, H as errorMarkerMismatch, I as errorDatabaseConnectionRequired, R as errorDriverRequired, Z as errorRuntime, _ as parseGlobalFlagsOrExit, b as handleResult, et as errorTargetMigrationNotSupported, f as targetSupportsMigrations, i as maskConnectionUrl, it as mapRefResolutionError, j as CliStructuredError, l as setCommandDescriptions, n as collectDeclaredInvariants, nt as errorUnexpected, o as resolveContractPath, rt as mapMigrationToolsError, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI, z as errorFileNotFound } from "../command-helpers-Cmdqyhz9.mjs";
|
|
3
|
-
import { t as createControlClient } from "../client-
|
|
3
|
+
import { t as createControlClient } from "../client-BHe8szOW.mjs";
|
|
4
4
|
import { t as toDeclaredExtensionsFromRaw } from "../extension-pack-inputs-IDvjRCi3.mjs";
|
|
5
5
|
import { a as loadContractSpaceAggregateForCli, o as refuseContractSpaceIntegrity } from "../contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
6
6
|
import { t as formatMigrationApplyCommandOutput } from "../migrations-DQ1t3XFL.mjs";
|
|
@@ -1,2 +1,165 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
+
import { E as formatStyledHeader, _ as parseGlobalFlagsOrExit, b as handleResult, d as setCommandSeeAlso, l as setCommandDescriptions, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI } from "../command-helpers-Cmdqyhz9.mjs";
|
|
3
|
+
import { r as buildReadAggregate } from "../contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
4
|
+
import { i as migrationGraphToRenderInput, n as graphRenderer } from "../graph-render-rFAqZujX.mjs";
|
|
5
|
+
import { c as buildMigrationGraphLayout, n as renderMigrationGraphTree, s as buildMigrationGraphRows, t as renderMigrationGraphLegend } from "../migration-graph-tree-render-BQdhKBO8.mjs";
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { ok } from "@prisma-next/utils/result";
|
|
8
|
+
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
9
|
+
//#region src/commands/migration-graph.ts
|
|
10
|
+
/**
|
|
11
|
+
* `--legend` describes the `--tree` visual language, so passing it auto-enables
|
|
12
|
+
* the tree path (it has nothing to say about the legacy dagre default).
|
|
13
|
+
*/
|
|
14
|
+
function migrationGraphUsesTree(options) {
|
|
15
|
+
return options.tree === true || options.legend === true;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The legend is decoration printed alongside the command header on stderr, so
|
|
19
|
+
* it is suppressed for the machine-readable / silent paths (`--json`, `--dot`,
|
|
20
|
+
* `--quiet`) exactly as the header is.
|
|
21
|
+
*/
|
|
22
|
+
function migrationGraphShowsLegend(options, flags) {
|
|
23
|
+
return options.legend === true && options.dot !== true && flags.json !== true && flags.quiet !== true;
|
|
24
|
+
}
|
|
25
|
+
async function executeMigrationGraphCommand(options, flags, ui) {
|
|
26
|
+
const config = await loadConfig(options.config);
|
|
27
|
+
const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(options.config, config);
|
|
28
|
+
if (!flags.json && !flags.quiet) {
|
|
29
|
+
const header = formatStyledHeader({
|
|
30
|
+
command: "migration graph",
|
|
31
|
+
description: "Show the migration graph topology",
|
|
32
|
+
details: [{
|
|
33
|
+
label: "config",
|
|
34
|
+
value: configPath
|
|
35
|
+
}, {
|
|
36
|
+
label: "migrations",
|
|
37
|
+
value: appMigrationsRelative
|
|
38
|
+
}],
|
|
39
|
+
flags
|
|
40
|
+
});
|
|
41
|
+
ui.stderr(header);
|
|
42
|
+
if (migrationGraphShowsLegend(options, flags)) {
|
|
43
|
+
ui.stderr(renderMigrationGraphLegend({
|
|
44
|
+
colorize: flags.color !== false,
|
|
45
|
+
glyphMode: ui.resolveGlyphMode(options.ascii === true)
|
|
46
|
+
}));
|
|
47
|
+
ui.stderr("");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
51
|
+
if (!loaded.ok) return loaded;
|
|
52
|
+
const { aggregate, contractHash } = loaded.value;
|
|
53
|
+
const graph = aggregate.app.graph();
|
|
54
|
+
return ok({
|
|
55
|
+
ok: true,
|
|
56
|
+
graph,
|
|
57
|
+
contractHash,
|
|
58
|
+
refs: Object.entries(aggregate.app.refs).map(([name, entry]) => ({
|
|
59
|
+
name,
|
|
60
|
+
hash: entry.hash,
|
|
61
|
+
active: false
|
|
62
|
+
})),
|
|
63
|
+
summary: `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function createMigrationGraphCommand() {
|
|
67
|
+
const command = new Command("graph");
|
|
68
|
+
setCommandDescriptions(command, "Show the migration graph topology", "Renders the migration graph topology. Offline — does not consult\nthe database. Use --tree for the condensed annotated tree\n(--ascii swaps box-drawing for pipe-friendly ASCII glyphs),\n--json for machine-readable output, or --dot for Graphviz DOT\nformat.");
|
|
69
|
+
setCommandExamples(command, [
|
|
70
|
+
"prisma-next migration graph",
|
|
71
|
+
"prisma-next migration graph --json",
|
|
72
|
+
"prisma-next migration graph --dot",
|
|
73
|
+
"prisma-next migration graph --tree",
|
|
74
|
+
"prisma-next migration graph --tree --ascii",
|
|
75
|
+
"prisma-next migration graph --legend"
|
|
76
|
+
]);
|
|
77
|
+
setCommandSeeAlso(command, [
|
|
78
|
+
{
|
|
79
|
+
verb: "migration status",
|
|
80
|
+
oneLiner: "Show migration path and pending status"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
verb: "migration log",
|
|
84
|
+
oneLiner: "Show executed migration history"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
verb: "migration list",
|
|
88
|
+
oneLiner: "List on-disk migrations"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
verb: "migration show",
|
|
92
|
+
oneLiner: "Display migration package contents"
|
|
93
|
+
}
|
|
94
|
+
]);
|
|
95
|
+
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").option("--dot", "Output in Graphviz DOT format").option("--tree", "Experimental condensed annotated tree renderer").option("--ascii", "Use ASCII glyphs for --tree (pipe-friendly)").option("--legend", "Print a key for the --tree glyphs and lane colors (implies --tree)").action(async (options) => {
|
|
96
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
97
|
+
const ui = createTerminalUI(flags);
|
|
98
|
+
const exitCode = handleResult(await executeMigrationGraphCommand(options, flags, ui), flags, ui, (graphResult) => {
|
|
99
|
+
if (options.dot) {
|
|
100
|
+
const lines = ["digraph migrations {"];
|
|
101
|
+
for (const edge of graphResult.graph.migrationByHash.values()) {
|
|
102
|
+
const from = edge.from.slice(0, 12);
|
|
103
|
+
const to = edge.to.slice(0, 12);
|
|
104
|
+
lines.push(` "${from}" -> "${to}" [label="${edge.dirName}"];`);
|
|
105
|
+
}
|
|
106
|
+
lines.push("}");
|
|
107
|
+
ui.output(lines.join("\n"));
|
|
108
|
+
} else if (flags.json) {
|
|
109
|
+
const nodes = [...graphResult.graph.nodes];
|
|
110
|
+
const edges = [...graphResult.graph.migrationByHash.values()].map((e) => ({
|
|
111
|
+
dirName: e.dirName,
|
|
112
|
+
from: e.from,
|
|
113
|
+
to: e.to,
|
|
114
|
+
migrationHash: e.migrationHash
|
|
115
|
+
}));
|
|
116
|
+
ui.output(JSON.stringify({
|
|
117
|
+
ok: true,
|
|
118
|
+
nodes,
|
|
119
|
+
edges,
|
|
120
|
+
summary: graphResult.summary
|
|
121
|
+
}, null, 2));
|
|
122
|
+
} else if (!flags.quiet) if (migrationGraphUsesTree(options)) {
|
|
123
|
+
const refsByHash = /* @__PURE__ */ new Map();
|
|
124
|
+
for (const ref of graphResult.refs) {
|
|
125
|
+
const existing = refsByHash.get(ref.hash);
|
|
126
|
+
refsByHash.set(ref.hash, existing ? [...existing, ref.name] : [ref.name]);
|
|
127
|
+
}
|
|
128
|
+
const layout = buildMigrationGraphLayout(buildMigrationGraphRows(graphResult.graph, { ...graphResult.contractHash !== null ? { contractHash: graphResult.contractHash } : {} }));
|
|
129
|
+
const activeRef = graphResult.refs.find((ref) => ref.active);
|
|
130
|
+
const treeOutput = renderMigrationGraphTree(layout, {
|
|
131
|
+
refsByHash,
|
|
132
|
+
...graphResult.contractHash !== null ? { contractHash: graphResult.contractHash } : {},
|
|
133
|
+
...activeRef !== void 0 ? { activeRefName: activeRef.name } : {},
|
|
134
|
+
colorize: flags.color !== false,
|
|
135
|
+
glyphMode: ui.resolveGlyphMode(options.ascii === true)
|
|
136
|
+
});
|
|
137
|
+
ui.output(treeOutput);
|
|
138
|
+
ui.output(`\n${graphResult.summary}`);
|
|
139
|
+
} else {
|
|
140
|
+
const renderInput = migrationGraphToRenderInput({
|
|
141
|
+
graph: graphResult.graph,
|
|
142
|
+
mode: "offline",
|
|
143
|
+
markerHash: void 0,
|
|
144
|
+
contractHash: graphResult.contractHash ?? EMPTY_CONTRACT_HASH,
|
|
145
|
+
refs: graphResult.refs,
|
|
146
|
+
activeRefHash: void 0,
|
|
147
|
+
activeRefName: void 0,
|
|
148
|
+
edgeStatuses: []
|
|
149
|
+
});
|
|
150
|
+
const graphOutput = graphRenderer.render(renderInput.graph, {
|
|
151
|
+
...renderInput.options,
|
|
152
|
+
colorize: flags.color !== false
|
|
153
|
+
});
|
|
154
|
+
ui.log(graphOutput);
|
|
155
|
+
ui.log(`\n${graphResult.summary}`);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
process.exit(exitCode);
|
|
159
|
+
});
|
|
160
|
+
return command;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
2
163
|
export { createMigrationGraphCommand, executeMigrationGraphCommand, migrationGraphShowsLegend, migrationGraphUsesTree };
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=migration-graph.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-graph.mjs","names":[],"sources":["../../src/commands/migration-graph.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { migrationGraphToRenderInput } from '../utils/formatters/graph-migration-mapper';\nimport { graphRenderer } from '../utils/formatters/graph-render';\nimport { buildMigrationGraphLayout } from '../utils/formatters/migration-graph-layout';\nimport { buildMigrationGraphRows } from '../utils/formatters/migration-graph-rows';\nimport {\n renderMigrationGraphLegend,\n renderMigrationGraphTree,\n} from '../utils/formatters/migration-graph-tree-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationGraphOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly dot?: boolean;\n readonly tree?: boolean;\n readonly ascii?: boolean;\n readonly legend?: boolean;\n}\n\n/**\n * `--legend` describes the `--tree` visual language, so passing it auto-enables\n * the tree path (it has nothing to say about the legacy dagre default).\n */\nexport function migrationGraphUsesTree(options: {\n readonly tree?: boolean;\n readonly legend?: boolean;\n}): boolean {\n return options.tree === true || options.legend === true;\n}\n\n/**\n * The legend is decoration printed alongside the command header on stderr, so\n * it is suppressed for the machine-readable / silent paths (`--json`, `--dot`,\n * `--quiet`) exactly as the header is.\n */\nexport function migrationGraphShowsLegend(\n options: { readonly legend?: boolean; readonly dot?: boolean },\n flags: GlobalFlags,\n): boolean {\n return (\n options.legend === true && options.dot !== true && flags.json !== true && flags.quiet !== true\n );\n}\n\nexport interface MigrationGraphResult {\n readonly ok: true;\n readonly graph: MigrationGraph;\n readonly contractHash: string | null;\n readonly refs: readonly StatusRef[];\n readonly summary: string;\n}\n\nexport async function executeMigrationGraphCommand(\n options: MigrationGraphOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationGraphResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration graph',\n description: 'Show the migration graph topology',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n if (migrationGraphShowsLegend(options, flags)) {\n ui.stderr(\n renderMigrationGraphLegend({\n colorize: flags.color !== false,\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n }),\n );\n // Blank line separating the stderr key from the graph that follows on stdout.\n ui.stderr('');\n }\n }\n\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return loaded;\n }\n\n const { aggregate, contractHash } = loaded.value;\n const graph = aggregate.app.graph();\n const refs: readonly StatusRef[] = Object.entries(aggregate.app.refs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: false,\n }));\n\n return ok({\n ok: true,\n graph,\n contractHash,\n refs,\n summary: `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`,\n });\n}\n\nexport function createMigrationGraphCommand(): Command {\n const command = new Command('graph');\n setCommandDescriptions(\n command,\n 'Show the migration graph topology',\n 'Renders the migration graph topology. Offline — does not consult\\n' +\n 'the database. Use --tree for the condensed annotated tree\\n' +\n '(--ascii swaps box-drawing for pipe-friendly ASCII glyphs),\\n' +\n '--json for machine-readable output, or --dot for Graphviz DOT\\n' +\n 'format.',\n );\n setCommandExamples(command, [\n 'prisma-next migration graph',\n 'prisma-next migration graph --json',\n 'prisma-next migration graph --dot',\n 'prisma-next migration graph --tree',\n 'prisma-next migration graph --tree --ascii',\n 'prisma-next migration graph --legend',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dot', 'Output in Graphviz DOT format')\n .option('--tree', 'Experimental condensed annotated tree renderer')\n .option('--ascii', 'Use ASCII glyphs for --tree (pipe-friendly)')\n .option('--legend', 'Print a key for the --tree glyphs and lane colors (implies --tree)')\n .action(async (options: MigrationGraphOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationGraphCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (graphResult) => {\n // Explicit format flags win over the auto-JSON default. `flags.json`\n // is auto-enabled when stdout is non-TTY (per CLI Style Guide §\n // JSON Semantics); without this ordering, `migration graph --dot |\n // dot -Tsvg` pipes JSON into the GraphViz binary, which then\n // errors. `--dot` is the more specific instruction; honour it.\n if (options.dot) {\n const lines = ['digraph migrations {'];\n for (const edge of graphResult.graph.migrationByHash.values()) {\n const from = edge.from.slice(0, 12);\n const to = edge.to.slice(0, 12);\n lines.push(` \"${from}\" -> \"${to}\" [label=\"${edge.dirName}\"];`);\n }\n lines.push('}');\n ui.output(lines.join('\\n'));\n } else if (flags.json) {\n const nodes = [...graphResult.graph.nodes];\n const edges = [...graphResult.graph.migrationByHash.values()].map((e) => ({\n dirName: e.dirName,\n from: e.from,\n to: e.to,\n migrationHash: e.migrationHash,\n }));\n ui.output(\n JSON.stringify({ ok: true, nodes, edges, summary: graphResult.summary }, null, 2),\n );\n } else if (!flags.quiet) {\n if (migrationGraphUsesTree(options)) {\n const refsByHash = new Map<string, string[]>();\n for (const ref of graphResult.refs) {\n const existing = refsByHash.get(ref.hash);\n refsByHash.set(ref.hash, existing ? [...existing, ref.name] : [ref.name]);\n }\n const rowModel = buildMigrationGraphRows(graphResult.graph, {\n ...(graphResult.contractHash !== null\n ? { contractHash: graphResult.contractHash }\n : {}),\n });\n const layout = buildMigrationGraphLayout(rowModel);\n const activeRef = graphResult.refs.find((ref) => ref.active);\n const treeOutput = renderMigrationGraphTree(layout, {\n refsByHash,\n ...(graphResult.contractHash !== null\n ? { contractHash: graphResult.contractHash }\n : {}),\n ...(activeRef !== undefined ? { activeRefName: activeRef.name } : {}),\n colorize: flags.color !== false,\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n });\n // Emit the rendered tree to stdout (same stream as flat `migration list`),\n // not through clack's `log.message` rail: the graph is the command's\n // result (and its own box-drawing is the only vertical structure it\n // should carry), not a status line that needs the prompt gutter.\n ui.output(treeOutput);\n ui.output(`\\n${graphResult.summary}`);\n } else {\n const renderInput = migrationGraphToRenderInput({\n graph: graphResult.graph,\n mode: 'offline',\n markerHash: undefined,\n contractHash: graphResult.contractHash ?? EMPTY_CONTRACT_HASH,\n refs: graphResult.refs,\n activeRefHash: undefined,\n activeRefName: undefined,\n edgeStatuses: [],\n });\n const graphOutput = graphRenderer.render(renderInput.graph, {\n ...renderInput.options,\n colorize: flags.color !== false,\n });\n ui.log(graphOutput);\n ui.log(`\\n${graphResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-list.d.mts","names":[],"sources":["../../src/utils/formatters/migration-list-types.ts","../../src/commands/migration-list.ts"],"mappings":";;;;;;;;UAAiB,kBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;EAAA,SACA,IAAA;EAAA,SACA,kBAAA;AAAA;AAAA,UAGM,uBAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAA,WAAqB,kBAAkB;AAAA;AAAA,UAGjC,mBAAA;EAAA,SACN,EAAA;EAAA,SACA,MAAA,WAAiB,uBAAuB;EAAA,SACxC,OAAA;AAAA;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"migration-list.d.mts","names":[],"sources":["../../src/utils/formatters/migration-list-types.ts","../../src/commands/migration-list.ts"],"mappings":";;;;;;;;UAAiB,kBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;EAAA,SACA,IAAA;EAAA,SACA,kBAAA;AAAA;AAAA,UAGM,uBAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAA,WAAqB,kBAAkB;AAAA;AAAA,UAGjC,mBAAA;EAAA,SACN,EAAA;EAAA,SACA,MAAA,WAAiB,uBAAuB;EAAA,SACxC,OAAA;AAAA;;;;;;;;;;;iBC2EW,sCAAA,CACpB,SAAA,EAAW,sBAAA,EACX,oBAAA,WACC,OAAA,UAAiB,uBAAA;AAAA,UA6BV,oBAAA,SAA6B,oBAAoB;EAAA,SAChD,MAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA;AAAA;AAAA,UAGM,+BAAA;EAAA,SACN,SAAA,EAAW,SAAS;EAAA,SACpB,QAAA;AAAA;AAAA,iBAGK,8BAAA,CACd,MAAA,EAAQ,mBAAA,EACR,OAAA,EAAS,+BAA+B;;;AD9HQ;AAGlD;;;;;UC2IiB,sBAAA;EAAA,SACN,MAAA,WAAiB,uBAAuB;EAAA,SACxC,WAAA;AAAA;AD1IO;;;;AC2ElB;;;;;AD3EkB,iBC8JF,gBAAA,CACd,MAAA,EAAQ,sBAAA,GACP,MAAA,CAAO,mBAAA,EAAqB,kBAAA;;;;;;iBA6BT,2BAAA,CACpB,OAAA,EAAS,oBAAA,EACT,KAAA,EAAO,WAAA,EACP,EAAA,EAAI,UAAA,GACH,OAAA,CAAQ,MAAA,CAAO,mBAAA,EAAqB,kBAAA;AAAA,iBAqCvB,0BAAA,CAAA,GAA8B,OAAO"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { $ as errorSpaceNotFound, E as formatStyledHeader, V as errorInvalidSpaceId, _ as parseGlobalFlagsOrExit, b as handleResult, d as setCommandSeeAlso, l as setCommandDescriptions, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI } from "../command-helpers-Cmdqyhz9.mjs";
|
|
3
3
|
import { r as buildReadAggregate } from "../contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { a as renderMigrationListWithStyle, r as createAnsiMigrationListStyler } from "../migration-graph-tree-render-BQdhKBO8.mjs";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
7
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -73,9 +73,7 @@ async function migrationSpaceListEntriesFromAggregate(aggregate, projectMigratio
|
|
|
73
73
|
return spaces;
|
|
74
74
|
}
|
|
75
75
|
function renderMigrationListHumanOutput(result, options) {
|
|
76
|
-
|
|
77
|
-
const topologyBySpaceId = buildMigrationListTopologyBySpace(result);
|
|
78
|
-
return renderMigrationListWithStyle(result, styler, options.glyphMode, topologyBySpaceId);
|
|
76
|
+
return renderMigrationListWithStyle(result, createAnsiMigrationListStyler({ useColor: options.useColor }), options.glyphMode, { colorize: options.useColor });
|
|
79
77
|
}
|
|
80
78
|
function computeSummary(spaces) {
|
|
81
79
|
const totalMigrations = spaces.reduce((count, space) => count + space.migrations.length, 0);
|
|
@@ -117,7 +115,7 @@ async function executeMigrationListCommand(options, flags, ui) {
|
|
|
117
115
|
if (!flags.json && !flags.quiet) {
|
|
118
116
|
const header = formatStyledHeader({
|
|
119
117
|
command: "migration list",
|
|
120
|
-
description: "List on-disk migrations
|
|
118
|
+
description: "List on-disk migrations per contract space",
|
|
121
119
|
details: [
|
|
122
120
|
{
|
|
123
121
|
label: "config",
|
|
@@ -145,7 +143,7 @@ async function executeMigrationListCommand(options, flags, ui) {
|
|
|
145
143
|
}
|
|
146
144
|
function createMigrationListCommand() {
|
|
147
145
|
const command = new Command("list");
|
|
148
|
-
setCommandDescriptions(command, "List on-disk migrations
|
|
146
|
+
setCommandDescriptions(command, "List on-disk migrations per contract space", "Enumerates every on-disk migration under migrations/<space>/ for every\ncontract space found on disk. Offline — does not consult the database.\nHuman output draws the shared migration graph tree with operation counts,\ninvariants on each migration row, and refs on destination contract nodes.\nPass --space <id> to narrow to one contract space. --ascii forces ASCII\ntree glyphs (orthogonal to --no-color).");
|
|
149
147
|
setCommandExamples(command, [
|
|
150
148
|
"prisma-next migration list",
|
|
151
149
|
"prisma-next migration list --space app",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-list.mjs","names":[],"sources":["../../src/commands/migration-list.ts"],"sourcesContent":["import type {\n ContractSpaceAggregate,\n ContractSpaceMember,\n} from '@prisma-next/migration-tools/aggregate';\nimport { HEAD_REF_NAME, refsByContractHash } from '@prisma-next/migration-tools/refs';\nimport {\n APP_SPACE_ID,\n isValidSpaceId,\n listContractSpaceDirectories,\n RESERVED_SPACE_SUBDIR_NAMES,\n} from '@prisma-next/migration-tools/spaces';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorInvalidSpaceId,\n errorSpaceNotFound,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport {\n buildMigrationListTopologyBySpace,\n renderMigrationListWithStyle,\n} from '../utils/formatters/migration-list-render';\nimport { createAnsiMigrationListStyler } from '../utils/formatters/migration-list-styler';\nimport type {\n MigrationListEntry,\n MigrationListResult,\n MigrationSpaceListEntry,\n} from '../utils/formatters/migration-list-types';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { GlyphMode } from '../utils/glyph-mode';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\nfunction compareSpaceIds(a: string, b: string): number {\n if (a === APP_SPACE_ID) return b === APP_SPACE_ID ? 0 : -1;\n if (b === APP_SPACE_ID) return 1;\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n}\n\nfunction compareDirNamesDescending(a: MigrationListEntry, b: MigrationListEntry): number {\n if (a.dirName < b.dirName) return 1;\n if (a.dirName > b.dirName) return -1;\n return 0;\n}\n\n/**\n * Ref names decorating a space's destination contract hashes. The\n * tolerant `member.refs` deliberately omits the structural `head.json`;\n * for extension spaces the old enumerator surfaced it as a `head`\n * decoration on the tip migration, so fold `member.headRef` back in to\n * keep that output. The app space synthesises its head, so it carries\n * no on-disk `head` ref to restore.\n */\nfunction listRefsByContractHash(\n member: ContractSpaceMember,\n): ReadonlyMap<string, readonly string[]> {\n const byHash = new Map(refsByContractHash(member.refs));\n if (member.spaceId !== APP_SPACE_ID && member.headRef !== null) {\n const hash = member.headRef.hash;\n const bucket = byHash.get(hash) ?? [];\n if (!bucket.includes(HEAD_REF_NAME)) {\n byHash.set(hash, [...bucket, HEAD_REF_NAME].sort());\n }\n }\n return byHash;\n}\n\nasync function orderedOnDiskSpaceIds(projectMigrationsDir: string): Promise<readonly string[]> {\n const candidateDirs = await listContractSpaceDirectories(projectMigrationsDir);\n return candidateDirs\n .filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name))\n .filter(isValidSpaceId)\n .sort(compareSpaceIds);\n}\n\n/**\n * Project the loaded {@link ContractSpaceAggregate} into the render-ready\n * {@link MigrationSpaceListEntry} rows `migration list` displays.\n *\n * Space membership matches the on-disk contract-space directories (not the\n * aggregate's always-present synthesized app member when `migrations/app/`\n * is absent); package and ref data come from `aggregate.space(id)`.\n */\nexport async function migrationSpaceListEntriesFromAggregate(\n aggregate: ContractSpaceAggregate,\n projectMigrationsDir: string,\n): Promise<readonly MigrationSpaceListEntry[]> {\n const spaceIds = await orderedOnDiskSpaceIds(projectMigrationsDir);\n const spaces: MigrationSpaceListEntry[] = [];\n\n for (const spaceId of spaceIds) {\n const member = aggregate.space(spaceId);\n if (member === undefined) {\n continue;\n }\n const refsByHash = listRefsByContractHash(member);\n const migrations: MigrationListEntry[] = member.packages\n .map((pkg) => ({\n dirName: pkg.dirName,\n from: pkg.metadata.from,\n to: pkg.metadata.to,\n migrationHash: pkg.metadata.migrationHash,\n operationCount: pkg.ops.length,\n createdAt: pkg.metadata.createdAt,\n refs: refsByHash.get(pkg.metadata.to) ?? [],\n providedInvariants: pkg.metadata.providedInvariants,\n }))\n .sort(compareDirNamesDescending);\n\n spaces.push({ spaceId, migrations });\n }\n\n return spaces;\n}\n\ninterface MigrationListOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly space?: string;\n readonly ascii?: boolean;\n}\n\nexport interface MigrationListHumanRenderOptions {\n readonly glyphMode: GlyphMode;\n readonly useColor: boolean;\n}\n\nexport function renderMigrationListHumanOutput(\n result: MigrationListResult,\n options: MigrationListHumanRenderOptions,\n): string {\n const styler = createAnsiMigrationListStyler({ useColor: options.useColor });\n const topologyBySpaceId = buildMigrationListTopologyBySpace(result);\n return renderMigrationListWithStyle(result, styler, options.glyphMode, topologyBySpaceId);\n}\n\n/**\n * Inputs for {@link runMigrationList} — the policy core of `migration list`\n * that tests exercise directly.\n *\n * The core does not call `loadConfig`, parse CLI flags, render a styled\n * header, or write to any stream. Enumeration is supplied by the caller\n * (the CLI shell builds it from {@link migrationSpaceListEntriesFromAggregate}).\n */\nexport interface RunMigrationListInputs {\n readonly spaces: readonly MigrationSpaceListEntry[];\n readonly spaceFilter?: string;\n}\n\nfunction computeSummary(spaces: readonly MigrationSpaceListEntry[]): string {\n const totalMigrations = spaces.reduce((count, space) => count + space.migrations.length, 0);\n if (spaces.length <= 1) {\n return `${totalMigrations} migration(s) on disk`;\n }\n return `${totalMigrations} migration(s) across ${spaces.length} contract space(s)`;\n}\n\n/**\n * Policy core of `migration list`: validates `--space`, narrows the\n * pre-enumerated spaces, and assembles a {@link MigrationListResult}.\n *\n * - `migrations/` missing or contains no valid space directories →\n * caller passes `spaces: []`; this synthesizes `[{ spaceId: APP_SPACE_ID, migrations: [] }]`.\n * - `--space <id>` on an existing-but-empty space → `{ spaceId, migrations: [] }` in the input.\n * - `--space <id>` on a non-existent (or reserved) space → `SPACE_NOT_FOUND`.\n */\nexport function runMigrationList(\n inputs: RunMigrationListInputs,\n): Result<MigrationListResult, CliStructuredError> {\n const { spaces, spaceFilter } = inputs;\n\n if (spaceFilter !== undefined && !isValidSpaceId(spaceFilter)) {\n return notOk(errorInvalidSpaceId(spaceFilter));\n }\n\n if (spaceFilter !== undefined && !spaces.some((s) => s.spaceId === spaceFilter)) {\n return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.spaceId).sort()));\n }\n\n const scopedSpaces =\n spaceFilter !== undefined ? spaces.filter((s) => s.spaceId === spaceFilter) : spaces;\n\n const resultSpaces: readonly MigrationSpaceListEntry[] =\n scopedSpaces.length === 0 ? [{ spaceId: APP_SPACE_ID, migrations: [] }] : scopedSpaces;\n\n return ok({\n ok: true,\n spaces: resultSpaces,\n summary: computeSummary(resultSpaces),\n });\n}\n\n/**\n * CLI shell: loads config, resolves paths, prints the styled header on\n * stderr (interactive mode only), and delegates to {@link runMigrationList}.\n * Kept intentionally thin so the unit-testable surface lives in the core.\n */\nexport async function executeMigrationListCommand(\n options: MigrationListOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationListResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, migrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration list',\n description: 'List on-disk migrations, latest first, per contract space',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: migrationsRelative },\n ...(options.space !== undefined ? [{ label: 'space', value: options.space }] : []),\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n\n const spaces = await migrationSpaceListEntriesFromAggregate(\n loaded.value.aggregate,\n migrationsDir,\n );\n\n return runMigrationList({\n spaces,\n ...ifDefined('spaceFilter', options.space),\n });\n}\n\nexport function createMigrationListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(\n command,\n 'List on-disk migrations, latest first, per contract space',\n 'Enumerates every on-disk migration under migrations/<space>/ for every\\n' +\n 'contract space found on disk, latest first. Offline — does not consult\\n' +\n 'the database. Each row leads with a kind glyph (* forward, ↩ rollback,\\n' +\n '⟲ self), then dirName, then source → destination contract hashes\\n' +\n '(7-char git-style). Self-edges show a single hash. Invariants render as\\n' +\n '{...}; refs on the destination as (production, db). Pass --space <id>\\n' +\n 'to narrow to one contract space. --ascii forces ASCII kind glyphs\\n' +\n '(orthogonal to --no-color).',\n );\n setCommandExamples(command, [\n 'prisma-next migration list',\n 'prisma-next migration list --space app',\n 'prisma-next migration list --ascii',\n 'prisma-next migration list --json',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--space <id>', 'Narrow output to a single contract space')\n .option('--ascii', 'Use ASCII kind glyphs (pipe-friendly)')\n .action(async (options: MigrationListOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationListCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (listResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(listResult, null, 2));\n } else if (!flags.quiet) {\n ui.output(\n renderMigrationListHumanOutput(listResult, {\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n useColor: ui.useColor,\n }),\n );\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-list.mjs","names":[],"sources":["../../src/commands/migration-list.ts"],"sourcesContent":["import type {\n ContractSpaceAggregate,\n ContractSpaceMember,\n} from '@prisma-next/migration-tools/aggregate';\nimport { HEAD_REF_NAME, refsByContractHash } from '@prisma-next/migration-tools/refs';\nimport {\n APP_SPACE_ID,\n isValidSpaceId,\n listContractSpaceDirectories,\n RESERVED_SPACE_SUBDIR_NAMES,\n} from '@prisma-next/migration-tools/spaces';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorInvalidSpaceId,\n errorSpaceNotFound,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { renderMigrationListWithStyle } from '../utils/formatters/migration-list-render';\nimport { createAnsiMigrationListStyler } from '../utils/formatters/migration-list-styler';\nimport type {\n MigrationListEntry,\n MigrationListResult,\n MigrationSpaceListEntry,\n} from '../utils/formatters/migration-list-types';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { GlyphMode } from '../utils/glyph-mode';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\nfunction compareSpaceIds(a: string, b: string): number {\n if (a === APP_SPACE_ID) return b === APP_SPACE_ID ? 0 : -1;\n if (b === APP_SPACE_ID) return 1;\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n}\n\nfunction compareDirNamesDescending(a: MigrationListEntry, b: MigrationListEntry): number {\n if (a.dirName < b.dirName) return 1;\n if (a.dirName > b.dirName) return -1;\n return 0;\n}\n\n/**\n * Ref names decorating a space's destination contract hashes. The\n * tolerant `member.refs` deliberately omits the structural `head.json`;\n * for extension spaces the old enumerator surfaced it as a `head`\n * decoration on the tip migration, so fold `member.headRef` back in to\n * keep that output. The app space synthesises its head, so it carries\n * no on-disk `head` ref to restore.\n */\nfunction listRefsByContractHash(\n member: ContractSpaceMember,\n): ReadonlyMap<string, readonly string[]> {\n const byHash = new Map(refsByContractHash(member.refs));\n if (member.spaceId !== APP_SPACE_ID && member.headRef !== null) {\n const hash = member.headRef.hash;\n const bucket = byHash.get(hash) ?? [];\n if (!bucket.includes(HEAD_REF_NAME)) {\n byHash.set(hash, [...bucket, HEAD_REF_NAME].sort());\n }\n }\n return byHash;\n}\n\nasync function orderedOnDiskSpaceIds(projectMigrationsDir: string): Promise<readonly string[]> {\n const candidateDirs = await listContractSpaceDirectories(projectMigrationsDir);\n return candidateDirs\n .filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name))\n .filter(isValidSpaceId)\n .sort(compareSpaceIds);\n}\n\n/**\n * Project the loaded {@link ContractSpaceAggregate} into the render-ready\n * {@link MigrationSpaceListEntry} rows `migration list` displays.\n *\n * Space membership matches the on-disk contract-space directories (not the\n * aggregate's always-present synthesized app member when `migrations/app/`\n * is absent); package and ref data come from `aggregate.space(id)`.\n */\nexport async function migrationSpaceListEntriesFromAggregate(\n aggregate: ContractSpaceAggregate,\n projectMigrationsDir: string,\n): Promise<readonly MigrationSpaceListEntry[]> {\n const spaceIds = await orderedOnDiskSpaceIds(projectMigrationsDir);\n const spaces: MigrationSpaceListEntry[] = [];\n\n for (const spaceId of spaceIds) {\n const member = aggregate.space(spaceId);\n if (member === undefined) {\n continue;\n }\n const refsByHash = listRefsByContractHash(member);\n const migrations: MigrationListEntry[] = member.packages\n .map((pkg) => ({\n dirName: pkg.dirName,\n from: pkg.metadata.from,\n to: pkg.metadata.to,\n migrationHash: pkg.metadata.migrationHash,\n operationCount: pkg.ops.length,\n createdAt: pkg.metadata.createdAt,\n refs: refsByHash.get(pkg.metadata.to) ?? [],\n providedInvariants: pkg.metadata.providedInvariants,\n }))\n .sort(compareDirNamesDescending);\n\n spaces.push({ spaceId, migrations });\n }\n\n return spaces;\n}\n\ninterface MigrationListOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly space?: string;\n readonly ascii?: boolean;\n}\n\nexport interface MigrationListHumanRenderOptions {\n readonly glyphMode: GlyphMode;\n readonly useColor: boolean;\n}\n\nexport function renderMigrationListHumanOutput(\n result: MigrationListResult,\n options: MigrationListHumanRenderOptions,\n): string {\n const styler = createAnsiMigrationListStyler({ useColor: options.useColor });\n return renderMigrationListWithStyle(result, styler, options.glyphMode, {\n colorize: options.useColor,\n });\n}\n\n/**\n * Inputs for {@link runMigrationList} — the policy core of `migration list`\n * that tests exercise directly.\n *\n * The core does not call `loadConfig`, parse CLI flags, render a styled\n * header, or write to any stream. Enumeration is supplied by the caller\n * (the CLI shell builds it from {@link migrationSpaceListEntriesFromAggregate}).\n */\nexport interface RunMigrationListInputs {\n readonly spaces: readonly MigrationSpaceListEntry[];\n readonly spaceFilter?: string;\n}\n\nfunction computeSummary(spaces: readonly MigrationSpaceListEntry[]): string {\n const totalMigrations = spaces.reduce((count, space) => count + space.migrations.length, 0);\n if (spaces.length <= 1) {\n return `${totalMigrations} migration(s) on disk`;\n }\n return `${totalMigrations} migration(s) across ${spaces.length} contract space(s)`;\n}\n\n/**\n * Policy core of `migration list`: validates `--space`, narrows the\n * pre-enumerated spaces, and assembles a {@link MigrationListResult}.\n *\n * - `migrations/` missing or contains no valid space directories →\n * caller passes `spaces: []`; this synthesizes `[{ spaceId: APP_SPACE_ID, migrations: [] }]`.\n * - `--space <id>` on an existing-but-empty space → `{ spaceId, migrations: [] }` in the input.\n * - `--space <id>` on a non-existent (or reserved) space → `SPACE_NOT_FOUND`.\n */\nexport function runMigrationList(\n inputs: RunMigrationListInputs,\n): Result<MigrationListResult, CliStructuredError> {\n const { spaces, spaceFilter } = inputs;\n\n if (spaceFilter !== undefined && !isValidSpaceId(spaceFilter)) {\n return notOk(errorInvalidSpaceId(spaceFilter));\n }\n\n if (spaceFilter !== undefined && !spaces.some((s) => s.spaceId === spaceFilter)) {\n return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.spaceId).sort()));\n }\n\n const scopedSpaces =\n spaceFilter !== undefined ? spaces.filter((s) => s.spaceId === spaceFilter) : spaces;\n\n const resultSpaces: readonly MigrationSpaceListEntry[] =\n scopedSpaces.length === 0 ? [{ spaceId: APP_SPACE_ID, migrations: [] }] : scopedSpaces;\n\n return ok({\n ok: true,\n spaces: resultSpaces,\n summary: computeSummary(resultSpaces),\n });\n}\n\n/**\n * CLI shell: loads config, resolves paths, prints the styled header on\n * stderr (interactive mode only), and delegates to {@link runMigrationList}.\n * Kept intentionally thin so the unit-testable surface lives in the core.\n */\nexport async function executeMigrationListCommand(\n options: MigrationListOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationListResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, migrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration list',\n description: 'List on-disk migrations per contract space',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: migrationsRelative },\n ...(options.space !== undefined ? [{ label: 'space', value: options.space }] : []),\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n\n const spaces = await migrationSpaceListEntriesFromAggregate(\n loaded.value.aggregate,\n migrationsDir,\n );\n\n return runMigrationList({\n spaces,\n ...ifDefined('spaceFilter', options.space),\n });\n}\n\nexport function createMigrationListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(\n command,\n 'List on-disk migrations per contract space',\n 'Enumerates every on-disk migration under migrations/<space>/ for every\\n' +\n 'contract space found on disk. Offline — does not consult the database.\\n' +\n 'Human output draws the shared migration graph tree with operation counts,\\n' +\n 'invariants on each migration row, and refs on destination contract nodes.\\n' +\n 'Pass --space <id> to narrow to one contract space. --ascii forces ASCII\\n' +\n 'tree glyphs (orthogonal to --no-color).',\n );\n setCommandExamples(command, [\n 'prisma-next migration list',\n 'prisma-next migration list --space app',\n 'prisma-next migration list --ascii',\n 'prisma-next migration list --json',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--space <id>', 'Narrow output to a single contract space')\n .option('--ascii', 'Use ASCII kind glyphs (pipe-friendly)')\n .action(async (options: MigrationListOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationListCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (listResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(listResult, null, 2));\n } else if (!flags.quiet) {\n ui.output(\n renderMigrationListHumanOutput(listResult, {\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n useColor: ui.useColor,\n }),\n );\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -3,28 +3,16 @@ import { n as GlobalFlags, t as CommonCommandOptions } from "../global-flags-DG4
|
|
|
3
3
|
import { t as TerminalUI } from "../terminal-ui-C3xGyxW-.mjs";
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import { Result } from "@prisma-next/utils/result";
|
|
6
|
+
import { LedgerEntryRecord } from "@prisma-next/contract/types";
|
|
6
7
|
|
|
7
8
|
//#region src/commands/migration-log.d.ts
|
|
8
9
|
interface MigrationLogOptions extends CommonCommandOptions {
|
|
9
10
|
readonly db?: string;
|
|
10
11
|
readonly config?: string;
|
|
12
|
+
readonly utc?: boolean;
|
|
11
13
|
}
|
|
12
|
-
|
|
13
|
-
readonly dirName: string;
|
|
14
|
-
readonly from: string;
|
|
15
|
-
readonly to: string;
|
|
16
|
-
readonly migrationHash: string;
|
|
17
|
-
readonly operationCount: number;
|
|
18
|
-
readonly createdAt: string;
|
|
19
|
-
}
|
|
20
|
-
interface MigrationLogResult {
|
|
21
|
-
readonly ok: true;
|
|
22
|
-
readonly markerHash: string | null;
|
|
23
|
-
readonly applied: readonly MigrationLogEntry[];
|
|
24
|
-
readonly summary: string;
|
|
25
|
-
}
|
|
26
|
-
declare function executeMigrationLogCommand(options: MigrationLogOptions, flags: GlobalFlags, ui: TerminalUI): Promise<Result<MigrationLogResult, CliStructuredError>>;
|
|
14
|
+
declare function executeMigrationLogCommand(options: MigrationLogOptions, flags: GlobalFlags, ui: TerminalUI): Promise<Result<readonly LedgerEntryRecord[], CliStructuredError>>;
|
|
27
15
|
declare function createMigrationLogCommand(): Command;
|
|
28
16
|
//#endregion
|
|
29
|
-
export {
|
|
17
|
+
export { createMigrationLogCommand, executeMigrationLogCommand };
|
|
30
18
|
//# sourceMappingURL=migration-log.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":";;;;;;;;UAkCU,mBAAA,SAA4B,oBAAoB;EAAA,SAC/C,EAAA;EAAA,SACA,MAAA;EAAA,SACA,GAAA;AAAA;AAAA,iBAGW,0BAAA,CACpB,OAAA,EAAS,mBAAA,EACT,KAAA,EAAO,WAAA,EACP,EAAA,EAAI,UAAA,GACH,OAAA,CAAQ,MAAA,UAAgB,iBAAA,IAAqB,kBAAA;AAAA,iBA4DhC,yBAAA,CAAA,GAA6B,OAAO"}
|
|
@@ -1,138 +1,2 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { E as formatStyledHeader, I as errorDatabaseConnectionRequired, R as errorDriverRequired, _ as parseGlobalFlagsOrExit, b as handleResult, d as setCommandSeeAlso, f as targetSupportsMigrations, i as maskConnectionUrl, j as CliStructuredError, l as setCommandDescriptions, nt as errorUnexpected, rt as mapMigrationToolsError, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI } from "../command-helpers-Cmdqyhz9.mjs";
|
|
3
|
-
import { t as createControlClient } from "../client-Cdxcme1x.mjs";
|
|
4
|
-
import { r as buildReadAggregate } from "../contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
5
|
-
import { Command } from "commander";
|
|
6
|
-
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
|
-
import { cyan, dim } from "colorette";
|
|
8
|
-
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
9
|
-
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
10
|
-
import { findPath } from "@prisma-next/migration-tools/migration-graph";
|
|
11
|
-
//#region src/commands/migration-log.ts
|
|
12
|
-
async function executeMigrationLogCommand(options, flags, ui) {
|
|
13
|
-
const config = await loadConfig(options.config);
|
|
14
|
-
const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(options.config, config);
|
|
15
|
-
const dbConnection = options.db ?? config.db?.connection;
|
|
16
|
-
if (!dbConnection) return notOk(errorDatabaseConnectionRequired({
|
|
17
|
-
why: `Database connection is required for migration log (set db.connection in ${configPath}, or pass --db <url>)`,
|
|
18
|
-
commandName: "migration log"
|
|
19
|
-
}));
|
|
20
|
-
if (!config.driver) return notOk(errorDriverRequired({ why: "Config.driver is required for migration log" }));
|
|
21
|
-
if (!targetSupportsMigrations(config.target)) return notOk(errorUnexpected("Target does not support migrations"));
|
|
22
|
-
if (!flags.json && !flags.quiet) {
|
|
23
|
-
const header = formatStyledHeader({
|
|
24
|
-
command: "migration log",
|
|
25
|
-
description: "Show executed migration history",
|
|
26
|
-
details: [
|
|
27
|
-
{
|
|
28
|
-
label: "config",
|
|
29
|
-
value: configPath
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
label: "migrations",
|
|
33
|
-
value: appMigrationsRelative
|
|
34
|
-
},
|
|
35
|
-
...typeof dbConnection === "string" ? [{
|
|
36
|
-
label: "database",
|
|
37
|
-
value: maskConnectionUrl(dbConnection)
|
|
38
|
-
}] : []
|
|
39
|
-
],
|
|
40
|
-
flags
|
|
41
|
-
});
|
|
42
|
-
ui.stderr(header);
|
|
43
|
-
}
|
|
44
|
-
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
45
|
-
if (!loaded.ok) return loaded;
|
|
46
|
-
const graph = loaded.value.aggregate.app.graph();
|
|
47
|
-
const bundles = loaded.value.aggregate.app.packages;
|
|
48
|
-
const client = createControlClient({
|
|
49
|
-
family: config.family,
|
|
50
|
-
target: config.target,
|
|
51
|
-
adapter: config.adapter,
|
|
52
|
-
driver: config.driver,
|
|
53
|
-
extensionPacks: config.extensionPacks ?? []
|
|
54
|
-
});
|
|
55
|
-
try {
|
|
56
|
-
await client.connect(dbConnection);
|
|
57
|
-
const markerHash = (await client.readMarker())?.storageHash ?? null;
|
|
58
|
-
if (!markerHash) return ok({
|
|
59
|
-
ok: true,
|
|
60
|
-
markerHash: null,
|
|
61
|
-
applied: [],
|
|
62
|
-
summary: "No migrations applied (database has no marker)"
|
|
63
|
-
});
|
|
64
|
-
const appliedPath = findPath(graph, EMPTY_CONTRACT_HASH, markerHash);
|
|
65
|
-
if (appliedPath === null) return notOk(errorUnexpected("Database marker is not reachable from migration history", {
|
|
66
|
-
why: `Marker hash ${markerHash} is not reachable from the root of the on-disk migration graph.`,
|
|
67
|
-
fix: "The database may have been migrated outside this project. Use `migration status` to inspect the current state."
|
|
68
|
-
}));
|
|
69
|
-
const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));
|
|
70
|
-
const entries = appliedPath.map((edge) => {
|
|
71
|
-
const ops = pkgByDirName.get(edge.dirName)?.ops ?? [];
|
|
72
|
-
return {
|
|
73
|
-
dirName: edge.dirName,
|
|
74
|
-
from: edge.from,
|
|
75
|
-
to: edge.to,
|
|
76
|
-
migrationHash: edge.migrationHash,
|
|
77
|
-
operationCount: ops.length,
|
|
78
|
-
createdAt: edge.createdAt
|
|
79
|
-
};
|
|
80
|
-
});
|
|
81
|
-
return ok({
|
|
82
|
-
ok: true,
|
|
83
|
-
markerHash,
|
|
84
|
-
applied: entries,
|
|
85
|
-
summary: `${entries.length} migration(s) applied`
|
|
86
|
-
});
|
|
87
|
-
} catch (error) {
|
|
88
|
-
if (CliStructuredError.is(error)) return notOk(error);
|
|
89
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
90
|
-
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}` }));
|
|
91
|
-
} finally {
|
|
92
|
-
await client.close();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function createMigrationLogCommand() {
|
|
96
|
-
const command = new Command("log");
|
|
97
|
-
setCommandDescriptions(command, "Show executed migration history", "Reads the database marker and displays the applied migration chain\nfrom the initial state to the current marker position.");
|
|
98
|
-
setCommandExamples(command, ["prisma-next migration log --db $DATABASE_URL", "prisma-next migration log --json --db $DATABASE_URL"]);
|
|
99
|
-
setCommandSeeAlso(command, [
|
|
100
|
-
{
|
|
101
|
-
verb: "migration status",
|
|
102
|
-
oneLiner: "Show migration path and pending status"
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
verb: "migration list",
|
|
106
|
-
oneLiner: "List on-disk migrations"
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
verb: "migration graph",
|
|
110
|
-
oneLiner: "Show the migration graph topology"
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
verb: "migration show",
|
|
114
|
-
oneLiner: "Display migration package contents"
|
|
115
|
-
}
|
|
116
|
-
]);
|
|
117
|
-
addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
|
|
118
|
-
const flags = parseGlobalFlagsOrExit(options);
|
|
119
|
-
const ui = createTerminalUI(flags);
|
|
120
|
-
const exitCode = handleResult(await executeMigrationLogCommand(options, flags, ui), flags, ui, (logResult) => {
|
|
121
|
-
if (flags.json) ui.output(JSON.stringify(logResult, null, 2));
|
|
122
|
-
else if (!flags.quiet) {
|
|
123
|
-
const c = (fn, s) => flags.color !== false ? fn(s) : s;
|
|
124
|
-
if (logResult.applied.length === 0) ui.log(logResult.summary);
|
|
125
|
-
else {
|
|
126
|
-
for (const entry of logResult.applied) ui.log(`${c(cyan, "✓")} ${entry.dirName} ${c(dim, entry.migrationHash.slice(0, 16) + "…")} ${entry.operationCount} op(s)`);
|
|
127
|
-
ui.log(`\n${logResult.summary}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
process.exit(exitCode);
|
|
132
|
-
});
|
|
133
|
-
return command;
|
|
134
|
-
}
|
|
135
|
-
//#endregion
|
|
1
|
+
import { n as executeMigrationLogCommand, t as createMigrationLogCommand } from "../migration-log-BzPmks3c.mjs";
|
|
136
2
|
export { createMigrationLogCommand, executeMigrationLogCommand };
|
|
137
|
-
|
|
138
|
-
//# sourceMappingURL=migration-log.mjs.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { E as formatStyledHeader, F as errorContractValidationFailed, Z as errorRuntime, _ as parseGlobalFlagsOrExit, b as handleResult, d as setCommandSeeAlso, it as mapRefResolutionError, l as setCommandDescriptions, nt as errorUnexpected, o as resolveContractPath, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI, z as errorFileNotFound } from "../command-helpers-Cmdqyhz9.mjs";
|
|
3
|
-
import { t as createControlClient } from "../client-
|
|
3
|
+
import { t as createControlClient } from "../client-BHe8szOW.mjs";
|
|
4
4
|
import { a as formatMigrationShowOutput } from "../migrations-DQ1t3XFL.mjs";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { E as formatStyledHeader, Z as errorRuntime, _ as parseGlobalFlagsOrExit, a as readContractEnvelope, b as handleResult, d as setCommandSeeAlso, i as maskConnectionUrl, it as mapRefResolutionError, j as CliStructuredError, l as setCommandDescriptions, m as toStructuralEdge, n as collectDeclaredInvariants, nt as errorUnexpected, p as toPathDecisionResult, rt as mapMigrationToolsError, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI } from "../command-helpers-Cmdqyhz9.mjs";
|
|
3
|
-
import { t as createControlClient } from "../client-
|
|
3
|
+
import { t as createControlClient } from "../client-BHe8szOW.mjs";
|
|
4
4
|
import { t as toDeclaredExtensionsFromRaw } from "../extension-pack-inputs-IDvjRCi3.mjs";
|
|
5
5
|
import { i as loadContractRawSafely, o as refuseContractSpaceIntegrity, s as refusePackageCorruptionOnAggregate, t as appContractStandInFromIdentity } from "../contract-space-aggregate-loader-CirAEsM8.mjs";
|
|
6
6
|
import { i as migrationGraphToRenderInput, n as graphRenderer, r as isLinearGraph, t as extractRelevantSubgraph } from "../graph-render-rFAqZujX.mjs";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _ as parseGlobalFlagsOrExit, b as handleResult, l as setCommandDescriptions, t as addGlobalOptions, u as setCommandExamples, v as createTerminalUI } from "./command-helpers-Cmdqyhz9.mjs";
|
|
2
|
-
import { t as inspectLiveSchema } from "./inspect-live-schema-
|
|
2
|
+
import { t as inspectLiveSchema } from "./inspect-live-schema-DVZlDlnF.mjs";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
5
5
|
import { dirname, relative, resolve } from "pathe";
|
|
@@ -72,4 +72,4 @@ function createContractInferCommand() {
|
|
|
72
72
|
//#endregion
|
|
73
73
|
export { createContractInferCommand as t };
|
|
74
74
|
|
|
75
|
-
//# sourceMappingURL=contract-infer-
|
|
75
|
+
//# sourceMappingURL=contract-infer-OCn12Zvn.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-infer-
|
|
1
|
+
{"version":3,"file":"contract-infer-OCn12Zvn.mjs","names":[],"sources":["../src/commands/contract-infer-paths.ts","../src/commands/contract-infer.ts"],"sourcesContent":["import { dirname, resolve } from 'pathe';\n\ninterface ContractInferPathOptions {\n readonly output?: string;\n readonly config?: string;\n}\n\n/**\n * Resolves the output path for the inferred PSL contract.\n *\n * Priority:\n * 1. --output <path> flag (resolved relative to cwd)\n * 2. contract.prisma next to config.contract.output\n * 3. Canonical default: contract.prisma in the config directory\n */\nexport function resolveContractInferOutputPath(\n options: ContractInferPathOptions,\n contractOutput: string | undefined,\n): string {\n const configDir = options.config\n ? dirname(resolve(process.cwd(), options.config))\n : process.cwd();\n\n if (options.output) {\n return resolve(process.cwd(), options.output);\n }\n if (contractOutput) {\n const contractPath = resolve(configDir, contractOutput);\n return resolve(dirname(contractPath), 'contract.prisma');\n }\n return resolve(configDir, 'contract.prisma');\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { errorRuntime } from '@prisma-next/errors/execution';\nimport { printPsl } from '@prisma-next/psl-printer';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, relative } from 'pathe';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\nimport { resolveContractInferOutputPath } from './contract-infer-paths';\nimport {\n type InspectLiveSchemaOptions,\n type InspectLiveSchemaResult,\n inspectLiveSchema,\n} from './inspect-live-schema';\n\ninterface ContractInferOptions extends InspectLiveSchemaOptions {\n readonly output?: string;\n}\n\ninterface ContractInferSuccessResult {\n readonly ok: true;\n readonly summary: string;\n readonly target: InspectLiveSchemaResult['target'];\n readonly psl: {\n readonly path: string;\n };\n readonly meta: InspectLiveSchemaResult['meta'];\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeContractInferCommand(\n options: ContractInferOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<ContractInferSuccessResult, CliStructuredError>> {\n const inspectResult = await inspectLiveSchema(options, flags, ui, startTime, {\n commandName: 'contract infer',\n description: 'Infer a PSL contract from the live database schema',\n url: 'https://pris.ly/contract-infer',\n });\n\n if (!inspectResult.ok) {\n return inspectResult;\n }\n\n const { config, target, meta, pslContractAst } = inspectResult.value;\n\n if (!pslContractAst) {\n return notOk(\n errorRuntime('contract infer is not supported for this family', {\n why: 'The configured family does not implement the PslContractInferCapable capability, so an inferred PSL contract cannot be produced from the live database schema.',\n fix: 'Use a family that supports contract inference (e.g. SQL/Postgres).',\n }),\n );\n }\n\n const outputPath = resolveContractInferOutputPath(options, config.contract?.output);\n const pslContent = printPsl(pslContractAst);\n\n if (existsSync(outputPath) && !flags.json && !flags.quiet) {\n ui.stderr(`\\u26A0 Overwriting existing file: ${relative(process.cwd(), outputPath)}`);\n }\n\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, pslContent, 'utf-8');\n\n const pslPath = relative(process.cwd(), outputPath);\n if (!flags.json && !flags.quiet) {\n ui.stderr(`\\u2714 Contract written to ${pslPath}`);\n }\n\n return ok({\n ok: true,\n summary: 'Contract inferred successfully',\n target,\n psl: {\n path: pslPath,\n },\n meta,\n timings: {\n total: Date.now() - startTime,\n },\n });\n}\n\nexport function createContractInferCommand(): Command {\n const command = new Command('infer');\n setCommandDescriptions(\n command,\n 'Infer a PSL contract from the live database schema',\n 'Reads the live database schema and writes an inferred PSL contract to disk.\\n' +\n 'This command stops at `contract.prisma`; follow it with `contract emit` and\\n' +\n '`db sign` as separate steps.',\n );\n setCommandExamples(command, [\n 'prisma-next contract infer --db $DATABASE_URL',\n 'prisma-next contract infer --db $DATABASE_URL --output ./src/prisma/contract.prisma',\n 'prisma-next contract infer --db $DATABASE_URL --json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--output <path>', 'Write the inferred PSL contract to the specified path')\n .action(async (options: ContractInferOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const startTime = Date.now();\n\n const result = await executeContractInferCommand(options, flags, ui, startTime);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAeA,SAAgB,+BACd,SACA,gBACQ;CACR,MAAM,YAAY,QAAQ,SACtB,QAAQ,QAAQ,QAAQ,IAAI,GAAG,QAAQ,MAAM,CAAC,IAC9C,QAAQ,IAAI;CAEhB,IAAI,QAAQ,QACV,OAAO,QAAQ,QAAQ,IAAI,GAAG,QAAQ,MAAM;CAE9C,IAAI,gBAEF,OAAO,QAAQ,QADM,QAAQ,WAAW,cACN,CAAC,GAAG,iBAAiB;CAEzD,OAAO,QAAQ,WAAW,iBAAiB;AAC7C;;;ACQA,eAAe,4BACb,SACA,OACA,IACA,WACiE;CACjE,MAAM,gBAAgB,MAAM,kBAAkB,SAAS,OAAO,IAAI,WAAW;EAC3E,aAAa;EACb,aAAa;EACb,KAAK;CACP,CAAC;CAED,IAAI,CAAC,cAAc,IACjB,OAAO;CAGT,MAAM,EAAE,QAAQ,QAAQ,MAAM,mBAAmB,cAAc;CAE/D,IAAI,CAAC,gBACH,OAAO,MACL,aAAa,mDAAmD;EAC9D,KAAK;EACL,KAAK;CACP,CAAC,CACH;CAGF,MAAM,aAAa,+BAA+B,SAAS,OAAO,UAAU,MAAM;CAClF,MAAM,aAAa,SAAS,cAAc;CAE1C,IAAI,WAAW,UAAU,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,OAClD,GAAG,OAAO,qCAAqC,SAAS,QAAQ,IAAI,GAAG,UAAU,GAAG;CAGtF,UAAU,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;CAClD,cAAc,YAAY,YAAY,OAAO;CAE7C,MAAM,UAAU,SAAS,QAAQ,IAAI,GAAG,UAAU;CAClD,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OACxB,GAAG,OAAO,8BAA8B,SAAS;CAGnD,OAAO,GAAG;EACR,IAAI;EACJ,SAAS;EACT;EACA,KAAK,EACH,MAAM,QACR;EACA;EACA,SAAS,EACP,OAAO,KAAK,IAAI,IAAI,UACtB;CACF,CAAC;AACH;AAEA,SAAgB,6BAAsC;CACpD,MAAM,UAAU,IAAI,QAAQ,OAAO;CACnC,uBACE,SACA,sDACA,wLAGF;CACA,mBAAmB,SAAS;EAC1B;EACA;EACA;CACF,CAAC;CACD,iBAAiB,OAAO,EACrB,OAAO,cAAc,4BAA4B,EACjD,OAAO,mBAAmB,+BAA+B,EACzD,OAAO,mBAAmB,uDAAuD,EACjF,OAAO,OAAO,YAAkC;EAC/C,MAAM,QAAQ,uBAAuB,OAAO;EAC5C,MAAM,KAAK,iBAAiB,KAAK;EAIjC,MAAM,WAAW,aAAa,MADT,4BAA4B,SAAS,OAAO,IAF/C,KAAK,IAEsD,CAAC,GACxC,OAAO,KAAK,UAAU;GAC1D,IAAI,MAAM,MACR,GAAG,OAAO,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;EAE5C,CAAC;EAED,QAAQ,KAAK,QAAQ;CACvB,CAAC;CAEH,OAAO;AACT"}
|