pocketbase-zod-schema 0.1.3 → 0.1.4

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/cli/index.cjs +406 -102
  3. package/dist/cli/index.cjs.map +1 -1
  4. package/dist/cli/index.js +404 -100
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/migrate.cjs +409 -105
  7. package/dist/cli/migrate.cjs.map +1 -1
  8. package/dist/cli/migrate.js +404 -100
  9. package/dist/cli/migrate.js.map +1 -1
  10. package/dist/index.cjs +515 -159
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +3 -3
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.js +511 -158
  15. package/dist/index.js.map +1 -1
  16. package/dist/migration/diff.cjs +21 -3
  17. package/dist/migration/diff.cjs.map +1 -1
  18. package/dist/migration/diff.js +21 -3
  19. package/dist/migration/diff.js.map +1 -1
  20. package/dist/migration/index.cjs +457 -123
  21. package/dist/migration/index.cjs.map +1 -1
  22. package/dist/migration/index.d.cts +1 -1
  23. package/dist/migration/index.d.ts +1 -1
  24. package/dist/migration/index.js +456 -123
  25. package/dist/migration/index.js.map +1 -1
  26. package/dist/migration/snapshot.cjs +432 -118
  27. package/dist/migration/snapshot.cjs.map +1 -1
  28. package/dist/migration/snapshot.d.cts +34 -12
  29. package/dist/migration/snapshot.d.ts +34 -12
  30. package/dist/migration/snapshot.js +430 -117
  31. package/dist/migration/snapshot.js.map +1 -1
  32. package/dist/mutator.d.cts +3 -3
  33. package/dist/mutator.d.ts +3 -3
  34. package/dist/schema.cjs +34 -0
  35. package/dist/schema.cjs.map +1 -1
  36. package/dist/schema.d.cts +1 -1
  37. package/dist/schema.d.ts +1 -1
  38. package/dist/schema.js +33 -1
  39. package/dist/schema.js.map +1 -1
  40. package/dist/types.d.cts +5 -2
  41. package/dist/types.d.ts +5 -2
  42. package/dist/user-_AM523hb.d.cts +123 -0
  43. package/dist/user-_AM523hb.d.ts +123 -0
  44. package/package.json +2 -3
  45. package/dist/user-C39DQ40N.d.cts +0 -53
  46. package/dist/user-C39DQ40N.d.ts +0 -53
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as path4 from 'path';
2
- import * as fs4 from 'fs';
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, path6, operation, code, originalError) {
135
+ constructor(message, path7, operation, code, originalError) {
136
136
  super(message);
137
137
  this.name = "FileSystemError";
138
- this.path = path6;
138
+ this.path = path7;
139
139
  this.operation = operation;
140
140
  this.code = code;
141
141
  this.originalError = originalError;
@@ -1076,20 +1076,20 @@ function mergeConfig(config) {
1076
1076
  }
1077
1077
  function resolveSchemaDir(config) {
1078
1078
  const workspaceRoot = config.workspaceRoot || process.cwd();
1079
- if (path4.isAbsolute(config.schemaDir)) {
1079
+ if (path5.isAbsolute(config.schemaDir)) {
1080
1080
  return config.schemaDir;
1081
1081
  }
1082
- return path4.join(workspaceRoot, config.schemaDir);
1082
+ return path5.join(workspaceRoot, config.schemaDir);
1083
1083
  }
1084
1084
  function discoverSchemaFiles(config) {
1085
1085
  const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
1086
1086
  const mergedConfig = mergeConfig(normalizedConfig);
1087
1087
  const schemaDir = resolveSchemaDir(normalizedConfig);
1088
1088
  try {
1089
- if (!fs4.existsSync(schemaDir)) {
1089
+ if (!fs5.existsSync(schemaDir)) {
1090
1090
  throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
1091
1091
  }
1092
- const files = fs4.readdirSync(schemaDir);
1092
+ const files = fs5.readdirSync(schemaDir);
1093
1093
  const schemaFiles = files.filter((file) => {
1094
1094
  const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
1095
1095
  if (!hasValidExtension) return false;
@@ -1105,7 +1105,7 @@ function discoverSchemaFiles(config) {
1105
1105
  });
1106
1106
  return schemaFiles.map((file) => {
1107
1107
  const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
1108
- return path4.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
1108
+ return path5.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
1109
1109
  });
1110
1110
  } catch (error) {
1111
1111
  if (error instanceof FileSystemError) {
@@ -1139,19 +1139,19 @@ async function importSchemaModule(filePath, config) {
1139
1139
  let resolvedPath = null;
1140
1140
  const jsPath = `${importPath}.js`;
1141
1141
  const tsPath = `${importPath}.ts`;
1142
- if (fs4.existsSync(jsPath)) {
1142
+ if (fs5.existsSync(jsPath)) {
1143
1143
  resolvedPath = jsPath;
1144
- } else if (fs4.existsSync(tsPath)) {
1144
+ } else if (fs5.existsSync(tsPath)) {
1145
1145
  resolvedPath = tsPath;
1146
1146
  } else {
1147
1147
  resolvedPath = jsPath;
1148
1148
  }
1149
- const fileUrl = new URL(`file://${path4.resolve(resolvedPath)}`);
1149
+ const fileUrl = new URL(`file://${path5.resolve(resolvedPath)}`);
1150
1150
  const module = await import(fileUrl.href);
1151
1151
  return module;
1152
1152
  } catch (error) {
1153
1153
  const tsPath = `${filePath}.ts`;
1154
- const isTypeScriptFile = fs4.existsSync(tsPath);
1154
+ const isTypeScriptFile = fs5.existsSync(tsPath);
1155
1155
  if (isTypeScriptFile) {
1156
1156
  throw new SchemaParsingError(
1157
1157
  `Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
@@ -1170,7 +1170,7 @@ Please either:
1170
1170
  }
1171
1171
  }
1172
1172
  function getCollectionNameFromFile(filePath) {
1173
- const filename = path4.basename(filePath).replace(/\.(ts|js)$/, "");
1173
+ const filename = path5.basename(filePath).replace(/\.(ts|js)$/, "");
1174
1174
  return toCollectionName(filename);
1175
1175
  }
1176
1176
  function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
@@ -1335,7 +1335,7 @@ async function buildSchemaDefinition(config) {
1335
1335
  importPath = normalizedConfig.pathTransformer(filePath);
1336
1336
  } else if (mergedConfig.useCompiledFiles) {
1337
1337
  const distPath = filePath.replace(/\/src\//, "/dist/");
1338
- if (fs4.existsSync(`${distPath}.js`) || fs4.existsSync(`${distPath}.mjs`)) {
1338
+ if (fs5.existsSync(`${distPath}.js`) || fs5.existsSync(`${distPath}.mjs`)) {
1339
1339
  importPath = distPath;
1340
1340
  } else {
1341
1341
  importPath = filePath;
@@ -1512,6 +1512,9 @@ function compareFieldOptions(currentField, previousField) {
1512
1512
  for (const key of allKeys) {
1513
1513
  const currentValue = currentOptions[key];
1514
1514
  const previousValue = previousOptions[key];
1515
+ if (currentValue === void 0 && previousValue === void 0) {
1516
+ continue;
1517
+ }
1515
1518
  if (!areValuesEqual(currentValue, previousValue)) {
1516
1519
  changes.push({
1517
1520
  property: `options.${key}`,
@@ -1532,11 +1535,26 @@ function compareRelationConfigurations(currentField, previousField) {
1532
1535
  if (!currentRelation || !previousRelation) {
1533
1536
  return changes;
1534
1537
  }
1535
- if (currentRelation.collection !== previousRelation.collection) {
1538
+ const normalizeCollection = (collection) => {
1539
+ if (!collection) return collection;
1540
+ if (collection === "_pb_users_auth_") {
1541
+ return "Users";
1542
+ }
1543
+ const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
1544
+ if (nameMatch) {
1545
+ return nameMatch[1];
1546
+ }
1547
+ return collection;
1548
+ };
1549
+ const normalizedCurrent = normalizeCollection(currentRelation.collection);
1550
+ const normalizedPrevious = normalizeCollection(previousRelation.collection);
1551
+ if (normalizedCurrent !== normalizedPrevious) {
1536
1552
  changes.push({
1537
1553
  property: "relation.collection",
1538
- oldValue: previousRelation.collection,
1539
- newValue: currentRelation.collection
1554
+ oldValue: normalizedPrevious,
1555
+ // Use normalized value for clarity
1556
+ newValue: normalizedCurrent
1557
+ // Use normalized value for clarity
1540
1558
  });
1541
1559
  }
1542
1560
  if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
@@ -1756,10 +1774,10 @@ function mergeConfig3(config) {
1756
1774
  }
1757
1775
  function resolveMigrationDir(config) {
1758
1776
  const workspaceRoot = config.workspaceRoot || process.cwd();
1759
- if (path4.isAbsolute(config.migrationDir)) {
1777
+ if (path5.isAbsolute(config.migrationDir)) {
1760
1778
  return config.migrationDir;
1761
1779
  }
1762
- return path4.join(workspaceRoot, config.migrationDir);
1780
+ return path5.join(workspaceRoot, config.migrationDir);
1763
1781
  }
1764
1782
  function generateTimestamp(config) {
1765
1783
  if (config?.timestampGenerator) {
@@ -1817,9 +1835,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
1817
1835
  }
1818
1836
  function writeMigrationFile(migrationDir, filename, content) {
1819
1837
  try {
1820
- if (!fs4.existsSync(migrationDir)) {
1838
+ if (!fs5.existsSync(migrationDir)) {
1821
1839
  try {
1822
- fs4.mkdirSync(migrationDir, { recursive: true });
1840
+ fs5.mkdirSync(migrationDir, { recursive: true });
1823
1841
  } catch (error) {
1824
1842
  const fsError = error;
1825
1843
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
@@ -1840,15 +1858,15 @@ function writeMigrationFile(migrationDir, filename, content) {
1840
1858
  );
1841
1859
  }
1842
1860
  }
1843
- const filePath = path4.join(migrationDir, filename);
1844
- fs4.writeFileSync(filePath, content, "utf-8");
1861
+ const filePath = path5.join(migrationDir, filename);
1862
+ fs5.writeFileSync(filePath, content, "utf-8");
1845
1863
  return filePath;
1846
1864
  } catch (error) {
1847
1865
  if (error instanceof FileSystemError) {
1848
1866
  throw error;
1849
1867
  }
1850
1868
  const fsError = error;
1851
- const filePath = path4.join(migrationDir, filename);
1869
+ const filePath = path5.join(migrationDir, filename);
1852
1870
  if (fsError.code === "EACCES" || fsError.code === "EPERM") {
1853
1871
  throw new FileSystemError(
1854
1872
  `Permission denied writing migration file. Check file and directory permissions.`,
@@ -2393,57 +2411,18 @@ function generate(diff, config) {
2393
2411
  );
2394
2412
  }
2395
2413
  }
2414
+
2415
+ // src/migration/pocketbase-converter.ts
2396
2416
  var SNAPSHOT_VERSION = "1.0.0";
2397
- ({
2398
- workspaceRoot: process.cwd()});
2399
- function findLatestSnapshot(migrationsPath) {
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;
2417
+ function resolveCollectionIdToName(collectionId) {
2418
+ if (collectionId === "_pb_users_auth_") {
2419
+ return "Users";
2420
2420
  }
2421
- }
2422
- function loadSnapshotIfExists(config = {}) {
2423
- const migrationsPath = config.migrationsPath;
2424
- if (!migrationsPath) {
2425
- return null;
2421
+ const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
2422
+ if (nameMatch) {
2423
+ return nameMatch[1];
2426
2424
  }
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
- }
2435
- }
2436
- const latestSnapshotPath = findLatestSnapshot(migrationsPath);
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;
2425
+ return collectionId;
2447
2426
  }
2448
2427
  function convertPocketBaseCollection(pbCollection) {
2449
2428
  const fields = [];
@@ -2462,17 +2441,28 @@ function convertPocketBaseCollection(pbCollection) {
2462
2441
  type: pbField.type,
2463
2442
  required: pbField.required || false
2464
2443
  };
2465
- if (pbField.options) {
2466
- field.options = pbField.options;
2444
+ field.options = pbField.options ? { ...pbField.options } : {};
2445
+ if (pbField.type === "select") {
2446
+ if (pbField.values && Array.isArray(pbField.values)) {
2447
+ field.options.values = pbField.values;
2448
+ } else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
2449
+ field.options.values = pbField.options.values;
2450
+ }
2467
2451
  }
2468
2452
  if (pbField.type === "relation") {
2453
+ const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
2454
+ const collectionName = resolveCollectionIdToName(collectionId);
2469
2455
  field.relation = {
2470
- collection: pbField.options?.collectionId || "",
2471
- cascadeDelete: pbField.options?.cascadeDelete || false,
2472
- maxSelect: pbField.options?.maxSelect,
2473
- minSelect: pbField.options?.minSelect
2456
+ collection: collectionName,
2457
+ cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
2458
+ maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
2459
+ minSelect: pbField.minSelect ?? pbField.options?.minSelect
2474
2460
  };
2475
2461
  }
2462
+ const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
2463
+ if (Object.keys(field.options).length === 0) {
2464
+ delete field.options;
2465
+ } else if (pbField.type === "select" && hasOnlyValues) ;
2476
2466
  fields.push(field);
2477
2467
  }
2478
2468
  }
@@ -2537,6 +2527,320 @@ function convertPocketBaseMigration(migrationContent) {
2537
2527
  }
2538
2528
  }
2539
2529
 
2530
+ // src/migration/migration-parser.ts
2531
+ function extractTimestampFromFilename(filename) {
2532
+ const match = filename.match(/^(\d+)_/);
2533
+ if (match) {
2534
+ return parseInt(match[1], 10);
2535
+ }
2536
+ return null;
2537
+ }
2538
+ function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
2539
+ try {
2540
+ if (!fs5.existsSync(migrationsPath)) {
2541
+ return [];
2542
+ }
2543
+ const files = fs5.readdirSync(migrationsPath);
2544
+ const migrationFiles = [];
2545
+ for (const file of files) {
2546
+ if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
2547
+ continue;
2548
+ }
2549
+ if (!file.endsWith(".js")) {
2550
+ continue;
2551
+ }
2552
+ const timestamp = extractTimestampFromFilename(file);
2553
+ if (timestamp && timestamp > snapshotTimestamp) {
2554
+ migrationFiles.push({
2555
+ path: path5.join(migrationsPath, file),
2556
+ timestamp
2557
+ });
2558
+ }
2559
+ }
2560
+ migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
2561
+ return migrationFiles.map((f) => f.path);
2562
+ } catch (error) {
2563
+ console.warn(`Error finding migrations after snapshot: ${error}`);
2564
+ return [];
2565
+ }
2566
+ }
2567
+ function parseMigrationOperationsFromContent(content) {
2568
+ const collectionsToCreate = [];
2569
+ const collectionsToDelete = [];
2570
+ try {
2571
+ let searchIndex = 0;
2572
+ while (true) {
2573
+ const collectionStart = content.indexOf("new Collection(", searchIndex);
2574
+ if (collectionStart === -1) {
2575
+ break;
2576
+ }
2577
+ const openParen = collectionStart + "new Collection(".length;
2578
+ let braceCount = 0;
2579
+ let parenCount = 1;
2580
+ let inString = false;
2581
+ let stringChar = null;
2582
+ let i = openParen;
2583
+ while (i < content.length && /\s/.test(content[i])) {
2584
+ i++;
2585
+ }
2586
+ if (content[i] !== "{") {
2587
+ searchIndex = i + 1;
2588
+ continue;
2589
+ }
2590
+ const objectStart = i;
2591
+ braceCount = 1;
2592
+ i++;
2593
+ while (i < content.length && (braceCount > 0 || parenCount > 0)) {
2594
+ const char = content[i];
2595
+ const prevChar = i > 0 ? content[i - 1] : "";
2596
+ if (!inString && (char === '"' || char === "'")) {
2597
+ inString = true;
2598
+ stringChar = char;
2599
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2600
+ inString = false;
2601
+ stringChar = null;
2602
+ }
2603
+ if (!inString) {
2604
+ if (char === "{") braceCount++;
2605
+ if (char === "}") braceCount--;
2606
+ if (char === "(") parenCount++;
2607
+ if (char === ")") parenCount--;
2608
+ }
2609
+ i++;
2610
+ }
2611
+ if (braceCount === 0 && parenCount === 0) {
2612
+ const objectContent = content.substring(objectStart, i - 1);
2613
+ try {
2614
+ const collectionObj = new Function(`return ${objectContent}`)();
2615
+ if (collectionObj && collectionObj.name) {
2616
+ const schema = convertPocketBaseCollection(collectionObj);
2617
+ collectionsToCreate.push(schema);
2618
+ }
2619
+ } catch (error) {
2620
+ console.warn(`Failed to parse collection definition: ${error}`);
2621
+ }
2622
+ }
2623
+ searchIndex = i;
2624
+ }
2625
+ const deleteMatches = content.matchAll(
2626
+ /app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
2627
+ );
2628
+ for (const match of deleteMatches) {
2629
+ if (match[1]) {
2630
+ collectionsToDelete.push(match[1]);
2631
+ } else {
2632
+ const varNameMatch = match[0].match(/collection_(\w+)/);
2633
+ if (varNameMatch) {
2634
+ const varName = `collection_${varNameMatch[1]}`;
2635
+ const deleteIndex = content.indexOf(match[0]);
2636
+ const beforeDelete = content.substring(0, deleteIndex);
2637
+ const varDefMatch = beforeDelete.match(
2638
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
2639
+ );
2640
+ if (varDefMatch && varDefMatch.length > 0) {
2641
+ const collectionDefMatch = beforeDelete.match(
2642
+ new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
2643
+ );
2644
+ if (collectionDefMatch) {
2645
+ try {
2646
+ const collectionDefStr = collectionDefMatch[1];
2647
+ const collectionObj = new Function(`return ${collectionDefStr}`)();
2648
+ if (collectionObj && collectionObj.name) {
2649
+ collectionsToDelete.push(collectionObj.name);
2650
+ }
2651
+ } catch {
2652
+ }
2653
+ }
2654
+ }
2655
+ }
2656
+ }
2657
+ }
2658
+ const findAndDeleteMatches = content.matchAll(
2659
+ /app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
2660
+ );
2661
+ for (const match of findAndDeleteMatches) {
2662
+ collectionsToDelete.push(match[1]);
2663
+ }
2664
+ } catch (error) {
2665
+ console.warn(`Failed to parse migration operations from content: ${error}`);
2666
+ }
2667
+ return { collectionsToCreate, collectionsToDelete };
2668
+ }
2669
+ function parseMigrationOperations(migrationContent) {
2670
+ try {
2671
+ const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
2672
+ if (!migrateMatch) {
2673
+ return parseMigrationOperationsFromContent(migrationContent);
2674
+ }
2675
+ const startIndex = migrateMatch.index + migrateMatch[0].length;
2676
+ let i = startIndex;
2677
+ let parenCount = 0;
2678
+ let foundFirstParen = false;
2679
+ while (i < migrationContent.length) {
2680
+ const char = migrationContent[i];
2681
+ if (char === "(") {
2682
+ parenCount++;
2683
+ foundFirstParen = true;
2684
+ i++;
2685
+ break;
2686
+ }
2687
+ i++;
2688
+ }
2689
+ if (!foundFirstParen) {
2690
+ return parseMigrationOperationsFromContent(migrationContent);
2691
+ }
2692
+ let inString = false;
2693
+ let stringChar = null;
2694
+ let foundBrace = false;
2695
+ let braceStart = -1;
2696
+ while (i < migrationContent.length && !foundBrace) {
2697
+ const char = migrationContent[i];
2698
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2699
+ if (!inString && (char === '"' || char === "'")) {
2700
+ inString = true;
2701
+ stringChar = char;
2702
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2703
+ inString = false;
2704
+ stringChar = null;
2705
+ }
2706
+ if (!inString) {
2707
+ if (char === "(") parenCount++;
2708
+ if (char === ")") {
2709
+ parenCount--;
2710
+ if (parenCount === 0) {
2711
+ i++;
2712
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2713
+ i++;
2714
+ }
2715
+ if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
2716
+ i += 2;
2717
+ while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
2718
+ i++;
2719
+ }
2720
+ if (i < migrationContent.length && migrationContent[i] === "{") {
2721
+ foundBrace = true;
2722
+ braceStart = i + 1;
2723
+ break;
2724
+ }
2725
+ }
2726
+ }
2727
+ }
2728
+ }
2729
+ i++;
2730
+ }
2731
+ if (!foundBrace || braceStart === -1) {
2732
+ return parseMigrationOperationsFromContent(migrationContent);
2733
+ }
2734
+ let braceCount = 1;
2735
+ i = braceStart;
2736
+ inString = false;
2737
+ stringChar = null;
2738
+ while (i < migrationContent.length && braceCount > 0) {
2739
+ const char = migrationContent[i];
2740
+ const prevChar = i > 0 ? migrationContent[i - 1] : "";
2741
+ if (!inString && (char === '"' || char === "'")) {
2742
+ inString = true;
2743
+ stringChar = char;
2744
+ } else if (inString && char === stringChar && prevChar !== "\\") {
2745
+ inString = false;
2746
+ stringChar = null;
2747
+ }
2748
+ if (!inString) {
2749
+ if (char === "{") braceCount++;
2750
+ if (char === "}") braceCount--;
2751
+ }
2752
+ i++;
2753
+ }
2754
+ if (braceCount === 0) {
2755
+ const upMigrationContent = migrationContent.substring(braceStart, i - 1);
2756
+ return parseMigrationOperationsFromContent(upMigrationContent);
2757
+ }
2758
+ return parseMigrationOperationsFromContent(migrationContent);
2759
+ } catch (error) {
2760
+ console.warn(`Failed to parse migration operations: ${error}`);
2761
+ return { collectionsToCreate: [], collectionsToDelete: [] };
2762
+ }
2763
+ }
2764
+ ({
2765
+ workspaceRoot: process.cwd()});
2766
+ function findLatestSnapshot(migrationsPath) {
2767
+ try {
2768
+ if (!fs5.existsSync(migrationsPath)) {
2769
+ return null;
2770
+ }
2771
+ const files = fs5.readdirSync(migrationsPath);
2772
+ const snapshotFiles = files.filter(
2773
+ (file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
2774
+ );
2775
+ if (snapshotFiles.length === 0) {
2776
+ return null;
2777
+ }
2778
+ snapshotFiles.sort().reverse();
2779
+ const latestSnapshot = snapshotFiles[0];
2780
+ if (!latestSnapshot) {
2781
+ return null;
2782
+ }
2783
+ return path5.join(migrationsPath, latestSnapshot);
2784
+ } catch (error) {
2785
+ console.warn(`Error finding latest snapshot: ${error}`);
2786
+ return null;
2787
+ }
2788
+ }
2789
+ function applyMigrationOperations(snapshot, operations) {
2790
+ const updatedCollections = new Map(snapshot.collections);
2791
+ for (const collectionName of operations.collectionsToDelete) {
2792
+ updatedCollections.delete(collectionName);
2793
+ }
2794
+ for (const collection of operations.collectionsToCreate) {
2795
+ updatedCollections.set(collection.name, collection);
2796
+ }
2797
+ return {
2798
+ ...snapshot,
2799
+ collections: updatedCollections
2800
+ };
2801
+ }
2802
+ function loadSnapshotWithMigrations(config = {}) {
2803
+ const migrationsPath = config.migrationsPath;
2804
+ if (!migrationsPath) {
2805
+ return null;
2806
+ }
2807
+ if (fs5.existsSync(migrationsPath) && fs5.statSync(migrationsPath).isFile()) {
2808
+ try {
2809
+ const migrationContent = fs5.readFileSync(migrationsPath, "utf-8");
2810
+ return convertPocketBaseMigration(migrationContent);
2811
+ } catch (error) {
2812
+ console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
2813
+ return null;
2814
+ }
2815
+ }
2816
+ const latestSnapshotPath = findLatestSnapshot(migrationsPath);
2817
+ if (!latestSnapshotPath) {
2818
+ return null;
2819
+ }
2820
+ try {
2821
+ const migrationContent = fs5.readFileSync(latestSnapshotPath, "utf-8");
2822
+ let snapshot = convertPocketBaseMigration(migrationContent);
2823
+ const snapshotFilename = path5.basename(latestSnapshotPath);
2824
+ const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
2825
+ if (snapshotTimestamp) {
2826
+ const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
2827
+ for (const migrationFile of migrationFiles) {
2828
+ try {
2829
+ const migrationContent2 = fs5.readFileSync(migrationFile, "utf-8");
2830
+ const operations = parseMigrationOperations(migrationContent2);
2831
+ snapshot = applyMigrationOperations(snapshot, operations);
2832
+ } catch (error) {
2833
+ console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
2834
+ }
2835
+ }
2836
+ }
2837
+ return snapshot;
2838
+ } catch (error) {
2839
+ console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
2840
+ return null;
2841
+ }
2842
+ }
2843
+
2540
2844
  // src/migration/validation.ts
2541
2845
  function detectCollectionDeletions(diff) {
2542
2846
  const changes = [];
@@ -2705,8 +3009,8 @@ var DEFAULT_CONFIG5 = {
2705
3009
  };
2706
3010
  function findConfigFile(directory) {
2707
3011
  for (const fileName of CONFIG_FILE_NAMES) {
2708
- const filePath = path4.join(directory, fileName);
2709
- if (fs4.existsSync(filePath)) {
3012
+ const filePath = path5.join(directory, fileName);
3013
+ if (fs5.existsSync(filePath)) {
2710
3014
  return filePath;
2711
3015
  }
2712
3016
  }
@@ -2714,7 +3018,7 @@ function findConfigFile(directory) {
2714
3018
  }
2715
3019
  function loadJsonConfig(configPath) {
2716
3020
  try {
2717
- const content = fs4.readFileSync(configPath, "utf-8");
3021
+ const content = fs5.readFileSync(configPath, "utf-8");
2718
3022
  return JSON.parse(content);
2719
3023
  } catch (error) {
2720
3024
  if (error instanceof SyntaxError) {
@@ -2743,10 +3047,10 @@ async function loadJsConfig(configPath) {
2743
3047
  }
2744
3048
  }
2745
3049
  async function loadConfigFile(configPath) {
2746
- if (!fs4.existsSync(configPath)) {
3050
+ if (!fs5.existsSync(configPath)) {
2747
3051
  return null;
2748
3052
  }
2749
- const ext = path4.extname(configPath).toLowerCase();
3053
+ const ext = path5.extname(configPath).toLowerCase();
2750
3054
  if (ext === ".json") {
2751
3055
  return loadJsonConfig(configPath);
2752
3056
  } else if (ext === ".js" || ext === ".mjs") {
@@ -2813,10 +3117,10 @@ function validateConfig(config, configPath) {
2813
3117
  }
2814
3118
  const cwd = process.cwd();
2815
3119
  const possiblePaths = [
2816
- path4.resolve(cwd, config.schema.directory),
2817
- path4.resolve(cwd, "shared", config.schema.directory)
3120
+ path5.resolve(cwd, config.schema.directory),
3121
+ path5.resolve(cwd, "shared", config.schema.directory)
2818
3122
  ];
2819
- const schemaDir = possiblePaths.find((p) => fs4.existsSync(p));
3123
+ const schemaDir = possiblePaths.find((p) => fs5.existsSync(p));
2820
3124
  if (!schemaDir) {
2821
3125
  throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
2822
3126
  "schema.directory"
@@ -2828,15 +3132,15 @@ async function loadConfig(options = {}) {
2828
3132
  let configFilePath;
2829
3133
  const cwd = process.cwd();
2830
3134
  if (options.config) {
2831
- const explicitPath = path4.resolve(cwd, options.config);
2832
- if (!fs4.existsSync(explicitPath)) {
3135
+ const explicitPath = path5.resolve(cwd, options.config);
3136
+ if (!fs5.existsSync(explicitPath)) {
2833
3137
  throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
2834
3138
  }
2835
3139
  configFilePath = explicitPath;
2836
3140
  } else {
2837
- const searchDirs = [cwd, path4.join(cwd, "shared")];
3141
+ const searchDirs = [cwd, path5.join(cwd, "shared")];
2838
3142
  for (const dir of searchDirs) {
2839
- if (fs4.existsSync(dir)) {
3143
+ if (fs5.existsSync(dir)) {
2840
3144
  const found = findConfigFile(dir);
2841
3145
  if (found) {
2842
3146
  configFilePath = found;
@@ -2865,18 +3169,18 @@ async function loadConfig(options = {}) {
2865
3169
  function getSchemaDirectory(config) {
2866
3170
  const cwd = process.cwd();
2867
3171
  const possiblePaths = [
2868
- path4.resolve(cwd, config.schema.directory),
2869
- path4.resolve(cwd, "shared", config.schema.directory)
3172
+ path5.resolve(cwd, config.schema.directory),
3173
+ path5.resolve(cwd, "shared", config.schema.directory)
2870
3174
  ];
2871
- return possiblePaths.find((p) => fs4.existsSync(p)) || possiblePaths[0];
3175
+ return possiblePaths.find((p) => fs5.existsSync(p)) || possiblePaths[0];
2872
3176
  }
2873
3177
  function getMigrationsDirectory(config) {
2874
3178
  const cwd = process.cwd();
2875
3179
  const possiblePaths = [
2876
- path4.resolve(cwd, config.migrations.directory),
2877
- path4.resolve(cwd, "shared", config.migrations.directory)
3180
+ path5.resolve(cwd, config.migrations.directory),
3181
+ path5.resolve(cwd, "shared", config.migrations.directory)
2878
3182
  ];
2879
- return possiblePaths.find((p) => fs4.existsSync(p)) || possiblePaths[0];
3183
+ return possiblePaths.find((p) => fs5.existsSync(p)) || possiblePaths[0];
2880
3184
  }
2881
3185
  var currentVerbosity = "normal";
2882
3186
  function setVerbosity(level) {
@@ -3153,7 +3457,7 @@ async function executeGenerate(options) {
3153
3457
  const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3154
3458
  logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
3155
3459
  logInfo("Loading previous snapshot...");
3156
- const previousSnapshot = loadSnapshotIfExists({
3460
+ const previousSnapshot = loadSnapshotWithMigrations({
3157
3461
  migrationsPath: migrationsDir,
3158
3462
  workspaceRoot: process.cwd()
3159
3463
  });
@@ -3180,7 +3484,7 @@ async function executeGenerate(options) {
3180
3484
  "Creating migration file...",
3181
3485
  () => Promise.resolve(generate(diff, migrationsDir))
3182
3486
  );
3183
- logSuccess(`Migration file created: ${path4.basename(migrationPath)}`);
3487
+ logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
3184
3488
  logSection("\u2705 Next Steps");
3185
3489
  console.log();
3186
3490
  console.log(" 1. Review the generated migration file:");
@@ -3346,7 +3650,7 @@ async function executeStatus(options) {
3346
3650
  const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
3347
3651
  logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
3348
3652
  logInfo("Loading previous snapshot...");
3349
- const previousSnapshot = loadSnapshotIfExists({
3653
+ const previousSnapshot = loadSnapshotWithMigrations({
3350
3654
  migrationsPath: migrationsDir,
3351
3655
  workspaceRoot: process.cwd()
3352
3656
  });