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/migrate.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import * as
|
|
4
|
+
import * as fs5 from 'fs';
|
|
5
5
|
import { readFileSync } from 'fs';
|
|
6
|
-
import * as
|
|
6
|
+
import * as path5 from 'path';
|
|
7
7
|
import { dirname, join } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { z } from 'zod';
|
|
@@ -136,10 +136,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
136
136
|
operation;
|
|
137
137
|
code;
|
|
138
138
|
originalError;
|
|
139
|
-
constructor(message,
|
|
139
|
+
constructor(message, path7, operation, code, originalError) {
|
|
140
140
|
super(message);
|
|
141
141
|
this.name = "FileSystemError";
|
|
142
|
-
this.path =
|
|
142
|
+
this.path = path7;
|
|
143
143
|
this.operation = operation;
|
|
144
144
|
this.code = code;
|
|
145
145
|
this.originalError = originalError;
|
|
@@ -1053,6 +1053,16 @@ function isFieldRequired(zodType) {
|
|
|
1053
1053
|
}
|
|
1054
1054
|
|
|
1055
1055
|
// src/migration/analyzer.ts
|
|
1056
|
+
var tsxLoaderRegistered = false;
|
|
1057
|
+
async function ensureTsxLoader() {
|
|
1058
|
+
if (tsxLoaderRegistered) return;
|
|
1059
|
+
try {
|
|
1060
|
+
await import('tsx/esm');
|
|
1061
|
+
tsxLoaderRegistered = true;
|
|
1062
|
+
} catch {
|
|
1063
|
+
tsxLoaderRegistered = false;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1056
1066
|
var DEFAULT_CONFIG = {
|
|
1057
1067
|
workspaceRoot: process.cwd(),
|
|
1058
1068
|
excludePatterns: [
|
|
@@ -1080,20 +1090,20 @@ function mergeConfig(config) {
|
|
|
1080
1090
|
}
|
|
1081
1091
|
function resolveSchemaDir(config) {
|
|
1082
1092
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1083
|
-
if (
|
|
1093
|
+
if (path5.isAbsolute(config.schemaDir)) {
|
|
1084
1094
|
return config.schemaDir;
|
|
1085
1095
|
}
|
|
1086
|
-
return
|
|
1096
|
+
return path5.join(workspaceRoot, config.schemaDir);
|
|
1087
1097
|
}
|
|
1088
1098
|
function discoverSchemaFiles(config) {
|
|
1089
1099
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1090
1100
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1091
1101
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1092
1102
|
try {
|
|
1093
|
-
if (!
|
|
1103
|
+
if (!fs5.existsSync(schemaDir)) {
|
|
1094
1104
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1095
1105
|
}
|
|
1096
|
-
const files =
|
|
1106
|
+
const files = fs5.readdirSync(schemaDir);
|
|
1097
1107
|
const schemaFiles = files.filter((file) => {
|
|
1098
1108
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1099
1109
|
if (!hasValidExtension) return false;
|
|
@@ -1109,7 +1119,7 @@ function discoverSchemaFiles(config) {
|
|
|
1109
1119
|
});
|
|
1110
1120
|
return schemaFiles.map((file) => {
|
|
1111
1121
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1112
|
-
return
|
|
1122
|
+
return path5.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1113
1123
|
});
|
|
1114
1124
|
} catch (error) {
|
|
1115
1125
|
if (error instanceof FileSystemError) {
|
|
@@ -1143,40 +1153,66 @@ async function importSchemaModule(filePath, config) {
|
|
|
1143
1153
|
let resolvedPath = null;
|
|
1144
1154
|
const jsPath = `${importPath}.js`;
|
|
1145
1155
|
const tsPath = `${importPath}.ts`;
|
|
1146
|
-
if (
|
|
1156
|
+
if (fs5.existsSync(jsPath)) {
|
|
1147
1157
|
resolvedPath = jsPath;
|
|
1148
|
-
} else if (
|
|
1158
|
+
} else if (fs5.existsSync(tsPath)) {
|
|
1149
1159
|
resolvedPath = tsPath;
|
|
1150
1160
|
} else {
|
|
1151
1161
|
resolvedPath = jsPath;
|
|
1152
1162
|
}
|
|
1153
|
-
|
|
1163
|
+
if (resolvedPath.endsWith(".ts")) {
|
|
1164
|
+
await ensureTsxLoader();
|
|
1165
|
+
if (!tsxLoaderRegistered) {
|
|
1166
|
+
throw new SchemaParsingError(
|
|
1167
|
+
`Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
|
|
1168
|
+
Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
|
|
1169
|
+
Alternatively, compile your schema files to JavaScript first.`,
|
|
1170
|
+
filePath
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
const fileUrl = new URL(`file://${path5.resolve(resolvedPath)}`);
|
|
1154
1175
|
const module = await import(fileUrl.href);
|
|
1155
1176
|
return module;
|
|
1156
1177
|
} catch (error) {
|
|
1157
1178
|
const tsPath = `${filePath}.ts`;
|
|
1158
|
-
const isTypeScriptFile =
|
|
1179
|
+
const isTypeScriptFile = fs5.existsSync(tsPath);
|
|
1180
|
+
if (isTypeScriptFile && error instanceof SchemaParsingError) {
|
|
1181
|
+
throw error;
|
|
1182
|
+
}
|
|
1159
1183
|
if (isTypeScriptFile) {
|
|
1160
1184
|
throw new SchemaParsingError(
|
|
1161
|
-
`Failed to import TypeScript schema file.
|
|
1162
|
-
Please
|
|
1163
|
-
|
|
1164
|
-
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")`,
|
|
1185
|
+
`Failed to import TypeScript schema file. The 'tsx' package is required to load TypeScript files.
|
|
1186
|
+
Please install tsx: npm install tsx (or yarn add tsx, or pnpm add tsx)
|
|
1187
|
+
Alternatively, compile your schema files to JavaScript first.`,
|
|
1165
1188
|
filePath,
|
|
1166
1189
|
error
|
|
1167
1190
|
);
|
|
1168
1191
|
}
|
|
1169
1192
|
throw new SchemaParsingError(
|
|
1170
|
-
`Failed to import schema module. Make sure the schema files
|
|
1193
|
+
`Failed to import schema module. Make sure the schema files exist and are valid.`,
|
|
1171
1194
|
filePath,
|
|
1172
1195
|
error
|
|
1173
1196
|
);
|
|
1174
1197
|
}
|
|
1175
1198
|
}
|
|
1176
1199
|
function getCollectionNameFromFile(filePath) {
|
|
1177
|
-
const filename =
|
|
1200
|
+
const filename = path5.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
1178
1201
|
return toCollectionName(filename);
|
|
1179
1202
|
}
|
|
1203
|
+
function extractCollectionNameFromSchema(zodSchema) {
|
|
1204
|
+
if (!zodSchema.description) {
|
|
1205
|
+
return null;
|
|
1206
|
+
}
|
|
1207
|
+
try {
|
|
1208
|
+
const metadata = JSON.parse(zodSchema.description);
|
|
1209
|
+
if (metadata.collectionName && typeof metadata.collectionName === "string") {
|
|
1210
|
+
return metadata.collectionName;
|
|
1211
|
+
}
|
|
1212
|
+
} catch {
|
|
1213
|
+
}
|
|
1214
|
+
return null;
|
|
1215
|
+
}
|
|
1180
1216
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
1181
1217
|
const result = {};
|
|
1182
1218
|
for (const [key, value] of Object.entries(module)) {
|
|
@@ -1339,7 +1375,7 @@ async function buildSchemaDefinition(config) {
|
|
|
1339
1375
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
1340
1376
|
} else if (mergedConfig.useCompiledFiles) {
|
|
1341
1377
|
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
1342
|
-
if (
|
|
1378
|
+
if (fs5.existsSync(`${distPath}.js`) || fs5.existsSync(`${distPath}.mjs`)) {
|
|
1343
1379
|
importPath = distPath;
|
|
1344
1380
|
} else {
|
|
1345
1381
|
importPath = filePath;
|
|
@@ -1352,7 +1388,8 @@ async function buildSchemaDefinition(config) {
|
|
|
1352
1388
|
console.warn(`No valid schema found in ${filePath}, skipping...`);
|
|
1353
1389
|
continue;
|
|
1354
1390
|
}
|
|
1355
|
-
const
|
|
1391
|
+
const collectionNameFromSchema = extractCollectionNameFromSchema(zodSchema);
|
|
1392
|
+
const collectionName = collectionNameFromSchema ?? getCollectionNameFromFile(filePath);
|
|
1356
1393
|
const collectionSchema = convertZodSchemaToCollectionSchema(collectionName, zodSchema);
|
|
1357
1394
|
collections.set(collectionName, collectionSchema);
|
|
1358
1395
|
} catch (error) {
|
|
@@ -1516,6 +1553,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
1516
1553
|
for (const key of allKeys) {
|
|
1517
1554
|
const currentValue = currentOptions[key];
|
|
1518
1555
|
const previousValue = previousOptions[key];
|
|
1556
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
1557
|
+
continue;
|
|
1558
|
+
}
|
|
1519
1559
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
1520
1560
|
changes.push({
|
|
1521
1561
|
property: `options.${key}`,
|
|
@@ -1536,11 +1576,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1536
1576
|
if (!currentRelation || !previousRelation) {
|
|
1537
1577
|
return changes;
|
|
1538
1578
|
}
|
|
1539
|
-
|
|
1579
|
+
const normalizeCollection = (collection) => {
|
|
1580
|
+
if (!collection) return collection;
|
|
1581
|
+
if (collection === "_pb_users_auth_") {
|
|
1582
|
+
return "Users";
|
|
1583
|
+
}
|
|
1584
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1585
|
+
if (nameMatch) {
|
|
1586
|
+
return nameMatch[1];
|
|
1587
|
+
}
|
|
1588
|
+
return collection;
|
|
1589
|
+
};
|
|
1590
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
1591
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
1592
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
1540
1593
|
changes.push({
|
|
1541
1594
|
property: "relation.collection",
|
|
1542
|
-
oldValue:
|
|
1543
|
-
|
|
1595
|
+
oldValue: normalizedPrevious,
|
|
1596
|
+
// Use normalized value for clarity
|
|
1597
|
+
newValue: normalizedCurrent
|
|
1598
|
+
// Use normalized value for clarity
|
|
1544
1599
|
});
|
|
1545
1600
|
}
|
|
1546
1601
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -1760,10 +1815,10 @@ function mergeConfig3(config) {
|
|
|
1760
1815
|
}
|
|
1761
1816
|
function resolveMigrationDir(config) {
|
|
1762
1817
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1763
|
-
if (
|
|
1818
|
+
if (path5.isAbsolute(config.migrationDir)) {
|
|
1764
1819
|
return config.migrationDir;
|
|
1765
1820
|
}
|
|
1766
|
-
return
|
|
1821
|
+
return path5.join(workspaceRoot, config.migrationDir);
|
|
1767
1822
|
}
|
|
1768
1823
|
function generateTimestamp(config) {
|
|
1769
1824
|
if (config?.timestampGenerator) {
|
|
@@ -1821,9 +1876,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
1821
1876
|
}
|
|
1822
1877
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
1823
1878
|
try {
|
|
1824
|
-
if (!
|
|
1879
|
+
if (!fs5.existsSync(migrationDir)) {
|
|
1825
1880
|
try {
|
|
1826
|
-
|
|
1881
|
+
fs5.mkdirSync(migrationDir, { recursive: true });
|
|
1827
1882
|
} catch (error) {
|
|
1828
1883
|
const fsError = error;
|
|
1829
1884
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -1844,15 +1899,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
1844
1899
|
);
|
|
1845
1900
|
}
|
|
1846
1901
|
}
|
|
1847
|
-
const filePath =
|
|
1848
|
-
|
|
1902
|
+
const filePath = path5.join(migrationDir, filename);
|
|
1903
|
+
fs5.writeFileSync(filePath, content, "utf-8");
|
|
1849
1904
|
return filePath;
|
|
1850
1905
|
} catch (error) {
|
|
1851
1906
|
if (error instanceof FileSystemError) {
|
|
1852
1907
|
throw error;
|
|
1853
1908
|
}
|
|
1854
1909
|
const fsError = error;
|
|
1855
|
-
const filePath =
|
|
1910
|
+
const filePath = path5.join(migrationDir, filename);
|
|
1856
1911
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
1857
1912
|
throw new FileSystemError(
|
|
1858
1913
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -2397,57 +2452,18 @@ function generate(diff, config) {
|
|
|
2397
2452
|
);
|
|
2398
2453
|
}
|
|
2399
2454
|
}
|
|
2455
|
+
|
|
2456
|
+
// src/migration/pocketbase-converter.ts
|
|
2400
2457
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2401
|
-
({
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
try {
|
|
2405
|
-
if (!fs4.existsSync(migrationsPath)) {
|
|
2406
|
-
return null;
|
|
2407
|
-
}
|
|
2408
|
-
const files = fs4.readdirSync(migrationsPath);
|
|
2409
|
-
const snapshotFiles = files.filter(
|
|
2410
|
-
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2411
|
-
);
|
|
2412
|
-
if (snapshotFiles.length === 0) {
|
|
2413
|
-
return null;
|
|
2414
|
-
}
|
|
2415
|
-
snapshotFiles.sort().reverse();
|
|
2416
|
-
const latestSnapshot = snapshotFiles[0];
|
|
2417
|
-
if (!latestSnapshot) {
|
|
2418
|
-
return null;
|
|
2419
|
-
}
|
|
2420
|
-
return path4.join(migrationsPath, latestSnapshot);
|
|
2421
|
-
} catch (error) {
|
|
2422
|
-
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2423
|
-
return null;
|
|
2458
|
+
function resolveCollectionIdToName(collectionId) {
|
|
2459
|
+
if (collectionId === "_pb_users_auth_") {
|
|
2460
|
+
return "Users";
|
|
2424
2461
|
}
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
if (!migrationsPath) {
|
|
2429
|
-
return null;
|
|
2430
|
-
}
|
|
2431
|
-
if (fs4.existsSync(migrationsPath) && fs4.statSync(migrationsPath).isFile()) {
|
|
2432
|
-
try {
|
|
2433
|
-
const migrationContent = fs4.readFileSync(migrationsPath, "utf-8");
|
|
2434
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2435
|
-
} catch (error) {
|
|
2436
|
-
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2437
|
-
return null;
|
|
2438
|
-
}
|
|
2462
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2463
|
+
if (nameMatch) {
|
|
2464
|
+
return nameMatch[1];
|
|
2439
2465
|
}
|
|
2440
|
-
|
|
2441
|
-
if (latestSnapshotPath) {
|
|
2442
|
-
try {
|
|
2443
|
-
const migrationContent = fs4.readFileSync(latestSnapshotPath, "utf-8");
|
|
2444
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2445
|
-
} catch (error) {
|
|
2446
|
-
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2447
|
-
return null;
|
|
2448
|
-
}
|
|
2449
|
-
}
|
|
2450
|
-
return null;
|
|
2466
|
+
return collectionId;
|
|
2451
2467
|
}
|
|
2452
2468
|
function convertPocketBaseCollection(pbCollection) {
|
|
2453
2469
|
const fields = [];
|
|
@@ -2466,17 +2482,28 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2466
2482
|
type: pbField.type,
|
|
2467
2483
|
required: pbField.required || false
|
|
2468
2484
|
};
|
|
2469
|
-
|
|
2470
|
-
|
|
2485
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
2486
|
+
if (pbField.type === "select") {
|
|
2487
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
2488
|
+
field.options.values = pbField.values;
|
|
2489
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
2490
|
+
field.options.values = pbField.options.values;
|
|
2491
|
+
}
|
|
2471
2492
|
}
|
|
2472
2493
|
if (pbField.type === "relation") {
|
|
2494
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2495
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2473
2496
|
field.relation = {
|
|
2474
|
-
collection:
|
|
2475
|
-
cascadeDelete: pbField.options?.cascadeDelete
|
|
2476
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2477
|
-
minSelect: pbField.options?.minSelect
|
|
2497
|
+
collection: collectionName,
|
|
2498
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
2499
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
2500
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
2478
2501
|
};
|
|
2479
2502
|
}
|
|
2503
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
2504
|
+
if (Object.keys(field.options).length === 0) {
|
|
2505
|
+
delete field.options;
|
|
2506
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
2480
2507
|
fields.push(field);
|
|
2481
2508
|
}
|
|
2482
2509
|
}
|
|
@@ -2541,6 +2568,320 @@ function convertPocketBaseMigration(migrationContent) {
|
|
|
2541
2568
|
}
|
|
2542
2569
|
}
|
|
2543
2570
|
|
|
2571
|
+
// src/migration/migration-parser.ts
|
|
2572
|
+
function extractTimestampFromFilename(filename) {
|
|
2573
|
+
const match = filename.match(/^(\d+)_/);
|
|
2574
|
+
if (match) {
|
|
2575
|
+
return parseInt(match[1], 10);
|
|
2576
|
+
}
|
|
2577
|
+
return null;
|
|
2578
|
+
}
|
|
2579
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
2580
|
+
try {
|
|
2581
|
+
if (!fs5.existsSync(migrationsPath)) {
|
|
2582
|
+
return [];
|
|
2583
|
+
}
|
|
2584
|
+
const files = fs5.readdirSync(migrationsPath);
|
|
2585
|
+
const migrationFiles = [];
|
|
2586
|
+
for (const file of files) {
|
|
2587
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
2588
|
+
continue;
|
|
2589
|
+
}
|
|
2590
|
+
if (!file.endsWith(".js")) {
|
|
2591
|
+
continue;
|
|
2592
|
+
}
|
|
2593
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
2594
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
2595
|
+
migrationFiles.push({
|
|
2596
|
+
path: path5.join(migrationsPath, file),
|
|
2597
|
+
timestamp
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
2602
|
+
return migrationFiles.map((f) => f.path);
|
|
2603
|
+
} catch (error) {
|
|
2604
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
2605
|
+
return [];
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
function parseMigrationOperationsFromContent(content) {
|
|
2609
|
+
const collectionsToCreate = [];
|
|
2610
|
+
const collectionsToDelete = [];
|
|
2611
|
+
try {
|
|
2612
|
+
let searchIndex = 0;
|
|
2613
|
+
while (true) {
|
|
2614
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
2615
|
+
if (collectionStart === -1) {
|
|
2616
|
+
break;
|
|
2617
|
+
}
|
|
2618
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
2619
|
+
let braceCount = 0;
|
|
2620
|
+
let parenCount = 1;
|
|
2621
|
+
let inString = false;
|
|
2622
|
+
let stringChar = null;
|
|
2623
|
+
let i = openParen;
|
|
2624
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
2625
|
+
i++;
|
|
2626
|
+
}
|
|
2627
|
+
if (content[i] !== "{") {
|
|
2628
|
+
searchIndex = i + 1;
|
|
2629
|
+
continue;
|
|
2630
|
+
}
|
|
2631
|
+
const objectStart = i;
|
|
2632
|
+
braceCount = 1;
|
|
2633
|
+
i++;
|
|
2634
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
2635
|
+
const char = content[i];
|
|
2636
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
2637
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2638
|
+
inString = true;
|
|
2639
|
+
stringChar = char;
|
|
2640
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2641
|
+
inString = false;
|
|
2642
|
+
stringChar = null;
|
|
2643
|
+
}
|
|
2644
|
+
if (!inString) {
|
|
2645
|
+
if (char === "{") braceCount++;
|
|
2646
|
+
if (char === "}") braceCount--;
|
|
2647
|
+
if (char === "(") parenCount++;
|
|
2648
|
+
if (char === ")") parenCount--;
|
|
2649
|
+
}
|
|
2650
|
+
i++;
|
|
2651
|
+
}
|
|
2652
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
2653
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
2654
|
+
try {
|
|
2655
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
2656
|
+
if (collectionObj && collectionObj.name) {
|
|
2657
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
2658
|
+
collectionsToCreate.push(schema);
|
|
2659
|
+
}
|
|
2660
|
+
} catch (error) {
|
|
2661
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
searchIndex = i;
|
|
2665
|
+
}
|
|
2666
|
+
const deleteMatches = content.matchAll(
|
|
2667
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
2668
|
+
);
|
|
2669
|
+
for (const match of deleteMatches) {
|
|
2670
|
+
if (match[1]) {
|
|
2671
|
+
collectionsToDelete.push(match[1]);
|
|
2672
|
+
} else {
|
|
2673
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
2674
|
+
if (varNameMatch) {
|
|
2675
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
2676
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
2677
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
2678
|
+
const varDefMatch = beforeDelete.match(
|
|
2679
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
2680
|
+
);
|
|
2681
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
2682
|
+
const collectionDefMatch = beforeDelete.match(
|
|
2683
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
2684
|
+
);
|
|
2685
|
+
if (collectionDefMatch) {
|
|
2686
|
+
try {
|
|
2687
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
2688
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
2689
|
+
if (collectionObj && collectionObj.name) {
|
|
2690
|
+
collectionsToDelete.push(collectionObj.name);
|
|
2691
|
+
}
|
|
2692
|
+
} catch {
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
const findAndDeleteMatches = content.matchAll(
|
|
2700
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
2701
|
+
);
|
|
2702
|
+
for (const match of findAndDeleteMatches) {
|
|
2703
|
+
collectionsToDelete.push(match[1]);
|
|
2704
|
+
}
|
|
2705
|
+
} catch (error) {
|
|
2706
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
2707
|
+
}
|
|
2708
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
2709
|
+
}
|
|
2710
|
+
function parseMigrationOperations(migrationContent) {
|
|
2711
|
+
try {
|
|
2712
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
2713
|
+
if (!migrateMatch) {
|
|
2714
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2715
|
+
}
|
|
2716
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
2717
|
+
let i = startIndex;
|
|
2718
|
+
let parenCount = 0;
|
|
2719
|
+
let foundFirstParen = false;
|
|
2720
|
+
while (i < migrationContent.length) {
|
|
2721
|
+
const char = migrationContent[i];
|
|
2722
|
+
if (char === "(") {
|
|
2723
|
+
parenCount++;
|
|
2724
|
+
foundFirstParen = true;
|
|
2725
|
+
i++;
|
|
2726
|
+
break;
|
|
2727
|
+
}
|
|
2728
|
+
i++;
|
|
2729
|
+
}
|
|
2730
|
+
if (!foundFirstParen) {
|
|
2731
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2732
|
+
}
|
|
2733
|
+
let inString = false;
|
|
2734
|
+
let stringChar = null;
|
|
2735
|
+
let foundBrace = false;
|
|
2736
|
+
let braceStart = -1;
|
|
2737
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
2738
|
+
const char = migrationContent[i];
|
|
2739
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2740
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2741
|
+
inString = true;
|
|
2742
|
+
stringChar = char;
|
|
2743
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2744
|
+
inString = false;
|
|
2745
|
+
stringChar = null;
|
|
2746
|
+
}
|
|
2747
|
+
if (!inString) {
|
|
2748
|
+
if (char === "(") parenCount++;
|
|
2749
|
+
if (char === ")") {
|
|
2750
|
+
parenCount--;
|
|
2751
|
+
if (parenCount === 0) {
|
|
2752
|
+
i++;
|
|
2753
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2754
|
+
i++;
|
|
2755
|
+
}
|
|
2756
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
2757
|
+
i += 2;
|
|
2758
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2759
|
+
i++;
|
|
2760
|
+
}
|
|
2761
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
2762
|
+
foundBrace = true;
|
|
2763
|
+
braceStart = i + 1;
|
|
2764
|
+
break;
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
i++;
|
|
2771
|
+
}
|
|
2772
|
+
if (!foundBrace || braceStart === -1) {
|
|
2773
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2774
|
+
}
|
|
2775
|
+
let braceCount = 1;
|
|
2776
|
+
i = braceStart;
|
|
2777
|
+
inString = false;
|
|
2778
|
+
stringChar = null;
|
|
2779
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2780
|
+
const char = migrationContent[i];
|
|
2781
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2782
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2783
|
+
inString = true;
|
|
2784
|
+
stringChar = char;
|
|
2785
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2786
|
+
inString = false;
|
|
2787
|
+
stringChar = null;
|
|
2788
|
+
}
|
|
2789
|
+
if (!inString) {
|
|
2790
|
+
if (char === "{") braceCount++;
|
|
2791
|
+
if (char === "}") braceCount--;
|
|
2792
|
+
}
|
|
2793
|
+
i++;
|
|
2794
|
+
}
|
|
2795
|
+
if (braceCount === 0) {
|
|
2796
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2797
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2798
|
+
}
|
|
2799
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2800
|
+
} catch (error) {
|
|
2801
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2802
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
({
|
|
2806
|
+
workspaceRoot: process.cwd()});
|
|
2807
|
+
function findLatestSnapshot(migrationsPath) {
|
|
2808
|
+
try {
|
|
2809
|
+
if (!fs5.existsSync(migrationsPath)) {
|
|
2810
|
+
return null;
|
|
2811
|
+
}
|
|
2812
|
+
const files = fs5.readdirSync(migrationsPath);
|
|
2813
|
+
const snapshotFiles = files.filter(
|
|
2814
|
+
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2815
|
+
);
|
|
2816
|
+
if (snapshotFiles.length === 0) {
|
|
2817
|
+
return null;
|
|
2818
|
+
}
|
|
2819
|
+
snapshotFiles.sort().reverse();
|
|
2820
|
+
const latestSnapshot = snapshotFiles[0];
|
|
2821
|
+
if (!latestSnapshot) {
|
|
2822
|
+
return null;
|
|
2823
|
+
}
|
|
2824
|
+
return path5.join(migrationsPath, latestSnapshot);
|
|
2825
|
+
} catch (error) {
|
|
2826
|
+
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2827
|
+
return null;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2831
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2832
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2833
|
+
updatedCollections.delete(collectionName);
|
|
2834
|
+
}
|
|
2835
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2836
|
+
updatedCollections.set(collection.name, collection);
|
|
2837
|
+
}
|
|
2838
|
+
return {
|
|
2839
|
+
...snapshot,
|
|
2840
|
+
collections: updatedCollections
|
|
2841
|
+
};
|
|
2842
|
+
}
|
|
2843
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2844
|
+
const migrationsPath = config.migrationsPath;
|
|
2845
|
+
if (!migrationsPath) {
|
|
2846
|
+
return null;
|
|
2847
|
+
}
|
|
2848
|
+
if (fs5.existsSync(migrationsPath) && fs5.statSync(migrationsPath).isFile()) {
|
|
2849
|
+
try {
|
|
2850
|
+
const migrationContent = fs5.readFileSync(migrationsPath, "utf-8");
|
|
2851
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2852
|
+
} catch (error) {
|
|
2853
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2854
|
+
return null;
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2858
|
+
if (!latestSnapshotPath) {
|
|
2859
|
+
return null;
|
|
2860
|
+
}
|
|
2861
|
+
try {
|
|
2862
|
+
const migrationContent = fs5.readFileSync(latestSnapshotPath, "utf-8");
|
|
2863
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2864
|
+
const snapshotFilename = path5.basename(latestSnapshotPath);
|
|
2865
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2866
|
+
if (snapshotTimestamp) {
|
|
2867
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2868
|
+
for (const migrationFile of migrationFiles) {
|
|
2869
|
+
try {
|
|
2870
|
+
const migrationContent2 = fs5.readFileSync(migrationFile, "utf-8");
|
|
2871
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2872
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2873
|
+
} catch (error) {
|
|
2874
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
return snapshot;
|
|
2879
|
+
} catch (error) {
|
|
2880
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2881
|
+
return null;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2544
2885
|
// src/migration/validation.ts
|
|
2545
2886
|
function detectCollectionDeletions(diff) {
|
|
2546
2887
|
const changes = [];
|
|
@@ -2709,8 +3050,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
2709
3050
|
};
|
|
2710
3051
|
function findConfigFile(directory) {
|
|
2711
3052
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
2712
|
-
const filePath =
|
|
2713
|
-
if (
|
|
3053
|
+
const filePath = path5.join(directory, fileName);
|
|
3054
|
+
if (fs5.existsSync(filePath)) {
|
|
2714
3055
|
return filePath;
|
|
2715
3056
|
}
|
|
2716
3057
|
}
|
|
@@ -2718,7 +3059,7 @@ function findConfigFile(directory) {
|
|
|
2718
3059
|
}
|
|
2719
3060
|
function loadJsonConfig(configPath) {
|
|
2720
3061
|
try {
|
|
2721
|
-
const content =
|
|
3062
|
+
const content = fs5.readFileSync(configPath, "utf-8");
|
|
2722
3063
|
return JSON.parse(content);
|
|
2723
3064
|
} catch (error) {
|
|
2724
3065
|
if (error instanceof SyntaxError) {
|
|
@@ -2747,10 +3088,10 @@ async function loadJsConfig(configPath) {
|
|
|
2747
3088
|
}
|
|
2748
3089
|
}
|
|
2749
3090
|
async function loadConfigFile(configPath) {
|
|
2750
|
-
if (!
|
|
3091
|
+
if (!fs5.existsSync(configPath)) {
|
|
2751
3092
|
return null;
|
|
2752
3093
|
}
|
|
2753
|
-
const ext =
|
|
3094
|
+
const ext = path5.extname(configPath).toLowerCase();
|
|
2754
3095
|
if (ext === ".json") {
|
|
2755
3096
|
return loadJsonConfig(configPath);
|
|
2756
3097
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -2817,10 +3158,10 @@ function validateConfig(config, configPath) {
|
|
|
2817
3158
|
}
|
|
2818
3159
|
const cwd = process.cwd();
|
|
2819
3160
|
const possiblePaths = [
|
|
2820
|
-
|
|
2821
|
-
|
|
3161
|
+
path5.resolve(cwd, config.schema.directory),
|
|
3162
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
2822
3163
|
];
|
|
2823
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
3164
|
+
const schemaDir = possiblePaths.find((p) => fs5.existsSync(p));
|
|
2824
3165
|
if (!schemaDir) {
|
|
2825
3166
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
2826
3167
|
"schema.directory"
|
|
@@ -2832,15 +3173,15 @@ async function loadConfig(options = {}) {
|
|
|
2832
3173
|
let configFilePath;
|
|
2833
3174
|
const cwd = process.cwd();
|
|
2834
3175
|
if (options.config) {
|
|
2835
|
-
const explicitPath =
|
|
2836
|
-
if (!
|
|
3176
|
+
const explicitPath = path5.resolve(cwd, options.config);
|
|
3177
|
+
if (!fs5.existsSync(explicitPath)) {
|
|
2837
3178
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
2838
3179
|
}
|
|
2839
3180
|
configFilePath = explicitPath;
|
|
2840
3181
|
} else {
|
|
2841
|
-
const searchDirs = [cwd,
|
|
3182
|
+
const searchDirs = [cwd, path5.join(cwd, "shared")];
|
|
2842
3183
|
for (const dir of searchDirs) {
|
|
2843
|
-
if (
|
|
3184
|
+
if (fs5.existsSync(dir)) {
|
|
2844
3185
|
const found = findConfigFile(dir);
|
|
2845
3186
|
if (found) {
|
|
2846
3187
|
configFilePath = found;
|
|
@@ -2869,18 +3210,18 @@ async function loadConfig(options = {}) {
|
|
|
2869
3210
|
function getSchemaDirectory(config) {
|
|
2870
3211
|
const cwd = process.cwd();
|
|
2871
3212
|
const possiblePaths = [
|
|
2872
|
-
|
|
2873
|
-
|
|
3213
|
+
path5.resolve(cwd, config.schema.directory),
|
|
3214
|
+
path5.resolve(cwd, "shared", config.schema.directory)
|
|
2874
3215
|
];
|
|
2875
|
-
return possiblePaths.find((p) =>
|
|
3216
|
+
return possiblePaths.find((p) => fs5.existsSync(p)) || possiblePaths[0];
|
|
2876
3217
|
}
|
|
2877
3218
|
function getMigrationsDirectory(config) {
|
|
2878
3219
|
const cwd = process.cwd();
|
|
2879
3220
|
const possiblePaths = [
|
|
2880
|
-
|
|
2881
|
-
|
|
3221
|
+
path5.resolve(cwd, config.migrations.directory),
|
|
3222
|
+
path5.resolve(cwd, "shared", config.migrations.directory)
|
|
2882
3223
|
];
|
|
2883
|
-
return possiblePaths.find((p) =>
|
|
3224
|
+
return possiblePaths.find((p) => fs5.existsSync(p)) || possiblePaths[0];
|
|
2884
3225
|
}
|
|
2885
3226
|
var currentVerbosity = "normal";
|
|
2886
3227
|
function setVerbosity(level) {
|
|
@@ -3097,7 +3438,7 @@ async function executeGenerate(options) {
|
|
|
3097
3438
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3098
3439
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
3099
3440
|
logInfo("Loading previous snapshot...");
|
|
3100
|
-
const previousSnapshot =
|
|
3441
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3101
3442
|
migrationsPath: migrationsDir,
|
|
3102
3443
|
workspaceRoot: process.cwd()
|
|
3103
3444
|
});
|
|
@@ -3124,7 +3465,7 @@ async function executeGenerate(options) {
|
|
|
3124
3465
|
"Creating migration file...",
|
|
3125
3466
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
3126
3467
|
);
|
|
3127
|
-
logSuccess(`Migration file created: ${
|
|
3468
|
+
logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
|
|
3128
3469
|
logSection("\u2705 Next Steps");
|
|
3129
3470
|
console.log();
|
|
3130
3471
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -3302,7 +3643,7 @@ async function executeStatus(options) {
|
|
|
3302
3643
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3303
3644
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
3304
3645
|
logInfo("Loading previous snapshot...");
|
|
3305
|
-
const previousSnapshot =
|
|
3646
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3306
3647
|
migrationsPath: migrationsDir,
|
|
3307
3648
|
workspaceRoot: process.cwd()
|
|
3308
3649
|
});
|