@fragno-dev/cli 0.1.1 → 0.1.3
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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +24 -0
- package/dist/cli.d.ts +33 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +212 -227
- package/dist/cli.js.map +1 -1
- package/package.json +3 -3
- package/src/cli.ts +12 -80
- package/src/commands/db/generate.ts +164 -157
- package/src/commands/db/info.ts +161 -76
- package/src/commands/db/migrate.ts +116 -114
- package/.turbo/turbo-types$colon$check.log +0 -1
package/src/commands/db/info.ts
CHANGED
|
@@ -1,93 +1,178 @@
|
|
|
1
|
-
import { isFragnoDatabase, type FragnoDatabase } from "@fragno-dev/db";
|
|
2
|
-
import type { AnySchema } from "@fragno-dev/db/schema";
|
|
3
1
|
import { resolve } from "node:path";
|
|
4
|
-
import
|
|
2
|
+
import { define } from "gunshi";
|
|
3
|
+
import { findFragnoDatabases } from "../../utils/find-fragno-databases";
|
|
4
|
+
import type { FragnoDatabase } from "@fragno-dev/db";
|
|
5
|
+
import type { AnySchema } from "@fragno-dev/db/schema";
|
|
5
6
|
|
|
6
|
-
export
|
|
7
|
-
|
|
7
|
+
export const infoCommand = define({
|
|
8
|
+
name: "info",
|
|
9
|
+
description: "Display database information and migration status",
|
|
10
|
+
args: {},
|
|
11
|
+
run: async (ctx) => {
|
|
12
|
+
const targets = ctx.positionals;
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
if (targets.length === 0) {
|
|
15
|
+
throw new Error("At least one target file path is required");
|
|
16
|
+
}
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
// De-duplicate targets (in case same file was specified multiple times)
|
|
19
|
+
const uniqueTargets = Array.from(new Set(targets));
|
|
20
|
+
|
|
21
|
+
// Load all target files and collect FragnoDatabase instances
|
|
22
|
+
const allFragnoDatabases: FragnoDatabase<AnySchema>[] = [];
|
|
23
|
+
|
|
24
|
+
for (const target of uniqueTargets) {
|
|
25
|
+
const targetPath = resolve(process.cwd(), target);
|
|
26
|
+
console.log(`Loading target file: ${targetPath}`);
|
|
27
|
+
|
|
28
|
+
// Dynamically import the target file
|
|
29
|
+
let targetModule: Record<string, unknown>;
|
|
30
|
+
try {
|
|
31
|
+
targetModule = await import(targetPath);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Failed to import target file ${target}: ${error instanceof Error ? error.message : String(error)}`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Find all FragnoDatabase instances or instantiated fragments with databases
|
|
39
|
+
const fragnoDatabases = findFragnoDatabases(targetModule);
|
|
40
|
+
|
|
41
|
+
if (fragnoDatabases.length === 0) {
|
|
42
|
+
console.warn(
|
|
43
|
+
`Warning: No FragnoDatabase instances found in ${target}.\n` +
|
|
44
|
+
`Make sure you export either:\n` +
|
|
45
|
+
` - A FragnoDatabase instance created with .create(adapter)\n` +
|
|
46
|
+
` - An instantiated fragment with embedded database definition\n`,
|
|
47
|
+
);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (fragnoDatabases.length > 1) {
|
|
52
|
+
console.warn(
|
|
53
|
+
`Warning: Multiple FragnoDatabase instances found in ${target} (${fragnoDatabases.length}). Showing info for all of them.`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
allFragnoDatabases.push(...fragnoDatabases);
|
|
58
|
+
}
|
|
15
59
|
|
|
16
|
-
|
|
60
|
+
if (allFragnoDatabases.length === 0) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`No FragnoDatabase instances found in any of the target files.\n` +
|
|
63
|
+
`Make sure your files export either:\n` +
|
|
64
|
+
` - A FragnoDatabase instance created with .create(adapter)\n` +
|
|
65
|
+
` - An instantiated fragment with embedded database definition\n`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
17
68
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
69
|
+
// Collect database information
|
|
70
|
+
const dbInfos = await Promise.all(
|
|
71
|
+
allFragnoDatabases.map(async (fragnoDb) => {
|
|
72
|
+
const info: {
|
|
73
|
+
namespace: string;
|
|
74
|
+
schemaVersion: number;
|
|
75
|
+
migrationSupport: boolean;
|
|
76
|
+
currentVersion?: number;
|
|
77
|
+
pendingVersions?: number;
|
|
78
|
+
status?: string;
|
|
79
|
+
error?: string;
|
|
80
|
+
} = {
|
|
81
|
+
namespace: fragnoDb.namespace,
|
|
82
|
+
schemaVersion: fragnoDb.schema.version,
|
|
83
|
+
migrationSupport: !!fragnoDb.adapter.createMigrationEngine,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Get current database version if migrations are supported
|
|
87
|
+
if (fragnoDb.adapter.createMigrationEngine) {
|
|
88
|
+
try {
|
|
89
|
+
const migrator = fragnoDb.adapter.createMigrationEngine(
|
|
90
|
+
fragnoDb.schema,
|
|
91
|
+
fragnoDb.namespace,
|
|
92
|
+
);
|
|
93
|
+
const currentVersion = await migrator.getVersion();
|
|
94
|
+
info.currentVersion = currentVersion;
|
|
95
|
+
info.pendingVersions = fragnoDb.schema.version - currentVersion;
|
|
96
|
+
|
|
97
|
+
if (info.pendingVersions > 0) {
|
|
98
|
+
info.status = `Pending (${info.pendingVersions} migration(s))`;
|
|
99
|
+
} else if (info.pendingVersions === 0) {
|
|
100
|
+
info.status = "Up to date";
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
info.error = error instanceof Error ? error.message : String(error);
|
|
104
|
+
info.status = "Error";
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
info.status = "Schema only";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return info;
|
|
111
|
+
}),
|
|
25
112
|
);
|
|
26
|
-
}
|
|
27
113
|
|
|
28
|
-
|
|
29
|
-
|
|
114
|
+
// Determine if any database supports migrations
|
|
115
|
+
const hasMigrationSupport = dbInfos.some((info) => info.migrationSupport);
|
|
30
116
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
117
|
+
// Print compact table
|
|
118
|
+
console.log("");
|
|
119
|
+
console.log(
|
|
120
|
+
`Found ${allFragnoDatabases.length} database(s) across ${uniqueTargets.length} file(s):`,
|
|
121
|
+
);
|
|
122
|
+
console.log("");
|
|
37
123
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
124
|
+
// Table header
|
|
125
|
+
const namespaceHeader = "Namespace";
|
|
126
|
+
const versionHeader = "Schema";
|
|
127
|
+
const currentHeader = "Current";
|
|
128
|
+
const statusHeader = "Status";
|
|
41
129
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
130
|
+
const maxNamespaceLen = Math.max(
|
|
131
|
+
namespaceHeader.length,
|
|
132
|
+
...dbInfos.map((info) => info.namespace.length),
|
|
45
133
|
);
|
|
46
|
-
|
|
134
|
+
const namespaceWidth = Math.max(maxNamespaceLen + 2, 20);
|
|
135
|
+
const versionWidth = 8;
|
|
136
|
+
const currentWidth = 9;
|
|
137
|
+
const statusWidth = 25;
|
|
47
138
|
|
|
48
|
-
|
|
49
|
-
|
|
139
|
+
// Print table
|
|
140
|
+
console.log(
|
|
141
|
+
namespaceHeader.padEnd(namespaceWidth) +
|
|
142
|
+
versionHeader.padEnd(versionWidth) +
|
|
143
|
+
(hasMigrationSupport ? currentHeader.padEnd(currentWidth) : "") +
|
|
144
|
+
statusHeader,
|
|
145
|
+
);
|
|
146
|
+
console.log(
|
|
147
|
+
"-".repeat(namespaceWidth) +
|
|
148
|
+
"-".repeat(versionWidth) +
|
|
149
|
+
(hasMigrationSupport ? "-".repeat(currentWidth) : "") +
|
|
150
|
+
"-".repeat(statusWidth),
|
|
151
|
+
);
|
|
50
152
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
153
|
+
for (const info of dbInfos) {
|
|
154
|
+
const currentVersionStr =
|
|
155
|
+
info.currentVersion !== undefined ? String(info.currentVersion) : "-";
|
|
156
|
+
console.log(
|
|
157
|
+
info.namespace.padEnd(namespaceWidth) +
|
|
158
|
+
String(info.schemaVersion).padEnd(versionWidth) +
|
|
159
|
+
(hasMigrationSupport ? currentVersionStr.padEnd(currentWidth) : "") +
|
|
160
|
+
(info.status || "-"),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
56
163
|
|
|
57
|
-
|
|
58
|
-
if (!fragnoDb.adapter.createMigrationEngine) {
|
|
59
|
-
console.log(`Migration Support: No`);
|
|
164
|
+
// Print help text
|
|
60
165
|
console.log("");
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const currentVersion = await migrator.getVersion();
|
|
72
|
-
|
|
73
|
-
console.log(`Current Database Version: ${currentVersion}`);
|
|
74
|
-
|
|
75
|
-
// Check if migrations are pending
|
|
76
|
-
const pendingVersions = fragnoDb.schema.version - currentVersion;
|
|
77
|
-
if (pendingVersions > 0) {
|
|
78
|
-
console.log("");
|
|
79
|
-
console.log(`⚠ Pending Migrations: ${pendingVersions} version(s) behind`);
|
|
80
|
-
console.log(` Run '@fragno-dev/cli db migrate --target ${target}' to update`);
|
|
81
|
-
} else if (pendingVersions === 0) {
|
|
82
|
-
console.log("");
|
|
83
|
-
console.log(`✓ Database is up to date`);
|
|
166
|
+
if (!hasMigrationSupport) {
|
|
167
|
+
console.log("Note: These adapters do not support migrations.");
|
|
168
|
+
console.log("Use '@fragno-dev/cli db generate' to generate schema files.");
|
|
169
|
+
} else {
|
|
170
|
+
const hasPendingMigrations = dbInfos.some(
|
|
171
|
+
(info) => info.pendingVersions && info.pendingVersions > 0,
|
|
172
|
+
);
|
|
173
|
+
if (hasPendingMigrations) {
|
|
174
|
+
console.log("Run '@fragno-dev/cli db migrate <target>' to apply pending migrations.");
|
|
175
|
+
}
|
|
84
176
|
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
console.log(
|
|
88
|
-
`Warning: Could not retrieve current version: ${error instanceof Error ? error.message : String(error)}`,
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log("=".repeat(50));
|
|
93
|
-
}
|
|
177
|
+
},
|
|
178
|
+
});
|
|
@@ -1,131 +1,133 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
-
import
|
|
2
|
+
import { define } from "gunshi";
|
|
3
3
|
import { findFragnoDatabases } from "../../utils/find-fragno-databases";
|
|
4
|
+
import { type FragnoDatabase } from "@fragno-dev/db";
|
|
5
|
+
import { executeMigrations, type ExecuteMigrationResult } from "@fragno-dev/db/generation-engine";
|
|
6
|
+
import type { AnySchema } from "@fragno-dev/db/schema";
|
|
7
|
+
|
|
8
|
+
export const migrateCommand = define({
|
|
9
|
+
name: "migrate",
|
|
10
|
+
description: "Run database migrations for all fragments to their latest versions",
|
|
11
|
+
args: {},
|
|
12
|
+
run: async (ctx) => {
|
|
13
|
+
const targets = ctx.positionals;
|
|
14
|
+
|
|
15
|
+
if (targets.length === 0) {
|
|
16
|
+
throw new Error("At least one target file path is required");
|
|
17
|
+
}
|
|
4
18
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const version = ctx.values["to"];
|
|
8
|
-
const fromVersion = ctx.values["from"];
|
|
9
|
-
|
|
10
|
-
if (!target || typeof target !== "string") {
|
|
11
|
-
throw new Error("Target file path is required and must be a string");
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (version !== undefined && typeof version !== "string" && typeof version !== "number") {
|
|
15
|
-
throw new Error("Version must be a number or string");
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
fromVersion !== undefined &&
|
|
20
|
-
typeof fromVersion !== "string" &&
|
|
21
|
-
typeof fromVersion !== "number"
|
|
22
|
-
) {
|
|
23
|
-
throw new Error("Version must be a number or string");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Resolve the target file path relative to current working directory
|
|
27
|
-
const targetPath = resolve(process.cwd(), target);
|
|
28
|
-
|
|
29
|
-
console.log(`Loading target file: ${targetPath}`);
|
|
30
|
-
|
|
31
|
-
// Dynamically import the target file
|
|
32
|
-
let targetModule: Record<string, unknown>;
|
|
33
|
-
try {
|
|
34
|
-
targetModule = await import(targetPath);
|
|
35
|
-
} catch (error) {
|
|
36
|
-
throw new Error(
|
|
37
|
-
`Failed to import target file: ${error instanceof Error ? error.message : String(error)}`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
19
|
+
// De-duplicate targets
|
|
20
|
+
const uniqueTargets = Array.from(new Set(targets));
|
|
40
21
|
|
|
41
|
-
|
|
42
|
-
|
|
22
|
+
// Load all target files and collect FragnoDatabase instances
|
|
23
|
+
const allFragnoDatabases: FragnoDatabase<AnySchema>[] = [];
|
|
43
24
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
`
|
|
47
|
-
`Make sure you export either:\n` +
|
|
48
|
-
` - A FragnoDatabase instance created with .create(adapter)\n` +
|
|
49
|
-
` - An instantiated fragment with embedded database definition\n`,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
25
|
+
for (const target of uniqueTargets) {
|
|
26
|
+
const targetPath = resolve(process.cwd(), target);
|
|
27
|
+
console.log(`Loading target file: ${targetPath}`);
|
|
52
28
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
29
|
+
// Dynamically import the target file
|
|
30
|
+
let targetModule: Record<string, unknown>;
|
|
31
|
+
try {
|
|
32
|
+
targetModule = await import(targetPath);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Failed to import target file ${target}: ${error instanceof Error ? error.message : String(error)}`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
58
38
|
|
|
59
|
-
|
|
60
|
-
|
|
39
|
+
// Find all FragnoDatabase instances or instantiated fragments with databases
|
|
40
|
+
const fragnoDatabases = findFragnoDatabases(targetModule);
|
|
61
41
|
|
|
62
|
-
|
|
42
|
+
if (fragnoDatabases.length === 0) {
|
|
43
|
+
console.warn(
|
|
44
|
+
`Warning: No FragnoDatabase instances found in ${target}.\n` +
|
|
45
|
+
`Make sure you export either:\n` +
|
|
46
|
+
` - A FragnoDatabase instance created with .create(adapter)\n` +
|
|
47
|
+
` - An instantiated fragment with embedded database definition\n`,
|
|
48
|
+
);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
63
51
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
`Adapter does not support running migrations. The adapter only supports schema generation.\n` +
|
|
68
|
-
`Try using 'fragno db generate' instead to generate schema files.`,
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Parse versions if provided
|
|
73
|
-
const targetVersion = version !== undefined ? parseInt(String(version), 10) : undefined;
|
|
74
|
-
const expectedFromVersion =
|
|
75
|
-
fromVersion !== undefined ? parseInt(String(fromVersion), 10) : undefined;
|
|
76
|
-
|
|
77
|
-
if (targetVersion !== undefined && isNaN(targetVersion)) {
|
|
78
|
-
throw new Error(`Invalid version number: ${version}`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (expectedFromVersion !== undefined && isNaN(expectedFromVersion)) {
|
|
82
|
-
throw new Error(`Invalid version number: ${fromVersion}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Run migrations
|
|
86
|
-
let didMigrate: boolean;
|
|
87
|
-
try {
|
|
88
|
-
if (targetVersion !== undefined) {
|
|
89
|
-
console.log(`Migrating to version ${targetVersion}...`);
|
|
90
|
-
const migrator = fragnoDb.adapter.createMigrationEngine(fragnoDb.schema, fragnoDb.namespace);
|
|
91
|
-
const currentVersion = await migrator.getVersion();
|
|
92
|
-
console.log(`Current version: ${currentVersion}`);
|
|
93
|
-
|
|
94
|
-
// Validate from version if provided
|
|
95
|
-
if (expectedFromVersion !== undefined && currentVersion !== expectedFromVersion) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`Current database version (${currentVersion}) does not match expected --from version (${expectedFromVersion})`,
|
|
52
|
+
if (fragnoDatabases.length > 1) {
|
|
53
|
+
console.warn(
|
|
54
|
+
`Warning: Multiple FragnoDatabase instances found in ${target} (${fragnoDatabases.length}). Using all of them.`,
|
|
98
55
|
);
|
|
99
56
|
}
|
|
100
57
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
58
|
+
allFragnoDatabases.push(...fragnoDatabases);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (allFragnoDatabases.length === 0) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`No FragnoDatabase instances found in any of the target files.\n` +
|
|
64
|
+
`Make sure your files export either:\n` +
|
|
65
|
+
` - A FragnoDatabase instance created with .create(adapter)\n` +
|
|
66
|
+
` - An instantiated fragment with embedded database definition\n`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log(
|
|
71
|
+
`Found ${allFragnoDatabases.length} FragnoDatabase instance(s) across ${uniqueTargets.length} file(s)`,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Validate all databases use the same adapter object (identity)
|
|
75
|
+
const firstDb = allFragnoDatabases[0];
|
|
76
|
+
const firstAdapter = firstDb.adapter;
|
|
77
|
+
const allSameAdapter = allFragnoDatabases.every((db) => db.adapter === firstAdapter);
|
|
78
|
+
|
|
79
|
+
if (!allSameAdapter) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
"All fragments must use the same database adapter instance. Mixed adapters are not supported.",
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log("\nMigrating all fragments to their latest versions...\n");
|
|
104
86
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
87
|
+
let results: ExecuteMigrationResult[];
|
|
88
|
+
try {
|
|
89
|
+
results = await executeMigrations(allFragnoDatabases);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Migration failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Display progress for each result
|
|
97
|
+
for (const result of results) {
|
|
98
|
+
console.log(`Fragment: ${result.namespace}`);
|
|
99
|
+
console.log(` Current version: ${result.fromVersion}`);
|
|
100
|
+
console.log(` Target version: ${result.toVersion}`);
|
|
101
|
+
|
|
102
|
+
if (result.didMigrate) {
|
|
103
|
+
console.log(` ✓ Migration completed: v${result.fromVersion} → v${result.toVersion}\n`);
|
|
108
104
|
} else {
|
|
109
|
-
|
|
110
|
-
didMigrate = true;
|
|
105
|
+
console.log(` ✓ Already at latest version. No migration needed.\n`);
|
|
111
106
|
}
|
|
112
|
-
} else {
|
|
113
|
-
console.log(`Migrating to latest version (${fragnoDb.schema.version})...`);
|
|
114
|
-
didMigrate = await fragnoDb.runMigrations();
|
|
115
107
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (
|
|
126
|
-
console.log(
|
|
127
|
-
|
|
128
|
-
|
|
108
|
+
|
|
109
|
+
// Summary
|
|
110
|
+
console.log("═══════════════════════════════════════");
|
|
111
|
+
console.log("Migration Summary");
|
|
112
|
+
console.log("═══════════════════════════════════════");
|
|
113
|
+
|
|
114
|
+
const migrated = results.filter((r) => r.didMigrate);
|
|
115
|
+
const skipped = results.filter((r) => !r.didMigrate);
|
|
116
|
+
|
|
117
|
+
if (migrated.length > 0) {
|
|
118
|
+
console.log(`\n✓ Migrated ${migrated.length} fragment(s):`);
|
|
119
|
+
for (const r of migrated) {
|
|
120
|
+
console.log(` - ${r.namespace}: v${r.fromVersion} → v${r.toVersion}`);
|
|
121
|
+
}
|
|
129
122
|
}
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
|
|
124
|
+
if (skipped.length > 0) {
|
|
125
|
+
console.log(`\n○ Skipped ${skipped.length} fragment(s) (already up-to-date):`);
|
|
126
|
+
for (const r of skipped) {
|
|
127
|
+
console.log(` - ${r.namespace}: v${r.toVersion}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log("\n✓ All migrations completed successfully");
|
|
132
|
+
},
|
|
133
|
+
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
$ tsc --noEmit
|