pocketbase-zod-schema 0.2.4 → 0.3.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +209 -24
  3. package/dist/cli/index.cjs +406 -294
  4. package/dist/cli/index.cjs.map +1 -1
  5. package/dist/cli/index.d.cts +3 -1
  6. package/dist/cli/index.d.ts +3 -1
  7. package/dist/cli/index.js +406 -294
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/cli/migrate.cjs +406 -294
  10. package/dist/cli/migrate.cjs.map +1 -1
  11. package/dist/cli/migrate.js +406 -294
  12. package/dist/cli/migrate.js.map +1 -1
  13. package/dist/cli/utils/index.d.cts +3 -1
  14. package/dist/cli/utils/index.d.ts +3 -1
  15. package/dist/fields-UcOPu1OQ.d.cts +364 -0
  16. package/dist/fields-UcOPu1OQ.d.ts +364 -0
  17. package/dist/index.cjs +633 -112
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +4 -3
  20. package/dist/index.d.ts +4 -3
  21. package/dist/index.js +619 -101
  22. package/dist/index.js.map +1 -1
  23. package/dist/migration/analyzer.cjs +44 -0
  24. package/dist/migration/analyzer.cjs.map +1 -1
  25. package/dist/migration/analyzer.d.cts +2 -1
  26. package/dist/migration/analyzer.d.ts +2 -1
  27. package/dist/migration/analyzer.js +44 -0
  28. package/dist/migration/analyzer.js.map +1 -1
  29. package/dist/migration/diff.cjs +76 -1
  30. package/dist/migration/diff.cjs.map +1 -1
  31. package/dist/migration/diff.d.cts +3 -1
  32. package/dist/migration/diff.d.ts +3 -1
  33. package/dist/migration/diff.js +76 -1
  34. package/dist/migration/diff.js.map +1 -1
  35. package/dist/migration/generator.cjs +323 -46
  36. package/dist/migration/generator.cjs.map +1 -1
  37. package/dist/migration/generator.d.cts +60 -11
  38. package/dist/migration/generator.d.ts +60 -11
  39. package/dist/migration/generator.js +319 -47
  40. package/dist/migration/generator.js.map +1 -1
  41. package/dist/migration/index.cjs +433 -47
  42. package/dist/migration/index.cjs.map +1 -1
  43. package/dist/migration/index.d.cts +3 -2
  44. package/dist/migration/index.d.ts +3 -2
  45. package/dist/migration/index.js +432 -48
  46. package/dist/migration/index.js.map +1 -1
  47. package/dist/migration/snapshot.cjs.map +1 -1
  48. package/dist/migration/snapshot.d.cts +3 -1
  49. package/dist/migration/snapshot.d.ts +3 -1
  50. package/dist/migration/snapshot.js.map +1 -1
  51. package/dist/migration/utils/index.cjs +80 -0
  52. package/dist/migration/utils/index.cjs.map +1 -1
  53. package/dist/migration/utils/index.d.cts +39 -202
  54. package/dist/migration/utils/index.d.ts +39 -202
  55. package/dist/migration/utils/index.js +77 -1
  56. package/dist/migration/utils/index.js.map +1 -1
  57. package/dist/schema.cjs +200 -61
  58. package/dist/schema.cjs.map +1 -1
  59. package/dist/schema.d.cts +2 -85
  60. package/dist/schema.d.ts +2 -85
  61. package/dist/schema.js +186 -50
  62. package/dist/schema.js.map +1 -1
  63. package/dist/type-mapper-DrQmtznD.d.cts +208 -0
  64. package/dist/type-mapper-n231Fspm.d.ts +208 -0
  65. package/dist/{types-z1Dkjg8m.d.ts → types-Ds3NQvny.d.ts} +33 -2
  66. package/dist/{types-BbTgmg6H.d.cts → types-YoBjsa-A.d.cts} +33 -2
  67. package/package.json +1 -1
@@ -7,6 +7,7 @@ import * as path5 from 'path';
7
7
  import { dirname, join } from 'path';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { z } from 'zod';
10
+ import { randomBytes } from 'crypto';
10
11
  import ora from 'ora';
11
12
 
12
13
  ({
@@ -40,6 +41,18 @@ function extractRelationMetadata(description) {
40
41
  }
41
42
  return null;
42
43
  }
44
+ var FIELD_METADATA_KEY = "__pocketbase_field__";
45
+ function extractFieldMetadata(description) {
46
+ if (!description) return null;
47
+ try {
48
+ const parsed = JSON.parse(description);
49
+ if (parsed[FIELD_METADATA_KEY]) {
50
+ return parsed[FIELD_METADATA_KEY];
51
+ }
52
+ } catch {
53
+ }
54
+ return null;
55
+ }
43
56
 
44
57
  // src/migration/errors.ts
45
58
  var MigrationError = class _MigrationError extends Error {
@@ -1278,6 +1291,38 @@ function isAuthCollection(fields) {
1278
1291
  return hasEmail && hasPassword;
1279
1292
  }
1280
1293
  function buildFieldDefinition(fieldName, zodType) {
1294
+ const fieldMetadata = extractFieldMetadata(zodType.description);
1295
+ if (fieldMetadata) {
1296
+ let required2;
1297
+ if (fieldMetadata.type === "number") {
1298
+ if (fieldMetadata.options?.required !== void 0) {
1299
+ required2 = fieldMetadata.options.required;
1300
+ } else {
1301
+ required2 = false;
1302
+ }
1303
+ } else {
1304
+ required2 = isFieldRequired(zodType);
1305
+ }
1306
+ const { required: _required, ...options2 } = fieldMetadata.options || {};
1307
+ const fieldDef2 = {
1308
+ name: fieldName,
1309
+ type: fieldMetadata.type,
1310
+ required: required2,
1311
+ options: Object.keys(options2).length > 0 ? options2 : void 0
1312
+ };
1313
+ if (fieldMetadata.type === "relation") {
1314
+ const relationMetadata2 = extractRelationMetadata(zodType.description);
1315
+ if (relationMetadata2) {
1316
+ fieldDef2.relation = {
1317
+ collection: relationMetadata2.collection,
1318
+ maxSelect: relationMetadata2.maxSelect,
1319
+ minSelect: relationMetadata2.minSelect,
1320
+ cascadeDelete: relationMetadata2.cascadeDelete
1321
+ };
1322
+ }
1323
+ }
1324
+ return fieldDef2;
1325
+ }
1281
1326
  const fieldType = mapZodTypeToPocketBase(zodType, fieldName);
1282
1327
  const required = isFieldRequired(zodType);
1283
1328
  const options = extractFieldOptions(zodType);
@@ -1433,6 +1478,65 @@ async function buildSchemaDefinition(config) {
1433
1478
  async function parseSchemaFiles(config) {
1434
1479
  return buildSchemaDefinition(config);
1435
1480
  }
1481
+ function generateCollectionId() {
1482
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
1483
+ const idLength = 15;
1484
+ const bytes = randomBytes(idLength);
1485
+ let id = "pb_";
1486
+ for (let i = 0; i < idLength; i++) {
1487
+ const index = bytes[i] % chars.length;
1488
+ id += chars[index];
1489
+ }
1490
+ return id;
1491
+ }
1492
+ var CollectionIdRegistry = class {
1493
+ ids;
1494
+ constructor() {
1495
+ this.ids = /* @__PURE__ */ new Set();
1496
+ }
1497
+ /**
1498
+ * Generates a unique collection ID for a given collection name
1499
+ * Special case: Returns constant "_pb_users_auth_" for users collection
1500
+ * Retries up to 10 times if collision occurs (extremely rare)
1501
+ *
1502
+ * @param collectionName - The name of the collection
1503
+ * @returns A unique collection ID
1504
+ * @throws Error if unable to generate unique ID after max attempts
1505
+ */
1506
+ generate(collectionName) {
1507
+ if (collectionName && collectionName.toLowerCase() === "users") {
1508
+ const usersId = "_pb_users_auth_";
1509
+ this.register(usersId);
1510
+ return usersId;
1511
+ }
1512
+ const maxAttempts = 10;
1513
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
1514
+ const id = generateCollectionId();
1515
+ if (!this.has(id)) {
1516
+ this.register(id);
1517
+ return id;
1518
+ }
1519
+ }
1520
+ throw new Error("Failed to generate unique collection ID after maximum attempts");
1521
+ }
1522
+ /**
1523
+ * Checks if an ID has already been registered
1524
+ *
1525
+ * @param id - The collection ID to check
1526
+ * @returns True if the ID exists in the registry
1527
+ */
1528
+ has(id) {
1529
+ return this.ids.has(id);
1530
+ }
1531
+ /**
1532
+ * Registers a collection ID in the registry
1533
+ *
1534
+ * @param id - The collection ID to register
1535
+ */
1536
+ register(id) {
1537
+ this.ids.add(id);
1538
+ }
1539
+ };
1436
1540
 
1437
1541
  // src/migration/diff.ts
1438
1542
  var DEFAULT_CONFIG2 = {
@@ -1764,6 +1868,18 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
1764
1868
  const filteredCollectionsToDelete = collectionsToDelete.filter(
1765
1869
  (collection) => !isSystemCollection(collection.name, config)
1766
1870
  );
1871
+ const registry = new CollectionIdRegistry();
1872
+ const collectionsWithIds = filteredCollectionsToCreate.map((collection) => {
1873
+ if (collection.id) {
1874
+ registry.register(collection.id);
1875
+ return collection;
1876
+ }
1877
+ const id = registry.generate(collection.name);
1878
+ return {
1879
+ ...collection,
1880
+ id
1881
+ };
1882
+ });
1767
1883
  const collectionsToModify = [];
1768
1884
  const matchedCollections = matchCollectionsByName(currentSchema, previousSnapshot);
1769
1885
  for (const [currentCollection, previousCollection] of matchedCollections) {
@@ -1773,7 +1889,7 @@ function aggregateChanges(currentSchema, previousSnapshot, config) {
1773
1889
  }
1774
1890
  }
1775
1891
  return {
1776
- collectionsToCreate: filteredCollectionsToCreate,
1892
+ collectionsToCreate: collectionsWithIds,
1777
1893
  collectionsToDelete: filteredCollectionsToDelete,
1778
1894
  collectionsToModify
1779
1895
  };
@@ -1856,42 +1972,48 @@ function generateTimestamp(config) {
1856
1972
  }
1857
1973
  return Math.floor(Date.now() / 1e3).toString();
1858
1974
  }
1859
- function generateMigrationDescription(diff) {
1860
- const parts = [];
1861
- if (diff.collectionsToCreate.length > 0) {
1862
- if (diff.collectionsToCreate.length === 1) {
1863
- parts.push(`created_${diff.collectionsToCreate[0].name}`);
1864
- } else {
1865
- parts.push(`created_${diff.collectionsToCreate.length}_collections`);
1866
- }
1867
- }
1868
- if (diff.collectionsToDelete.length > 0) {
1869
- if (diff.collectionsToDelete.length === 1) {
1870
- parts.push(`deleted_${diff.collectionsToDelete[0].name}`);
1871
- } else {
1872
- parts.push(`deleted_${diff.collectionsToDelete.length}_collections`);
1873
- }
1874
- }
1875
- if (diff.collectionsToModify.length > 0) {
1876
- if (diff.collectionsToModify.length === 1) {
1877
- parts.push(`updated_${diff.collectionsToModify[0].collection}`);
1878
- } else {
1879
- parts.push(`updated_${diff.collectionsToModify.length}_collections`);
1880
- }
1975
+ function splitDiffByCollection(diff, baseTimestamp) {
1976
+ const operations = [];
1977
+ let currentTimestamp = parseInt(baseTimestamp, 10);
1978
+ for (const collection of diff.collectionsToCreate) {
1979
+ operations.push({
1980
+ type: "create",
1981
+ collection,
1982
+ timestamp: currentTimestamp.toString()
1983
+ });
1984
+ currentTimestamp += 1;
1881
1985
  }
1882
- if (parts.length === 0) {
1883
- return "no_changes";
1986
+ for (const modification of diff.collectionsToModify) {
1987
+ operations.push({
1988
+ type: "modify",
1989
+ collection: modification.collection,
1990
+ modifications: modification,
1991
+ timestamp: currentTimestamp.toString()
1992
+ });
1993
+ currentTimestamp += 1;
1884
1994
  }
1885
- let description = parts.join("_");
1886
- if (description.length > 80) {
1887
- description = description.substring(0, 77) + "...";
1995
+ for (const collection of diff.collectionsToDelete) {
1996
+ operations.push({
1997
+ type: "delete",
1998
+ collection: collection.name || collection,
1999
+ // Handle both object and string
2000
+ timestamp: currentTimestamp.toString()
2001
+ });
2002
+ currentTimestamp += 1;
1888
2003
  }
1889
- return description;
2004
+ return operations;
1890
2005
  }
1891
- function generateMigrationFilename(diff, config) {
1892
- const timestamp = generateTimestamp(config);
1893
- const description = generateMigrationDescription(diff);
1894
- return `${timestamp}_${description}.js`;
2006
+ function generateCollectionMigrationFilename(operation) {
2007
+ const timestamp = operation.timestamp;
2008
+ const operationType = operation.type === "modify" ? "updated" : operation.type === "create" ? "created" : "deleted";
2009
+ let collectionName;
2010
+ if (typeof operation.collection === "string") {
2011
+ collectionName = operation.collection;
2012
+ } else {
2013
+ collectionName = operation.collection.name;
2014
+ }
2015
+ const sanitizedName = collectionName.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase();
2016
+ return `${timestamp}_${operationType}_${sanitizedName}.js`;
1895
2017
  }
1896
2018
  function createMigrationFileStructure(upCode, downCode, config) {
1897
2019
  const mergedConfig = config ? mergeConfig3(config) : DEFAULT_CONFIG3;
@@ -1963,14 +2085,13 @@ function formatValue(value) {
1963
2085
  return "null";
1964
2086
  }
1965
2087
  if (typeof value === "string") {
1966
- return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n")}"`;
2088
+ return JSON.stringify(value);
1967
2089
  }
1968
2090
  if (typeof value === "number" || typeof value === "boolean") {
1969
2091
  return String(value);
1970
2092
  }
1971
2093
  if (Array.isArray(value)) {
1972
- const items = value.map((v) => formatValue(v)).join(", ");
1973
- return `[${items}]`;
2094
+ return JSON.stringify(value).replace(/","/g, '", "');
1974
2095
  }
1975
2096
  if (typeof value === "object") {
1976
2097
  const entries = Object.entries(value).map(([k, v]) => `${k}: ${formatValue(v)}`).join(", ");
@@ -1978,7 +2099,7 @@ function formatValue(value) {
1978
2099
  }
1979
2100
  return String(value);
1980
2101
  }
1981
- function generateFieldDefinitionObject(field) {
2102
+ function generateFieldDefinitionObject(field, collectionIdMap) {
1982
2103
  const parts = [];
1983
2104
  parts.push(` name: "${field.name}"`);
1984
2105
  parts.push(` type: "${field.type}"`);
@@ -1986,34 +2107,47 @@ function generateFieldDefinitionObject(field) {
1986
2107
  if (field.unique !== void 0) {
1987
2108
  parts.push(` unique: ${field.unique}`);
1988
2109
  }
2110
+ if (field.type === "select") {
2111
+ const maxSelect = field.options?.maxSelect ?? 1;
2112
+ parts.push(` maxSelect: ${maxSelect}`);
2113
+ const values = field.options?.values ?? [];
2114
+ parts.push(` values: ${formatValue(values)}`);
2115
+ }
1989
2116
  if (field.options && Object.keys(field.options).length > 0) {
1990
2117
  for (const [key, value] of Object.entries(field.options)) {
2118
+ if (field.type === "select" && (key === "maxSelect" || key === "values")) {
2119
+ continue;
2120
+ }
1991
2121
  parts.push(` ${key}: ${formatValue(value)}`);
1992
2122
  }
1993
2123
  }
1994
2124
  if (field.relation) {
1995
2125
  const isUsersCollection = field.relation.collection.toLowerCase() === "users";
1996
- const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
1997
- parts.push(` collectionId: ${collectionIdPlaceholder}`);
1998
- if (field.relation.maxSelect !== void 0) {
1999
- parts.push(` maxSelect: ${field.relation.maxSelect}`);
2000
- }
2001
- if (field.relation.minSelect !== void 0) {
2002
- parts.push(` minSelect: ${field.relation.minSelect}`);
2003
- }
2004
- if (field.relation.cascadeDelete !== void 0) {
2005
- parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
2126
+ let collectionIdValue;
2127
+ if (isUsersCollection) {
2128
+ collectionIdValue = '"_pb_users_auth_"';
2129
+ } else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
2130
+ collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
2131
+ } else {
2132
+ collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
2006
2133
  }
2134
+ parts.push(` collectionId: ${collectionIdValue}`);
2135
+ const maxSelect = field.relation.maxSelect ?? 1;
2136
+ parts.push(` maxSelect: ${maxSelect}`);
2137
+ const minSelect = field.relation.minSelect ?? null;
2138
+ parts.push(` minSelect: ${minSelect}`);
2139
+ const cascadeDelete = field.relation.cascadeDelete ?? false;
2140
+ parts.push(` cascadeDelete: ${cascadeDelete}`);
2007
2141
  }
2008
2142
  return ` {
2009
2143
  ${parts.join(",\n")},
2010
2144
  }`;
2011
2145
  }
2012
- function generateFieldsArray(fields) {
2146
+ function generateFieldsArray(fields, collectionIdMap) {
2013
2147
  if (fields.length === 0) {
2014
2148
  return "[]";
2015
2149
  }
2016
- const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field));
2150
+ const fieldObjects = fields.map((field) => generateFieldDefinitionObject(field, collectionIdMap));
2017
2151
  return `[
2018
2152
  ${fieldObjects.join(",\n")},
2019
2153
  ]`;
@@ -2072,7 +2206,7 @@ function generateIndexesArray(indexes) {
2072
2206
  if (!indexes || indexes.length === 0) {
2073
2207
  return "[]";
2074
2208
  }
2075
- const indexStrings = indexes.map((idx) => `"${idx}"`);
2209
+ const indexStrings = indexes.map((idx) => JSON.stringify(idx));
2076
2210
  return `[
2077
2211
  ${indexStrings.join(",\n ")},
2078
2212
  ]`;
@@ -2126,7 +2260,7 @@ function getSystemFields() {
2126
2260
  }
2127
2261
  ];
2128
2262
  }
2129
- function generateCollectionCreation(collection, varName = "collection", isLast = false) {
2263
+ function generateCollectionCreation(collection, varName = "collection", isLast = false, collectionIdMap) {
2130
2264
  const lines = [];
2131
2265
  lines.push(` const ${varName} = new Collection({`);
2132
2266
  lines.push(` name: "${collection.name}",`);
@@ -2140,7 +2274,7 @@ function generateCollectionCreation(collection, varName = "collection", isLast =
2140
2274
  }
2141
2275
  const systemFields = getSystemFields();
2142
2276
  const allFields = [...systemFields, ...collection.fields];
2143
- lines.push(` fields: ${generateFieldsArray(allFields)},`);
2277
+ lines.push(` fields: ${generateFieldsArray(allFields, collectionIdMap)},`);
2144
2278
  lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
2145
2279
  lines.push(` });`);
2146
2280
  lines.push(``);
@@ -2162,42 +2296,59 @@ function getFieldConstructorName(fieldType) {
2162
2296
  };
2163
2297
  return constructorMap[fieldType] || "TextField";
2164
2298
  }
2165
- function generateFieldConstructorOptions(field) {
2299
+ function generateFieldConstructorOptions(field, collectionIdMap) {
2166
2300
  const parts = [];
2167
2301
  parts.push(` name: "${field.name}"`);
2168
2302
  parts.push(` required: ${field.required}`);
2169
2303
  if (field.unique !== void 0) {
2170
2304
  parts.push(` unique: ${field.unique}`);
2171
2305
  }
2306
+ if (field.type === "select") {
2307
+ const maxSelect = field.options?.maxSelect ?? 1;
2308
+ parts.push(` maxSelect: ${maxSelect}`);
2309
+ const values = field.options?.values ?? [];
2310
+ parts.push(` values: ${formatValue(values)}`);
2311
+ }
2172
2312
  if (field.options && Object.keys(field.options).length > 0) {
2173
2313
  for (const [key, value] of Object.entries(field.options)) {
2174
- parts.push(` ${key}: ${formatValue(value)}`);
2314
+ if (field.type === "select" && (key === "maxSelect" || key === "values")) {
2315
+ continue;
2316
+ }
2317
+ if (field.type === "number" && key === "noDecimal") {
2318
+ parts.push(` onlyInt: ${formatValue(value)}`);
2319
+ } else {
2320
+ parts.push(` ${key}: ${formatValue(value)}`);
2321
+ }
2175
2322
  }
2176
2323
  }
2177
2324
  if (field.relation && field.type === "relation") {
2178
2325
  const isUsersCollection = field.relation.collection.toLowerCase() === "users";
2179
- const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
2180
- parts.push(` collectionId: ${collectionIdPlaceholder}`);
2181
- if (field.relation.maxSelect !== void 0) {
2182
- parts.push(` maxSelect: ${field.relation.maxSelect}`);
2183
- }
2184
- if (field.relation.minSelect !== void 0) {
2185
- parts.push(` minSelect: ${field.relation.minSelect}`);
2186
- }
2187
- if (field.relation.cascadeDelete !== void 0) {
2188
- parts.push(` cascadeDelete: ${field.relation.cascadeDelete}`);
2326
+ let collectionIdValue;
2327
+ if (isUsersCollection) {
2328
+ collectionIdValue = '"_pb_users_auth_"';
2329
+ } else if (collectionIdMap && collectionIdMap.has(field.relation.collection)) {
2330
+ collectionIdValue = `"${collectionIdMap.get(field.relation.collection)}"`;
2331
+ } else {
2332
+ collectionIdValue = `app.findCollectionByNameOrId("${field.relation.collection}").id`;
2189
2333
  }
2334
+ parts.push(` collectionId: ${collectionIdValue}`);
2335
+ const maxSelect = field.relation.maxSelect ?? 1;
2336
+ parts.push(` maxSelect: ${maxSelect}`);
2337
+ const minSelect = field.relation.minSelect ?? null;
2338
+ parts.push(` minSelect: ${minSelect}`);
2339
+ const cascadeDelete = field.relation.cascadeDelete ?? false;
2340
+ parts.push(` cascadeDelete: ${cascadeDelete}`);
2190
2341
  }
2191
2342
  return parts.join(",\n");
2192
2343
  }
2193
- function generateFieldAddition(collectionName, field, varName, isLast = false) {
2344
+ function generateFieldAddition(collectionName, field, varName, isLast = false, collectionIdMap) {
2194
2345
  const lines = [];
2195
2346
  const constructorName = getFieldConstructorName(field.type);
2196
2347
  const collectionVar = varName || `collection_${collectionName}_${field.name}`;
2197
2348
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2198
2349
  lines.push(``);
2199
2350
  lines.push(` ${collectionVar}.fields.add(new ${constructorName}({`);
2200
- lines.push(generateFieldConstructorOptions(field));
2351
+ lines.push(generateFieldConstructorOptions(field, collectionIdMap));
2201
2352
  lines.push(` }));`);
2202
2353
  lines.push(``);
2203
2354
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
@@ -2247,7 +2398,7 @@ function generateIndexAddition(collectionName, index, varName, isLast = false) {
2247
2398
  const lines = [];
2248
2399
  const collectionVar = varName || `collection_${collectionName}_idx`;
2249
2400
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2250
- lines.push(` ${collectionVar}.indexes.push("${index}");`);
2401
+ lines.push(` ${collectionVar}.indexes.push(${JSON.stringify(index)});`);
2251
2402
  lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
2252
2403
  return lines.join("\n");
2253
2404
  }
@@ -2256,7 +2407,7 @@ function generateIndexRemoval(collectionName, index, varName, isLast = false) {
2256
2407
  const collectionVar = varName || `collection_${collectionName}_idx`;
2257
2408
  const indexVar = `${collectionVar}_indexToRemove`;
2258
2409
  lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
2259
- lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === "${index}");`);
2410
+ lines.push(` const ${indexVar} = ${collectionVar}.indexes.findIndex(idx => idx === ${JSON.stringify(index)});`);
2260
2411
  lines.push(` if (${indexVar} !== -1) {`);
2261
2412
  lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
2262
2413
  lines.push(` }`);
@@ -2285,243 +2436,194 @@ function generateCollectionDeletion(collectionName, varName = "collection", isLa
2285
2436
  lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
2286
2437
  return lines.join("\n");
2287
2438
  }
2288
- function generateUpMigration(diff) {
2439
+ function generateOperationUpMigration(operation, collectionIdMap) {
2289
2440
  const lines = [];
2290
- lines.push(` // UP MIGRATION`);
2291
- lines.push(``);
2292
- if (diff.collectionsToCreate.length > 0) {
2293
- lines.push(` // Create new collections`);
2294
- for (let i = 0; i < diff.collectionsToCreate.length; i++) {
2295
- const collection = diff.collectionsToCreate[i];
2296
- const varName = `collection_${collection.name}_create`;
2297
- lines.push(generateCollectionCreation(collection, varName));
2298
- lines.push(``);
2299
- }
2300
- }
2301
- if (diff.collectionsToModify.length > 0) {
2302
- lines.push(` // Modify existing collections`);
2303
- for (const modification of diff.collectionsToModify) {
2304
- const collectionName = modification.collection;
2305
- if (modification.fieldsToAdd.length > 0) {
2306
- lines.push(` // Add fields to ${collectionName}`);
2307
- for (const field of modification.fieldsToAdd) {
2308
- const varName = `collection_${collectionName}_add_${field.name}`;
2309
- lines.push(generateFieldAddition(collectionName, field, varName));
2310
- lines.push(``);
2311
- }
2312
- }
2313
- if (modification.fieldsToModify.length > 0) {
2314
- lines.push(` // Modify fields in ${collectionName}`);
2315
- for (const fieldMod of modification.fieldsToModify) {
2316
- const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
2317
- lines.push(generateFieldModification(collectionName, fieldMod, varName));
2318
- lines.push(``);
2319
- }
2320
- }
2321
- if (modification.fieldsToRemove.length > 0) {
2322
- lines.push(` // Remove fields from ${collectionName}`);
2323
- for (const field of modification.fieldsToRemove) {
2324
- const varName = `collection_${collectionName}_remove_${field.name}`;
2325
- lines.push(generateFieldDeletion(collectionName, field.name, varName));
2326
- lines.push(``);
2327
- }
2328
- }
2329
- if (modification.indexesToAdd.length > 0) {
2330
- lines.push(` // Add indexes to ${collectionName}`);
2331
- for (let i = 0; i < modification.indexesToAdd.length; i++) {
2332
- const index = modification.indexesToAdd[i];
2333
- const varName = `collection_${collectionName}_addidx_${i}`;
2334
- lines.push(generateIndexAddition(collectionName, index, varName));
2335
- lines.push(``);
2336
- }
2337
- }
2338
- if (modification.indexesToRemove.length > 0) {
2339
- lines.push(` // Remove indexes from ${collectionName}`);
2340
- for (let i = 0; i < modification.indexesToRemove.length; i++) {
2341
- const index = modification.indexesToRemove[i];
2342
- const varName = `collection_${collectionName}_rmidx_${i}`;
2343
- lines.push(generateIndexRemoval(collectionName, index, varName));
2344
- lines.push(``);
2345
- }
2346
- }
2347
- if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
2348
- lines.push(` // Update permissions for ${collectionName}`);
2349
- for (const permission of modification.permissionsToUpdate) {
2350
- const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
2351
- lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName));
2352
- lines.push(``);
2353
- }
2354
- } else if (modification.rulesToUpdate.length > 0) {
2355
- lines.push(` // Update rules for ${collectionName}`);
2356
- for (const rule of modification.rulesToUpdate) {
2357
- const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
2358
- lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName));
2359
- lines.push(``);
2360
- }
2361
- }
2441
+ if (operation.type === "create") {
2442
+ const collection = operation.collection;
2443
+ const varName = `collection_${collection.name}`;
2444
+ lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
2445
+ } else if (operation.type === "modify") {
2446
+ const modification = operation.modifications;
2447
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
2448
+ let operationCount = 0;
2449
+ const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
2450
+ for (const field of modification.fieldsToAdd) {
2451
+ operationCount++;
2452
+ const varName = `collection_${collectionName}_add_${field.name}`;
2453
+ const isLast = operationCount === totalOperations;
2454
+ lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
2455
+ if (!isLast) lines.push("");
2362
2456
  }
2363
- }
2364
- if (diff.collectionsToDelete.length > 0) {
2365
- lines.push(` // Delete collections`);
2366
- for (let i = 0; i < diff.collectionsToDelete.length; i++) {
2367
- const collection = diff.collectionsToDelete[i];
2368
- const varName = `collection_${collection.name}_delete`;
2369
- lines.push(generateCollectionDeletion(collection.name, varName));
2370
- lines.push(``);
2371
- }
2372
- }
2373
- if (lines.length === 2) {
2374
- lines.push(` // No changes detected`);
2375
- lines.push(``);
2376
- }
2377
- let code = lines.join("\n");
2378
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2379
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2380
- const saveMatches = [...code.matchAll(savePattern)];
2381
- const deleteMatches = [...code.matchAll(deletePattern)];
2382
- const allMatches = [
2383
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2384
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2385
- ].sort((a, b) => b.index - a.index);
2386
- if (allMatches.length > 0) {
2387
- const lastMatch = allMatches[0];
2388
- if (lastMatch.type === "save") {
2389
- code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
2390
- } else {
2391
- code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
2457
+ for (const fieldMod of modification.fieldsToModify) {
2458
+ operationCount++;
2459
+ const varName = `collection_${collectionName}_modify_${fieldMod.fieldName}`;
2460
+ const isLast = operationCount === totalOperations;
2461
+ lines.push(generateFieldModification(collectionName, fieldMod, varName, isLast));
2462
+ if (!isLast) lines.push("");
2392
2463
  }
2464
+ for (const field of modification.fieldsToRemove) {
2465
+ operationCount++;
2466
+ const varName = `collection_${collectionName}_remove_${field.name}`;
2467
+ const isLast = operationCount === totalOperations;
2468
+ lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
2469
+ if (!isLast) lines.push("");
2470
+ }
2471
+ for (let i = 0; i < modification.indexesToAdd.length; i++) {
2472
+ operationCount++;
2473
+ const index = modification.indexesToAdd[i];
2474
+ const varName = `collection_${collectionName}_addidx_${i}`;
2475
+ const isLast = operationCount === totalOperations;
2476
+ lines.push(generateIndexAddition(collectionName, index, varName, isLast));
2477
+ if (!isLast) lines.push("");
2478
+ }
2479
+ for (let i = 0; i < modification.indexesToRemove.length; i++) {
2480
+ operationCount++;
2481
+ const index = modification.indexesToRemove[i];
2482
+ const varName = `collection_${collectionName}_rmidx_${i}`;
2483
+ const isLast = operationCount === totalOperations;
2484
+ lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
2485
+ if (!isLast) lines.push("");
2486
+ }
2487
+ if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
2488
+ for (const permission of modification.permissionsToUpdate) {
2489
+ operationCount++;
2490
+ const varName = `collection_${collectionName}_perm_${permission.ruleType}`;
2491
+ const isLast = operationCount === totalOperations;
2492
+ lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.newValue, varName, isLast));
2493
+ if (!isLast) lines.push("");
2494
+ }
2495
+ } else if (modification.rulesToUpdate.length > 0) {
2496
+ for (const rule of modification.rulesToUpdate) {
2497
+ operationCount++;
2498
+ const varName = `collection_${collectionName}_rule_${rule.ruleType}`;
2499
+ const isLast = operationCount === totalOperations;
2500
+ lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.newValue, varName, isLast));
2501
+ if (!isLast) lines.push("");
2502
+ }
2503
+ }
2504
+ } else if (operation.type === "delete") {
2505
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection.name;
2506
+ const varName = `collection_${collectionName}`;
2507
+ lines.push(generateCollectionDeletion(collectionName, varName, true));
2393
2508
  }
2394
- return code;
2509
+ return lines.join("\n");
2395
2510
  }
2396
- function generateDownMigration(diff) {
2511
+ function generateOperationDownMigration(operation, collectionIdMap) {
2397
2512
  const lines = [];
2398
- lines.push(` // DOWN MIGRATION (ROLLBACK)`);
2399
- lines.push(``);
2400
- if (diff.collectionsToDelete.length > 0) {
2401
- lines.push(` // Recreate deleted collections`);
2402
- for (let i = 0; i < diff.collectionsToDelete.length; i++) {
2403
- const collection = diff.collectionsToDelete[i];
2404
- const varName = `collection_${collection.name}_recreate`;
2405
- lines.push(generateCollectionCreation(collection, varName));
2406
- lines.push(``);
2513
+ if (operation.type === "create") {
2514
+ const collection = operation.collection;
2515
+ const varName = `collection_${collection.name}`;
2516
+ lines.push(generateCollectionDeletion(collection.name, varName, true));
2517
+ } else if (operation.type === "modify") {
2518
+ const modification = operation.modifications;
2519
+ const collectionName = typeof operation.collection === "string" ? operation.collection : operation.collection?.name ?? modification.collection;
2520
+ let operationCount = 0;
2521
+ const totalOperations = modification.fieldsToAdd.length + modification.fieldsToModify.length + modification.fieldsToRemove.length + modification.indexesToAdd.length + modification.indexesToRemove.length + modification.rulesToUpdate.length + modification.permissionsToUpdate.length;
2522
+ if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
2523
+ for (const permission of modification.permissionsToUpdate) {
2524
+ operationCount++;
2525
+ const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
2526
+ const isLast = operationCount === totalOperations;
2527
+ lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName, isLast));
2528
+ if (!isLast) lines.push("");
2529
+ }
2530
+ } else if (modification.rulesToUpdate.length > 0) {
2531
+ for (const rule of modification.rulesToUpdate) {
2532
+ operationCount++;
2533
+ const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
2534
+ const isLast = operationCount === totalOperations;
2535
+ lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName, isLast));
2536
+ if (!isLast) lines.push("");
2537
+ }
2538
+ }
2539
+ for (let i = 0; i < modification.indexesToRemove.length; i++) {
2540
+ operationCount++;
2541
+ const index = modification.indexesToRemove[i];
2542
+ const varName = `collection_${collectionName}_restore_idx_${i}`;
2543
+ const isLast = operationCount === totalOperations;
2544
+ lines.push(generateIndexAddition(collectionName, index, varName, isLast));
2545
+ if (!isLast) lines.push("");
2546
+ }
2547
+ for (let i = 0; i < modification.indexesToAdd.length; i++) {
2548
+ operationCount++;
2549
+ const index = modification.indexesToAdd[i];
2550
+ const varName = `collection_${collectionName}_revert_idx_${i}`;
2551
+ const isLast = operationCount === totalOperations;
2552
+ lines.push(generateIndexRemoval(collectionName, index, varName, isLast));
2553
+ if (!isLast) lines.push("");
2407
2554
  }
2408
- }
2409
- if (diff.collectionsToModify.length > 0) {
2410
- lines.push(` // Revert modifications`);
2411
- for (const modification of diff.collectionsToModify) {
2412
- const collectionName = modification.collection;
2413
- if (modification.permissionsToUpdate && modification.permissionsToUpdate.length > 0) {
2414
- lines.push(` // Revert permissions for ${collectionName}`);
2415
- for (const permission of modification.permissionsToUpdate) {
2416
- const varName = `collection_${collectionName}_revert_perm_${permission.ruleType}`;
2417
- lines.push(generatePermissionUpdate(collectionName, permission.ruleType, permission.oldValue, varName));
2418
- lines.push(``);
2419
- }
2420
- } else if (modification.rulesToUpdate.length > 0) {
2421
- lines.push(` // Revert rules for ${collectionName}`);
2422
- for (const rule of modification.rulesToUpdate) {
2423
- const varName = `collection_${collectionName}_revert_rule_${rule.ruleType}`;
2424
- lines.push(generateRuleUpdate(collectionName, rule.ruleType, rule.oldValue, varName));
2425
- lines.push(``);
2426
- }
2427
- }
2428
- if (modification.indexesToRemove.length > 0) {
2429
- lines.push(` // Restore indexes to ${collectionName}`);
2430
- for (let i = 0; i < modification.indexesToRemove.length; i++) {
2431
- const index = modification.indexesToRemove[i];
2432
- const varName = `collection_${collectionName}_restore_idx_${i}`;
2433
- lines.push(generateIndexAddition(collectionName, index, varName));
2434
- lines.push(``);
2435
- }
2436
- }
2437
- if (modification.indexesToAdd.length > 0) {
2438
- lines.push(` // Remove indexes from ${collectionName}`);
2439
- for (let i = 0; i < modification.indexesToAdd.length; i++) {
2440
- const index = modification.indexesToAdd[i];
2441
- const varName = `collection_${collectionName}_revert_idx_${i}`;
2442
- lines.push(generateIndexRemoval(collectionName, index, varName));
2443
- lines.push(``);
2444
- }
2445
- }
2446
- if (modification.fieldsToRemove.length > 0) {
2447
- lines.push(` // Restore fields to ${collectionName}`);
2448
- for (const field of modification.fieldsToRemove) {
2449
- const varName = `collection_${collectionName}_restore_${field.name}`;
2450
- lines.push(generateFieldAddition(collectionName, field, varName));
2451
- lines.push(``);
2452
- }
2453
- }
2454
- if (modification.fieldsToModify.length > 0) {
2455
- lines.push(` // Revert field modifications in ${collectionName}`);
2456
- for (const fieldMod of modification.fieldsToModify) {
2457
- const reverseChanges = fieldMod.changes.map((change) => ({
2458
- property: change.property,
2459
- oldValue: change.newValue,
2460
- newValue: change.oldValue
2461
- }));
2462
- const reverseMod = {
2463
- fieldName: fieldMod.fieldName,
2464
- currentDefinition: fieldMod.newDefinition,
2465
- newDefinition: fieldMod.currentDefinition,
2466
- changes: reverseChanges
2467
- };
2468
- const varName = `collection_${collectionName}_revert_${fieldMod.fieldName}`;
2469
- lines.push(generateFieldModification(collectionName, reverseMod, varName));
2470
- lines.push(``);
2471
- }
2472
- }
2473
- if (modification.fieldsToAdd.length > 0) {
2474
- lines.push(` // Remove added fields from ${collectionName}`);
2475
- for (const field of modification.fieldsToAdd) {
2476
- const varName = `collection_${collectionName}_revert_add_${field.name}`;
2477
- lines.push(generateFieldDeletion(collectionName, field.name, varName));
2478
- lines.push(``);
2479
- }
2480
- }
2555
+ for (const field of modification.fieldsToRemove) {
2556
+ operationCount++;
2557
+ const varName = `collection_${collectionName}_restore_${field.name}`;
2558
+ const isLast = operationCount === totalOperations;
2559
+ lines.push(generateFieldAddition(collectionName, field, varName, isLast, collectionIdMap));
2560
+ if (!isLast) lines.push("");
2481
2561
  }
2482
- }
2483
- if (diff.collectionsToCreate.length > 0) {
2484
- lines.push(` // Delete created collections`);
2485
- for (let i = 0; i < diff.collectionsToCreate.length; i++) {
2486
- const collection = diff.collectionsToCreate[i];
2487
- const varName = `collection_${collection.name}_rollback`;
2488
- lines.push(generateCollectionDeletion(collection.name, varName));
2489
- lines.push(``);
2490
- }
2491
- }
2492
- if (lines.length === 2) {
2493
- lines.push(` // No changes to revert`);
2494
- lines.push(``);
2495
- }
2496
- let code = lines.join("\n");
2497
- const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
2498
- const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
2499
- const saveMatches = [...code.matchAll(savePattern)];
2500
- const deleteMatches = [...code.matchAll(deletePattern)];
2501
- const allMatches = [
2502
- ...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
2503
- ...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
2504
- ].sort((a, b) => b.index - a.index);
2505
- if (allMatches.length > 0) {
2506
- const lastMatch = allMatches[0];
2507
- if (lastMatch.type === "save") {
2508
- code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.save(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
2509
- } else {
2510
- code = code.substring(0, lastMatch.match.index) + lastMatch.match[1] + "return app.delete(" + lastMatch.match[2] + ");" + code.substring(lastMatch.match.index + lastMatch.match[0].length);
2562
+ for (const fieldMod of modification.fieldsToModify) {
2563
+ operationCount++;
2564
+ const reverseChanges = fieldMod.changes.map((change) => ({
2565
+ property: change.property,
2566
+ oldValue: change.newValue,
2567
+ newValue: change.oldValue
2568
+ }));
2569
+ const reverseMod = {
2570
+ fieldName: fieldMod.fieldName,
2571
+ currentDefinition: fieldMod.newDefinition,
2572
+ newDefinition: fieldMod.currentDefinition,
2573
+ changes: reverseChanges
2574
+ };
2575
+ const varName = `collection_${collectionName}_revert_${fieldMod.fieldName}`;
2576
+ const isLast = operationCount === totalOperations;
2577
+ lines.push(generateFieldModification(collectionName, reverseMod, varName, isLast));
2578
+ if (!isLast) lines.push("");
2579
+ }
2580
+ for (const field of modification.fieldsToAdd) {
2581
+ operationCount++;
2582
+ const varName = `collection_${collectionName}_revert_add_${field.name}`;
2583
+ const isLast = operationCount === totalOperations;
2584
+ lines.push(generateFieldDeletion(collectionName, field.name, varName, isLast));
2585
+ if (!isLast) lines.push("");
2586
+ }
2587
+ } else if (operation.type === "delete") {
2588
+ const collection = operation.collection;
2589
+ if (typeof collection !== "string") {
2590
+ const varName = `collection_${collection.name}`;
2591
+ lines.push(generateCollectionCreation(collection, varName, true, collectionIdMap));
2511
2592
  }
2512
2593
  }
2513
- return code;
2594
+ return lines.join("\n");
2514
2595
  }
2515
2596
  function generate(diff, config) {
2516
2597
  const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
2517
2598
  try {
2518
2599
  const migrationDir = resolveMigrationDir(normalizedConfig);
2519
- const upCode = generateUpMigration(diff);
2520
- const downCode = generateDownMigration(diff);
2521
- const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
2522
- const filename = generateMigrationFilename(diff, normalizedConfig);
2523
- const filePath = writeMigrationFile(migrationDir, filename, content);
2524
- return filePath;
2600
+ const hasChanges4 = diff.collectionsToCreate.length > 0 || diff.collectionsToModify.length > 0 || diff.collectionsToDelete.length > 0;
2601
+ if (!hasChanges4) {
2602
+ return [];
2603
+ }
2604
+ const collectionIdMap = /* @__PURE__ */ new Map();
2605
+ for (const collection of diff.collectionsToCreate) {
2606
+ if (collection.id) {
2607
+ collectionIdMap.set(collection.name, collection.id);
2608
+ }
2609
+ }
2610
+ for (const collection of diff.collectionsToDelete) {
2611
+ if (collection.id) {
2612
+ collectionIdMap.set(collection.name, collection.id);
2613
+ }
2614
+ }
2615
+ const baseTimestamp = generateTimestamp(normalizedConfig);
2616
+ const operations = splitDiffByCollection(diff, baseTimestamp);
2617
+ const filePaths = [];
2618
+ for (const operation of operations) {
2619
+ const upCode = generateOperationUpMigration(operation, collectionIdMap);
2620
+ const downCode = generateOperationDownMigration(operation, collectionIdMap);
2621
+ const content = createMigrationFileStructure(upCode, downCode, normalizedConfig);
2622
+ const filename = generateCollectionMigrationFilename(operation);
2623
+ const filePath = writeMigrationFile(migrationDir, filename, content);
2624
+ filePaths.push(filePath);
2625
+ }
2626
+ return filePaths;
2525
2627
  } catch (error) {
2526
2628
  if (error instanceof MigrationGenerationError || error instanceof FileSystemError) {
2527
2629
  throw error;
@@ -3542,15 +3644,25 @@ async function executeGenerate(options) {
3542
3644
  process.exit(1);
3543
3645
  }
3544
3646
  logSection("\u{1F4DD} Generating Migration");
3545
- const migrationPath = await withProgress(
3647
+ const migrationPaths = await withProgress(
3546
3648
  "Creating migration file...",
3547
3649
  () => Promise.resolve(generate(diff, migrationsDir))
3548
3650
  );
3549
- logSuccess(`Migration file created: ${path5.basename(migrationPath)}`);
3651
+ if (migrationPaths.length === 0) {
3652
+ logWarning("No migration files were generated (no changes detected).");
3653
+ return;
3654
+ }
3655
+ if (migrationPaths.length === 1) {
3656
+ logSuccess(`Migration file created: ${path5.basename(migrationPaths[0])}`);
3657
+ } else {
3658
+ logSuccess(`Created ${migrationPaths.length} migration files`);
3659
+ }
3550
3660
  logSection("\u2705 Next Steps");
3551
3661
  console.log();
3552
- console.log(" 1. Review the generated migration file:");
3553
- console.log(` ${migrationPath}`);
3662
+ console.log(" 1. Review the generated migration file(s):");
3663
+ migrationPaths.forEach((migrationPath) => {
3664
+ console.log(` ${migrationPath}`);
3665
+ });
3554
3666
  console.log();
3555
3667
  console.log(" 2. Apply the migration by running PocketBase:");
3556
3668
  console.log(" yarn pb");