pocketbase-zod-schema 0.1.3 → 0.2.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/CHANGELOG.md +14 -0
- package/README.md +233 -98
- package/dist/cli/index.cjs +449 -108
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +447 -106
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +452 -111
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +447 -106
- package/dist/cli/migrate.js.map +1 -1
- package/dist/index.cjs +593 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +583 -172
- package/dist/index.js.map +1 -1
- package/dist/migration/analyzer.cjs +44 -6
- package/dist/migration/analyzer.cjs.map +1 -1
- package/dist/migration/analyzer.d.cts +11 -1
- package/dist/migration/analyzer.d.ts +11 -1
- package/dist/migration/analyzer.js +44 -7
- package/dist/migration/analyzer.js.map +1 -1
- package/dist/migration/diff.cjs +21 -3
- package/dist/migration/diff.cjs.map +1 -1
- package/dist/migration/diff.js +21 -3
- package/dist/migration/diff.js.map +1 -1
- package/dist/migration/index.cjs +500 -129
- package/dist/migration/index.cjs.map +1 -1
- package/dist/migration/index.d.cts +1 -1
- package/dist/migration/index.d.ts +1 -1
- package/dist/migration/index.js +499 -129
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/snapshot.cjs +432 -118
- package/dist/migration/snapshot.cjs.map +1 -1
- package/dist/migration/snapshot.d.cts +34 -12
- package/dist/migration/snapshot.d.ts +34 -12
- package/dist/migration/snapshot.js +430 -117
- package/dist/migration/snapshot.js.map +1 -1
- package/dist/mutator.cjs +20 -21
- package/dist/mutator.cjs.map +1 -1
- package/dist/mutator.d.cts +4 -4
- package/dist/mutator.d.ts +4 -4
- package/dist/mutator.js +20 -21
- package/dist/mutator.js.map +1 -1
- package/dist/schema.cjs +69 -10
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +98 -8
- package/dist/schema.d.ts +98 -8
- package/dist/schema.js +62 -9
- package/dist/schema.js.map +1 -1
- package/dist/types.d.cts +5 -2
- package/dist/types.d.ts +5 -2
- package/dist/user-DTJQIj4K.d.cts +149 -0
- package/dist/user-DTJQIj4K.d.ts +149 -0
- package/package.json +3 -3
- package/dist/user-C39DQ40N.d.cts +0 -53
- package/dist/user-C39DQ40N.d.ts +0 -53
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import * as
|
|
1
|
+
import * as path5 from 'path';
|
|
2
|
+
import * as fs5 from 'fs';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import ora from 'ora';
|
|
@@ -132,10 +132,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
132
132
|
operation;
|
|
133
133
|
code;
|
|
134
134
|
originalError;
|
|
135
|
-
constructor(message,
|
|
135
|
+
constructor(message, path7, operation, code, originalError) {
|
|
136
136
|
super(message);
|
|
137
137
|
this.name = "FileSystemError";
|
|
138
|
-
this.path =
|
|
138
|
+
this.path = path7;
|
|
139
139
|
this.operation = operation;
|
|
140
140
|
this.code = code;
|
|
141
141
|
this.originalError = originalError;
|
|
@@ -1049,6 +1049,16 @@ function isFieldRequired(zodType) {
|
|
|
1049
1049
|
}
|
|
1050
1050
|
|
|
1051
1051
|
// src/migration/analyzer.ts
|
|
1052
|
+
var tsxLoaderRegistered = false;
|
|
1053
|
+
async function ensureTsxLoader() {
|
|
1054
|
+
if (tsxLoaderRegistered) return;
|
|
1055
|
+
try {
|
|
1056
|
+
await import('tsx/esm');
|
|
1057
|
+
tsxLoaderRegistered = true;
|
|
1058
|
+
} catch {
|
|
1059
|
+
tsxLoaderRegistered = false;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1052
1062
|
var DEFAULT_CONFIG = {
|
|
1053
1063
|
workspaceRoot: process.cwd(),
|
|
1054
1064
|
excludePatterns: [
|
|
@@ -1076,20 +1086,20 @@ function mergeConfig(config) {
|
|
|
1076
1086
|
}
|
|
1077
1087
|
function resolveSchemaDir(config) {
|
|
1078
1088
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1079
|
-
if (
|
|
1089
|
+
if (path5.isAbsolute(config.schemaDir)) {
|
|
1080
1090
|
return config.schemaDir;
|
|
1081
1091
|
}
|
|
1082
|
-
return
|
|
1092
|
+
return path5.join(workspaceRoot, config.schemaDir);
|
|
1083
1093
|
}
|
|
1084
1094
|
function discoverSchemaFiles(config) {
|
|
1085
1095
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1086
1096
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1087
1097
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1088
1098
|
try {
|
|
1089
|
-
if (!
|
|
1099
|
+
if (!fs5.existsSync(schemaDir)) {
|
|
1090
1100
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1091
1101
|
}
|
|
1092
|
-
const files =
|
|
1102
|
+
const files = fs5.readdirSync(schemaDir);
|
|
1093
1103
|
const schemaFiles = files.filter((file) => {
|
|
1094
1104
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1095
1105
|
if (!hasValidExtension) return false;
|
|
@@ -1105,7 +1115,7 @@ function discoverSchemaFiles(config) {
|
|
|
1105
1115
|
});
|
|
1106
1116
|
return schemaFiles.map((file) => {
|
|
1107
1117
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1108
|
-
return
|
|
1118
|
+
return path5.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1109
1119
|
});
|
|
1110
1120
|
} catch (error) {
|
|
1111
1121
|
if (error instanceof FileSystemError) {
|
|
@@ -1139,40 +1149,66 @@ async function importSchemaModule(filePath, config) {
|
|
|
1139
1149
|
let resolvedPath = null;
|
|
1140
1150
|
const jsPath = `${importPath}.js`;
|
|
1141
1151
|
const tsPath = `${importPath}.ts`;
|
|
1142
|
-
if (
|
|
1152
|
+
if (fs5.existsSync(jsPath)) {
|
|
1143
1153
|
resolvedPath = jsPath;
|
|
1144
|
-
} else if (
|
|
1154
|
+
} else if (fs5.existsSync(tsPath)) {
|
|
1145
1155
|
resolvedPath = tsPath;
|
|
1146
1156
|
} else {
|
|
1147
1157
|
resolvedPath = jsPath;
|
|
1148
1158
|
}
|
|
1149
|
-
|
|
1159
|
+
if (resolvedPath.endsWith(".ts")) {
|
|
1160
|
+
await ensureTsxLoader();
|
|
1161
|
+
if (!tsxLoaderRegistered) {
|
|
1162
|
+
throw new SchemaParsingError(
|
|
1163
|
+
`Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
|
|
1164
|
+
Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
|
|
1165
|
+
Alternatively, compile your schema files to JavaScript first.`,
|
|
1166
|
+
filePath
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
const fileUrl = new URL(`file://${path5.resolve(resolvedPath)}`);
|
|
1150
1171
|
const module = await import(fileUrl.href);
|
|
1151
1172
|
return module;
|
|
1152
1173
|
} catch (error) {
|
|
1153
1174
|
const tsPath = `${filePath}.ts`;
|
|
1154
|
-
const isTypeScriptFile =
|
|
1175
|
+
const isTypeScriptFile = fs5.existsSync(tsPath);
|
|
1176
|
+
if (isTypeScriptFile && error instanceof SchemaParsingError) {
|
|
1177
|
+
throw error;
|
|
1178
|
+
}
|
|
1155
1179
|
if (isTypeScriptFile) {
|
|
1156
1180
|
throw new SchemaParsingError(
|
|
1157
|
-
`Failed to import TypeScript schema file.
|
|
1158
|
-
Please
|
|
1159
|
-
|
|
1160
|
-
2. Use tsx to run the migration tool (e.g., "npx tsx package/dist/cli/migrate.js status" or "tsx package/dist/cli/migrate.js status")`,
|
|
1181
|
+
`Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
|
|
1182
|
+
Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
|
|
1183
|
+
Alternatively, compile your schema files to JavaScript first.`,
|
|
1161
1184
|
filePath,
|
|
1162
1185
|
error
|
|
1163
1186
|
);
|
|
1164
1187
|
}
|
|
1165
1188
|
throw new SchemaParsingError(
|
|
1166
|
-
`Failed to import schema module. Make sure the schema files
|
|
1189
|
+
`Failed to import schema module. Make sure the schema files exist and are valid.`,
|
|
1167
1190
|
filePath,
|
|
1168
1191
|
error
|
|
1169
1192
|
);
|
|
1170
1193
|
}
|
|
1171
1194
|
}
|
|
1172
1195
|
function getCollectionNameFromFile(filePath) {
|
|
1173
|
-
const filename =
|
|
1196
|
+
const filename = path5.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
1174
1197
|
return toCollectionName(filename);
|
|
1175
1198
|
}
|
|
1199
|
+
function extractCollectionNameFromSchema(zodSchema) {
|
|
1200
|
+
if (!zodSchema.description) {
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
try {
|
|
1204
|
+
const metadata = JSON.parse(zodSchema.description);
|
|
1205
|
+
if (metadata.collectionName && typeof metadata.collectionName === "string") {
|
|
1206
|
+
return metadata.collectionName;
|
|
1207
|
+
}
|
|
1208
|
+
} catch {
|
|
1209
|
+
}
|
|
1210
|
+
return null;
|
|
1211
|
+
}
|
|
1176
1212
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
1177
1213
|
const result = {};
|
|
1178
1214
|
for (const [key, value] of Object.entries(module)) {
|
|
@@ -1335,7 +1371,7 @@ async function buildSchemaDefinition(config) {
|
|
|
1335
1371
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
1336
1372
|
} else if (mergedConfig.useCompiledFiles) {
|
|
1337
1373
|
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
1338
|
-
if (
|
|
1374
|
+
if (fs5.existsSync(`${distPath}.js`) || fs5.existsSync(`${distPath}.mjs`)) {
|
|
1339
1375
|
importPath = distPath;
|
|
1340
1376
|
} else {
|
|
1341
1377
|
importPath = filePath;
|
|
@@ -1348,7 +1384,8 @@ async function buildSchemaDefinition(config) {
|
|
|
1348
1384
|
console.warn(`No valid schema found in ${filePath}, skipping...`);
|
|
1349
1385
|
continue;
|
|
1350
1386
|
}
|
|
1351
|
-
const
|
|
1387
|
+
const collectionNameFromSchema = extractCollectionNameFromSchema(zodSchema);
|
|
1388
|
+
const collectionName = collectionNameFromSchema ?? getCollectionNameFromFile(filePath);
|
|
1352
1389
|
const collectionSchema = convertZodSchemaToCollectionSchema(collectionName, zodSchema);
|
|
1353
1390
|
collections.set(collectionName, collectionSchema);
|
|
1354
1391
|
} catch (error) {
|
|
@@ -1512,6 +1549,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
1512
1549
|
for (const key of allKeys) {
|
|
1513
1550
|
const currentValue = currentOptions[key];
|
|
1514
1551
|
const previousValue = previousOptions[key];
|
|
1552
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1515
1555
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
1516
1556
|
changes.push({
|
|
1517
1557
|
property: `options.${key}`,
|
|
@@ -1532,11 +1572,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1532
1572
|
if (!currentRelation || !previousRelation) {
|
|
1533
1573
|
return changes;
|
|
1534
1574
|
}
|
|
1535
|
-
|
|
1575
|
+
const normalizeCollection = (collection) => {
|
|
1576
|
+
if (!collection) return collection;
|
|
1577
|
+
if (collection === "_pb_users_auth_") {
|
|
1578
|
+
return "Users";
|
|
1579
|
+
}
|
|
1580
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1581
|
+
if (nameMatch) {
|
|
1582
|
+
return nameMatch[1];
|
|
1583
|
+
}
|
|
1584
|
+
return collection;
|
|
1585
|
+
};
|
|
1586
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
1587
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
1588
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
1536
1589
|
changes.push({
|
|
1537
1590
|
property: "relation.collection",
|
|
1538
|
-
oldValue:
|
|
1539
|
-
|
|
1591
|
+
oldValue: normalizedPrevious,
|
|
1592
|
+
// Use normalized value for clarity
|
|
1593
|
+
newValue: normalizedCurrent
|
|
1594
|
+
// Use normalized value for clarity
|
|
1540
1595
|
});
|
|
1541
1596
|
}
|
|
1542
1597
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -1756,10 +1811,10 @@ function mergeConfig3(config) {
|
|
|
1756
1811
|
}
|
|
1757
1812
|
function resolveMigrationDir(config) {
|
|
1758
1813
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1759
|
-
if (
|
|
1814
|
+
if (path5.isAbsolute(config.migrationDir)) {
|
|
1760
1815
|
return config.migrationDir;
|
|
1761
1816
|
}
|
|
1762
|
-
return
|
|
1817
|
+
return path5.join(workspaceRoot, config.migrationDir);
|
|
1763
1818
|
}
|
|
1764
1819
|
function generateTimestamp(config) {
|
|
1765
1820
|
if (config?.timestampGenerator) {
|
|
@@ -1817,9 +1872,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
1817
1872
|
}
|
|
1818
1873
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
1819
1874
|
try {
|
|
1820
|
-
if (!
|
|
1875
|
+
if (!fs5.existsSync(migrationDir)) {
|
|
1821
1876
|
try {
|
|
1822
|
-
|
|
1877
|
+
fs5.mkdirSync(migrationDir, { recursive: true });
|
|
1823
1878
|
} catch (error) {
|
|
1824
1879
|
const fsError = error;
|
|
1825
1880
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -1840,15 +1895,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
1840
1895
|
);
|
|
1841
1896
|
}
|
|
1842
1897
|
}
|
|
1843
|
-
const filePath =
|
|
1844
|
-
|
|
1898
|
+
const filePath = path5.join(migrationDir, filename);
|
|
1899
|
+
fs5.writeFileSync(filePath, content, "utf-8");
|
|
1845
1900
|
return filePath;
|
|
1846
1901
|
} catch (error) {
|
|
1847
1902
|
if (error instanceof FileSystemError) {
|
|
1848
1903
|
throw error;
|
|
1849
1904
|
}
|
|
1850
1905
|
const fsError = error;
|
|
1851
|
-
const filePath =
|
|
1906
|
+
const filePath = path5.join(migrationDir, filename);
|
|
1852
1907
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
1853
1908
|
throw new FileSystemError(
|
|
1854
1909
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -2393,57 +2448,18 @@ function generate(diff, config) {
|
|
|
2393
2448
|
);
|
|
2394
2449
|
}
|
|
2395
2450
|
}
|
|
2451
|
+
|
|
2452
|
+
// src/migration/pocketbase-converter.ts
|
|
2396
2453
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2397
|
-
({
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
try {
|
|
2401
|
-
if (!fs4.existsSync(migrationsPath)) {
|
|
2402
|
-
return null;
|
|
2403
|
-
}
|
|
2404
|
-
const files = fs4.readdirSync(migrationsPath);
|
|
2405
|
-
const snapshotFiles = files.filter(
|
|
2406
|
-
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2407
|
-
);
|
|
2408
|
-
if (snapshotFiles.length === 0) {
|
|
2409
|
-
return null;
|
|
2410
|
-
}
|
|
2411
|
-
snapshotFiles.sort().reverse();
|
|
2412
|
-
const latestSnapshot = snapshotFiles[0];
|
|
2413
|
-
if (!latestSnapshot) {
|
|
2414
|
-
return null;
|
|
2415
|
-
}
|
|
2416
|
-
return path4.join(migrationsPath, latestSnapshot);
|
|
2417
|
-
} catch (error) {
|
|
2418
|
-
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2419
|
-
return null;
|
|
2454
|
+
function resolveCollectionIdToName(collectionId) {
|
|
2455
|
+
if (collectionId === "_pb_users_auth_") {
|
|
2456
|
+
return "Users";
|
|
2420
2457
|
}
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
if (!migrationsPath) {
|
|
2425
|
-
return null;
|
|
2426
|
-
}
|
|
2427
|
-
if (fs4.existsSync(migrationsPath) && fs4.statSync(migrationsPath).isFile()) {
|
|
2428
|
-
try {
|
|
2429
|
-
const migrationContent = fs4.readFileSync(migrationsPath, "utf-8");
|
|
2430
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2431
|
-
} catch (error) {
|
|
2432
|
-
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2433
|
-
return null;
|
|
2434
|
-
}
|
|
2458
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2459
|
+
if (nameMatch) {
|
|
2460
|
+
return nameMatch[1];
|
|
2435
2461
|
}
|
|
2436
|
-
|
|
2437
|
-
if (latestSnapshotPath) {
|
|
2438
|
-
try {
|
|
2439
|
-
const migrationContent = fs4.readFileSync(latestSnapshotPath, "utf-8");
|
|
2440
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2441
|
-
} catch (error) {
|
|
2442
|
-
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2443
|
-
return null;
|
|
2444
|
-
}
|
|
2445
|
-
}
|
|
2446
|
-
return null;
|
|
2462
|
+
return collectionId;
|
|
2447
2463
|
}
|
|
2448
2464
|
function convertPocketBaseCollection(pbCollection) {
|
|
2449
2465
|
const fields = [];
|
|
@@ -2462,17 +2478,28 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2462
2478
|
type: pbField.type,
|
|
2463
2479
|
required: pbField.required || false
|
|
2464
2480
|
};
|
|
2465
|
-
|
|
2466
|
-
|
|
2481
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
2482
|
+
if (pbField.type === "select") {
|
|
2483
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
2484
|
+
field.options.values = pbField.values;
|
|
2485
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
2486
|
+
field.options.values = pbField.options.values;
|
|
2487
|
+
}
|
|
2467
2488
|
}
|
|
2468
2489
|
if (pbField.type === "relation") {
|
|
2490
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2491
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2469
2492
|
field.relation = {
|
|
2470
|
-
collection:
|
|
2471
|
-
cascadeDelete: pbField.options?.cascadeDelete
|
|
2472
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2473
|
-
minSelect: pbField.options?.minSelect
|
|
2493
|
+
collection: collectionName,
|
|
2494
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
2495
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
2496
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
2474
2497
|
};
|
|
2475
2498
|
}
|
|
2499
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
2500
|
+
if (Object.keys(field.options).length === 0) {
|
|
2501
|
+
delete field.options;
|
|
2502
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
2476
2503
|
fields.push(field);
|
|
2477
2504
|
}
|
|
2478
2505
|
}
|
|
@@ -2537,6 +2564,320 @@ function convertPocketBaseMigration(migrationContent) {
|
|
|
2537
2564
|
}
|
|
2538
2565
|
}
|
|
2539
2566
|
|
|
2567
|
+
// src/migration/migration-parser.ts
|
|
2568
|
+
function extractTimestampFromFilename(filename) {
|
|
2569
|
+
const match = filename.match(/^(\d+)_/);
|
|
2570
|
+
if (match) {
|
|
2571
|
+
return parseInt(match[1], 10);
|
|
2572
|
+
}
|
|
2573
|
+
return null;
|
|
2574
|
+
}
|
|
2575
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
2576
|
+
try {
|
|
2577
|
+
if (!fs5.existsSync(migrationsPath)) {
|
|
2578
|
+
return [];
|
|
2579
|
+
}
|
|
2580
|
+
const files = fs5.readdirSync(migrationsPath);
|
|
2581
|
+
const migrationFiles = [];
|
|
2582
|
+
for (const file of files) {
|
|
2583
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
2584
|
+
continue;
|
|
2585
|
+
}
|
|
2586
|
+
if (!file.endsWith(".js")) {
|
|
2587
|
+
continue;
|
|
2588
|
+
}
|
|
2589
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
2590
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
2591
|
+
migrationFiles.push({
|
|
2592
|
+
path: path5.join(migrationsPath, file),
|
|
2593
|
+
timestamp
|
|
2594
|
+
});
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
2598
|
+
return migrationFiles.map((f) => f.path);
|
|
2599
|
+
} catch (error) {
|
|
2600
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
2601
|
+
return [];
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
function parseMigrationOperationsFromContent(content) {
|
|
2605
|
+
const collectionsToCreate = [];
|
|
2606
|
+
const collectionsToDelete = [];
|
|
2607
|
+
try {
|
|
2608
|
+
let searchIndex = 0;
|
|
2609
|
+
while (true) {
|
|
2610
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
2611
|
+
if (collectionStart === -1) {
|
|
2612
|
+
break;
|
|
2613
|
+
}
|
|
2614
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
2615
|
+
let braceCount = 0;
|
|
2616
|
+
let parenCount = 1;
|
|
2617
|
+
let inString = false;
|
|
2618
|
+
let stringChar = null;
|
|
2619
|
+
let i = openParen;
|
|
2620
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
2621
|
+
i++;
|
|
2622
|
+
}
|
|
2623
|
+
if (content[i] !== "{") {
|
|
2624
|
+
searchIndex = i + 1;
|
|
2625
|
+
continue;
|
|
2626
|
+
}
|
|
2627
|
+
const objectStart = i;
|
|
2628
|
+
braceCount = 1;
|
|
2629
|
+
i++;
|
|
2630
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
2631
|
+
const char = content[i];
|
|
2632
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
2633
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2634
|
+
inString = true;
|
|
2635
|
+
stringChar = char;
|
|
2636
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2637
|
+
inString = false;
|
|
2638
|
+
stringChar = null;
|
|
2639
|
+
}
|
|
2640
|
+
if (!inString) {
|
|
2641
|
+
if (char === "{") braceCount++;
|
|
2642
|
+
if (char === "}") braceCount--;
|
|
2643
|
+
if (char === "(") parenCount++;
|
|
2644
|
+
if (char === ")") parenCount--;
|
|
2645
|
+
}
|
|
2646
|
+
i++;
|
|
2647
|
+
}
|
|
2648
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
2649
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
2650
|
+
try {
|
|
2651
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
2652
|
+
if (collectionObj && collectionObj.name) {
|
|
2653
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
2654
|
+
collectionsToCreate.push(schema);
|
|
2655
|
+
}
|
|
2656
|
+
} catch (error) {
|
|
2657
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
searchIndex = i;
|
|
2661
|
+
}
|
|
2662
|
+
const deleteMatches = content.matchAll(
|
|
2663
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
2664
|
+
);
|
|
2665
|
+
for (const match of deleteMatches) {
|
|
2666
|
+
if (match[1]) {
|
|
2667
|
+
collectionsToDelete.push(match[1]);
|
|
2668
|
+
} else {
|
|
2669
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
2670
|
+
if (varNameMatch) {
|
|
2671
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
2672
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
2673
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
2674
|
+
const varDefMatch = beforeDelete.match(
|
|
2675
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
2676
|
+
);
|
|
2677
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
2678
|
+
const collectionDefMatch = beforeDelete.match(
|
|
2679
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
2680
|
+
);
|
|
2681
|
+
if (collectionDefMatch) {
|
|
2682
|
+
try {
|
|
2683
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
2684
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
2685
|
+
if (collectionObj && collectionObj.name) {
|
|
2686
|
+
collectionsToDelete.push(collectionObj.name);
|
|
2687
|
+
}
|
|
2688
|
+
} catch {
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
const findAndDeleteMatches = content.matchAll(
|
|
2696
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
2697
|
+
);
|
|
2698
|
+
for (const match of findAndDeleteMatches) {
|
|
2699
|
+
collectionsToDelete.push(match[1]);
|
|
2700
|
+
}
|
|
2701
|
+
} catch (error) {
|
|
2702
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
2703
|
+
}
|
|
2704
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
2705
|
+
}
|
|
2706
|
+
function parseMigrationOperations(migrationContent) {
|
|
2707
|
+
try {
|
|
2708
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
2709
|
+
if (!migrateMatch) {
|
|
2710
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2711
|
+
}
|
|
2712
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
2713
|
+
let i = startIndex;
|
|
2714
|
+
let parenCount = 0;
|
|
2715
|
+
let foundFirstParen = false;
|
|
2716
|
+
while (i < migrationContent.length) {
|
|
2717
|
+
const char = migrationContent[i];
|
|
2718
|
+
if (char === "(") {
|
|
2719
|
+
parenCount++;
|
|
2720
|
+
foundFirstParen = true;
|
|
2721
|
+
i++;
|
|
2722
|
+
break;
|
|
2723
|
+
}
|
|
2724
|
+
i++;
|
|
2725
|
+
}
|
|
2726
|
+
if (!foundFirstParen) {
|
|
2727
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2728
|
+
}
|
|
2729
|
+
let inString = false;
|
|
2730
|
+
let stringChar = null;
|
|
2731
|
+
let foundBrace = false;
|
|
2732
|
+
let braceStart = -1;
|
|
2733
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
2734
|
+
const char = migrationContent[i];
|
|
2735
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2736
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2737
|
+
inString = true;
|
|
2738
|
+
stringChar = char;
|
|
2739
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2740
|
+
inString = false;
|
|
2741
|
+
stringChar = null;
|
|
2742
|
+
}
|
|
2743
|
+
if (!inString) {
|
|
2744
|
+
if (char === "(") parenCount++;
|
|
2745
|
+
if (char === ")") {
|
|
2746
|
+
parenCount--;
|
|
2747
|
+
if (parenCount === 0) {
|
|
2748
|
+
i++;
|
|
2749
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2750
|
+
i++;
|
|
2751
|
+
}
|
|
2752
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
2753
|
+
i += 2;
|
|
2754
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2755
|
+
i++;
|
|
2756
|
+
}
|
|
2757
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
2758
|
+
foundBrace = true;
|
|
2759
|
+
braceStart = i + 1;
|
|
2760
|
+
break;
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
i++;
|
|
2767
|
+
}
|
|
2768
|
+
if (!foundBrace || braceStart === -1) {
|
|
2769
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2770
|
+
}
|
|
2771
|
+
let braceCount = 1;
|
|
2772
|
+
i = braceStart;
|
|
2773
|
+
inString = false;
|
|
2774
|
+
stringChar = null;
|
|
2775
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2776
|
+
const char = migrationContent[i];
|
|
2777
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2778
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2779
|
+
inString = true;
|
|
2780
|
+
stringChar = char;
|
|
2781
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2782
|
+
inString = false;
|
|
2783
|
+
stringChar = null;
|
|
2784
|
+
}
|
|
2785
|
+
if (!inString) {
|
|
2786
|
+
if (char === "{") braceCount++;
|
|
2787
|
+
if (char === "}") braceCount--;
|
|
2788
|
+
}
|
|
2789
|
+
i++;
|
|
2790
|
+
}
|
|
2791
|
+
if (braceCount === 0) {
|
|
2792
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2793
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2794
|
+
}
|
|
2795
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2796
|
+
} catch (error) {
|
|
2797
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2798
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
({
|
|
2802
|
+
workspaceRoot: process.cwd()});
|
|
2803
|
+
function findLatestSnapshot(migrationsPath) {
|
|
2804
|
+
try {
|
|
2805
|
+
if (!fs5.existsSync(migrationsPath)) {
|
|
2806
|
+
return null;
|
|
2807
|
+
}
|
|
2808
|
+
const files = fs5.readdirSync(migrationsPath);
|
|
2809
|
+
const snapshotFiles = files.filter(
|
|
2810
|
+
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2811
|
+
);
|
|
2812
|
+
if (snapshotFiles.length === 0) {
|
|
2813
|
+
return null;
|
|
2814
|
+
}
|
|
2815
|
+
snapshotFiles.sort().reverse();
|
|
2816
|
+
const latestSnapshot = snapshotFiles[0];
|
|
2817
|
+
if (!latestSnapshot) {
|
|
2818
|
+
return null;
|
|
2819
|
+
}
|
|
2820
|
+
return path5.join(migrationsPath, latestSnapshot);
|
|
2821
|
+
} catch (error) {
|
|
2822
|
+
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2823
|
+
return null;
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2827
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2828
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2829
|
+
updatedCollections.delete(collectionName);
|
|
2830
|
+
}
|
|
2831
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2832
|
+
updatedCollections.set(collection.name, collection);
|
|
2833
|
+
}
|
|
2834
|
+
return {
|
|
2835
|
+
...snapshot,
|
|
2836
|
+
collections: updatedCollections
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2840
|
+
const migrationsPath = config.migrationsPath;
|
|
2841
|
+
if (!migrationsPath) {
|
|
2842
|
+
return null;
|
|
2843
|
+
}
|
|
2844
|
+
if (fs5.existsSync(migrationsPath) && fs5.statSync(migrationsPath).isFile()) {
|
|
2845
|
+
try {
|
|
2846
|
+
const migrationContent = fs5.readFileSync(migrationsPath, "utf-8");
|
|
2847
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2848
|
+
} catch (error) {
|
|
2849
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2850
|
+
return null;
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2854
|
+
if (!latestSnapshotPath) {
|
|
2855
|
+
return null;
|
|
2856
|
+
}
|
|
2857
|
+
try {
|
|
2858
|
+
const migrationContent = fs5.readFileSync(latestSnapshotPath, "utf-8");
|
|
2859
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2860
|
+
const snapshotFilename = path5.basename(latestSnapshotPath);
|
|
2861
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2862
|
+
if (snapshotTimestamp) {
|
|
2863
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2864
|
+
for (const migrationFile of migrationFiles) {
|
|
2865
|
+
try {
|
|
2866
|
+
const migrationContent2 = fs5.readFileSync(migrationFile, "utf-8");
|
|
2867
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2868
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2869
|
+
} catch (error) {
|
|
2870
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
return snapshot;
|
|
2875
|
+
} catch (error) {
|
|
2876
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2877
|
+
return null;
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2540
2881
|
// src/migration/validation.ts
|
|
2541
2882
|
function detectCollectionDeletions(diff) {
|
|
2542
2883
|
const changes = [];
|
|
@@ -2705,8 +3046,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
2705
3046
|
};
|
|
2706
3047
|
function findConfigFile(directory) {
|
|
2707
3048
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
2708
|
-
const filePath =
|
|
2709
|
-
if (
|
|
3049
|
+
const filePath = path5.join(directory, fileName);
|
|
3050
|
+
if (fs5.existsSync(filePath)) {
|
|
2710
3051
|
return filePath;
|
|
2711
3052
|
}
|
|
2712
3053
|
}
|
|
@@ -2714,7 +3055,7 @@ function findConfigFile(directory) {
|
|
|
2714
3055
|
}
|
|
2715
3056
|
function loadJsonConfig(configPath) {
|
|
2716
3057
|
try {
|
|
2717
|
-
const content =
|
|
3058
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
2718
3059
|
return JSON.parse(content);
|
|
2719
3060
|
} catch (error) {
|
|
2720
3061
|
if (error instanceof SyntaxError) {
|
|
@@ -2743,10 +3084,10 @@ async function loadJsConfig(configPath) {
|
|
|
2743
3084
|
}
|
|
2744
3085
|
}
|
|
2745
3086
|
async function loadConfigFile(configPath) {
|
|
2746
|
-
if (!
|
|
3087
|
+
if (!fs5.existsSync(configPath)) {
|
|
2747
3088
|
return null;
|
|
2748
3089
|
}
|
|
2749
|
-
const ext =
|
|
3090
|
+
const ext = path5.extname(configPath).toLowerCase();
|
|
2750
3091
|
if (ext === ".json") {
|
|
2751
3092
|
return loadJsonConfig(configPath);
|
|
2752
3093
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -2813,10 +3154,10 @@ function validateConfig(config, configPath) {
|
|
|
2813
3154
|
}
|
|
2814
3155
|
const cwd = process.cwd();
|
|
2815
3156
|
const possiblePaths = [
|
|
2816
|
-
|
|
2817
|
-
|
|
3157
|
+
path5.resolve(cwd, config.schema.directory),
|
|
3158
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
2818
3159
|
];
|
|
2819
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
3160
|
+
const schemaDir = possiblePaths.find((p) => fs5.existsSync(p));
|
|
2820
3161
|
if (!schemaDir) {
|
|
2821
3162
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
2822
3163
|
"schema.directory"
|
|
@@ -2828,15 +3169,15 @@ async function loadConfig(options = {}) {
|
|
|
2828
3169
|
let configFilePath;
|
|
2829
3170
|
const cwd = process.cwd();
|
|
2830
3171
|
if (options.config) {
|
|
2831
|
-
const explicitPath =
|
|
2832
|
-
if (!
|
|
3172
|
+
const explicitPath = path5.resolve(cwd, options.config);
|
|
3173
|
+
if (!fs5.existsSync(explicitPath)) {
|
|
2833
3174
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
2834
3175
|
}
|
|
2835
3176
|
configFilePath = explicitPath;
|
|
2836
3177
|
} else {
|
|
2837
|
-
const searchDirs = [cwd,
|
|
3178
|
+
const searchDirs = [cwd, path5.join(cwd, "shared")];
|
|
2838
3179
|
for (const dir of searchDirs) {
|
|
2839
|
-
if (
|
|
3180
|
+
if (fs5.existsSync(dir)) {
|
|
2840
3181
|
const found = findConfigFile(dir);
|
|
2841
3182
|
if (found) {
|
|
2842
3183
|
configFilePath = found;
|
|
@@ -2865,18 +3206,18 @@ async function loadConfig(options = {}) {
|
|
|
2865
3206
|
function getSchemaDirectory(config) {
|
|
2866
3207
|
const cwd = process.cwd();
|
|
2867
3208
|
const possiblePaths = [
|
|
2868
|
-
|
|
2869
|
-
|
|
3209
|
+
path5.resolve(cwd, config.schema.directory),
|
|
3210
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
2870
3211
|
];
|
|
2871
|
-
return possiblePaths.find((p) =>
|
|
3212
|
+
return possiblePaths.find((p) => fs5.existsSync(p)) || possiblePaths[0];
|
|
2872
3213
|
}
|
|
2873
3214
|
function getMigrationsDirectory(config) {
|
|
2874
3215
|
const cwd = process.cwd();
|
|
2875
3216
|
const possiblePaths = [
|
|
2876
|
-
|
|
2877
|
-
|
|
3217
|
+
path5.resolve(cwd, config.migrations.directory),
|
|
3218
|
+
path5.resolve(cwd, "shared", config.migrations.directory)
|
|
2878
3219
|
];
|
|
2879
|
-
return possiblePaths.find((p) =>
|
|
3220
|
+
return possiblePaths.find((p) => fs5.existsSync(p)) || possiblePaths[0];
|
|
2880
3221
|
}
|
|
2881
3222
|
var currentVerbosity = "normal";
|
|
2882
3223
|
function setVerbosity(level) {
|
|
@@ -3153,7 +3494,7 @@ async function executeGenerate(options) {
|
|
|
3153
3494
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3154
3495
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
3155
3496
|
logInfo("Loading previous snapshot...");
|
|
3156
|
-
const previousSnapshot =
|
|
3497
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3157
3498
|
migrationsPath: migrationsDir,
|
|
3158
3499
|
workspaceRoot: process.cwd()
|
|
3159
3500
|
});
|
|
@@ -3180,7 +3521,7 @@ async function executeGenerate(options) {
|
|
|
3180
3521
|
"Creating migration file...",
|
|
3181
3522
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
3182
3523
|
);
|
|
3183
|
-
logSuccess(`Migration file created: ${
|
|
3524
|
+
logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
|
|
3184
3525
|
logSection("\u2705 Next Steps");
|
|
3185
3526
|
console.log();
|
|
3186
3527
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -3346,7 +3687,7 @@ async function executeStatus(options) {
|
|
|
3346
3687
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3347
3688
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
3348
3689
|
logInfo("Loading previous snapshot...");
|
|
3349
|
-
const previousSnapshot =
|
|
3690
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3350
3691
|
migrationsPath: migrationsDir,
|
|
3351
3692
|
workspaceRoot: process.cwd()
|
|
3352
3693
|
});
|