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.
- package/CHANGELOG.md +7 -0
- package/dist/cli/index.cjs +406 -102
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +404 -100
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +409 -105
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +404 -100
- package/dist/cli/migrate.js.map +1 -1
- package/dist/index.cjs +515 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +511 -158
- package/dist/index.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 +457 -123
- 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 +456 -123
- 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.d.cts +3 -3
- package/dist/mutator.d.ts +3 -3
- package/dist/schema.cjs +34 -0
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +33 -1
- package/dist/schema.js.map +1 -1
- package/dist/types.d.cts +5 -2
- package/dist/types.d.ts +5 -2
- package/dist/user-_AM523hb.d.cts +123 -0
- package/dist/user-_AM523hb.d.ts +123 -0
- package/package.json +2 -3
- package/dist/user-C39DQ40N.d.cts +0 -53
- package/dist/user-C39DQ40N.d.ts +0 -53
package/dist/cli/migrate.cjs
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
var chalk = require('chalk');
|
|
5
5
|
var commander = require('commander');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var fs5 = require('fs');
|
|
7
|
+
var path5 = require('path');
|
|
8
8
|
var url = require('url');
|
|
9
9
|
var zod = require('zod');
|
|
10
10
|
var ora = require('ora');
|
|
@@ -30,8 +30,8 @@ function _interopNamespace(e) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
33
|
-
var
|
|
34
|
-
var
|
|
33
|
+
var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
|
|
34
|
+
var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
|
|
35
35
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
36
36
|
|
|
37
37
|
// ../node_modules/tsup/assets/cjs_shims.js
|
|
@@ -164,10 +164,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
164
164
|
operation;
|
|
165
165
|
code;
|
|
166
166
|
originalError;
|
|
167
|
-
constructor(message,
|
|
167
|
+
constructor(message, path7, operation, code, originalError) {
|
|
168
168
|
super(message);
|
|
169
169
|
this.name = "FileSystemError";
|
|
170
|
-
this.path =
|
|
170
|
+
this.path = path7;
|
|
171
171
|
this.operation = operation;
|
|
172
172
|
this.code = code;
|
|
173
173
|
this.originalError = originalError;
|
|
@@ -1108,20 +1108,20 @@ function mergeConfig(config) {
|
|
|
1108
1108
|
}
|
|
1109
1109
|
function resolveSchemaDir(config) {
|
|
1110
1110
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1111
|
-
if (
|
|
1111
|
+
if (path5__namespace.isAbsolute(config.schemaDir)) {
|
|
1112
1112
|
return config.schemaDir;
|
|
1113
1113
|
}
|
|
1114
|
-
return
|
|
1114
|
+
return path5__namespace.join(workspaceRoot, config.schemaDir);
|
|
1115
1115
|
}
|
|
1116
1116
|
function discoverSchemaFiles(config) {
|
|
1117
1117
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1118
1118
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1119
1119
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1120
1120
|
try {
|
|
1121
|
-
if (!
|
|
1121
|
+
if (!fs5__namespace.existsSync(schemaDir)) {
|
|
1122
1122
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1123
1123
|
}
|
|
1124
|
-
const files =
|
|
1124
|
+
const files = fs5__namespace.readdirSync(schemaDir);
|
|
1125
1125
|
const schemaFiles = files.filter((file) => {
|
|
1126
1126
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1127
1127
|
if (!hasValidExtension) return false;
|
|
@@ -1137,7 +1137,7 @@ function discoverSchemaFiles(config) {
|
|
|
1137
1137
|
});
|
|
1138
1138
|
return schemaFiles.map((file) => {
|
|
1139
1139
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1140
|
-
return
|
|
1140
|
+
return path5__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1141
1141
|
});
|
|
1142
1142
|
} catch (error) {
|
|
1143
1143
|
if (error instanceof FileSystemError) {
|
|
@@ -1171,19 +1171,19 @@ async function importSchemaModule(filePath, config) {
|
|
|
1171
1171
|
let resolvedPath = null;
|
|
1172
1172
|
const jsPath = `${importPath}.js`;
|
|
1173
1173
|
const tsPath = `${importPath}.ts`;
|
|
1174
|
-
if (
|
|
1174
|
+
if (fs5__namespace.existsSync(jsPath)) {
|
|
1175
1175
|
resolvedPath = jsPath;
|
|
1176
|
-
} else if (
|
|
1176
|
+
} else if (fs5__namespace.existsSync(tsPath)) {
|
|
1177
1177
|
resolvedPath = tsPath;
|
|
1178
1178
|
} else {
|
|
1179
1179
|
resolvedPath = jsPath;
|
|
1180
1180
|
}
|
|
1181
|
-
const fileUrl = new URL(`file://${
|
|
1181
|
+
const fileUrl = new URL(`file://${path5__namespace.resolve(resolvedPath)}`);
|
|
1182
1182
|
const module = await import(fileUrl.href);
|
|
1183
1183
|
return module;
|
|
1184
1184
|
} catch (error) {
|
|
1185
1185
|
const tsPath = `${filePath}.ts`;
|
|
1186
|
-
const isTypeScriptFile =
|
|
1186
|
+
const isTypeScriptFile = fs5__namespace.existsSync(tsPath);
|
|
1187
1187
|
if (isTypeScriptFile) {
|
|
1188
1188
|
throw new SchemaParsingError(
|
|
1189
1189
|
`Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
|
|
@@ -1202,7 +1202,7 @@ Please either:
|
|
|
1202
1202
|
}
|
|
1203
1203
|
}
|
|
1204
1204
|
function getCollectionNameFromFile(filePath) {
|
|
1205
|
-
const filename =
|
|
1205
|
+
const filename = path5__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
1206
1206
|
return toCollectionName(filename);
|
|
1207
1207
|
}
|
|
1208
1208
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
@@ -1367,7 +1367,7 @@ async function buildSchemaDefinition(config) {
|
|
|
1367
1367
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
1368
1368
|
} else if (mergedConfig.useCompiledFiles) {
|
|
1369
1369
|
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
1370
|
-
if (
|
|
1370
|
+
if (fs5__namespace.existsSync(`${distPath}.js`) || fs5__namespace.existsSync(`${distPath}.mjs`)) {
|
|
1371
1371
|
importPath = distPath;
|
|
1372
1372
|
} else {
|
|
1373
1373
|
importPath = filePath;
|
|
@@ -1544,6 +1544,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
1544
1544
|
for (const key of allKeys) {
|
|
1545
1545
|
const currentValue = currentOptions[key];
|
|
1546
1546
|
const previousValue = previousOptions[key];
|
|
1547
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
1548
|
+
continue;
|
|
1549
|
+
}
|
|
1547
1550
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
1548
1551
|
changes.push({
|
|
1549
1552
|
property: `options.${key}`,
|
|
@@ -1564,11 +1567,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1564
1567
|
if (!currentRelation || !previousRelation) {
|
|
1565
1568
|
return changes;
|
|
1566
1569
|
}
|
|
1567
|
-
|
|
1570
|
+
const normalizeCollection = (collection) => {
|
|
1571
|
+
if (!collection) return collection;
|
|
1572
|
+
if (collection === "_pb_users_auth_") {
|
|
1573
|
+
return "Users";
|
|
1574
|
+
}
|
|
1575
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1576
|
+
if (nameMatch) {
|
|
1577
|
+
return nameMatch[1];
|
|
1578
|
+
}
|
|
1579
|
+
return collection;
|
|
1580
|
+
};
|
|
1581
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
1582
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
1583
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
1568
1584
|
changes.push({
|
|
1569
1585
|
property: "relation.collection",
|
|
1570
|
-
oldValue:
|
|
1571
|
-
|
|
1586
|
+
oldValue: normalizedPrevious,
|
|
1587
|
+
// Use normalized value for clarity
|
|
1588
|
+
newValue: normalizedCurrent
|
|
1589
|
+
// Use normalized value for clarity
|
|
1572
1590
|
});
|
|
1573
1591
|
}
|
|
1574
1592
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -1788,10 +1806,10 @@ function mergeConfig3(config) {
|
|
|
1788
1806
|
}
|
|
1789
1807
|
function resolveMigrationDir(config) {
|
|
1790
1808
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1791
|
-
if (
|
|
1809
|
+
if (path5__namespace.isAbsolute(config.migrationDir)) {
|
|
1792
1810
|
return config.migrationDir;
|
|
1793
1811
|
}
|
|
1794
|
-
return
|
|
1812
|
+
return path5__namespace.join(workspaceRoot, config.migrationDir);
|
|
1795
1813
|
}
|
|
1796
1814
|
function generateTimestamp(config) {
|
|
1797
1815
|
if (config?.timestampGenerator) {
|
|
@@ -1849,9 +1867,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
1849
1867
|
}
|
|
1850
1868
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
1851
1869
|
try {
|
|
1852
|
-
if (!
|
|
1870
|
+
if (!fs5__namespace.existsSync(migrationDir)) {
|
|
1853
1871
|
try {
|
|
1854
|
-
|
|
1872
|
+
fs5__namespace.mkdirSync(migrationDir, { recursive: true });
|
|
1855
1873
|
} catch (error) {
|
|
1856
1874
|
const fsError = error;
|
|
1857
1875
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -1872,15 +1890,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
1872
1890
|
);
|
|
1873
1891
|
}
|
|
1874
1892
|
}
|
|
1875
|
-
const filePath =
|
|
1876
|
-
|
|
1893
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
1894
|
+
fs5__namespace.writeFileSync(filePath, content, "utf-8");
|
|
1877
1895
|
return filePath;
|
|
1878
1896
|
} catch (error) {
|
|
1879
1897
|
if (error instanceof FileSystemError) {
|
|
1880
1898
|
throw error;
|
|
1881
1899
|
}
|
|
1882
1900
|
const fsError = error;
|
|
1883
|
-
const filePath =
|
|
1901
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
1884
1902
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
1885
1903
|
throw new FileSystemError(
|
|
1886
1904
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -2425,57 +2443,18 @@ function generate(diff, config) {
|
|
|
2425
2443
|
);
|
|
2426
2444
|
}
|
|
2427
2445
|
}
|
|
2446
|
+
|
|
2447
|
+
// src/migration/pocketbase-converter.ts
|
|
2428
2448
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2429
|
-
({
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
try {
|
|
2433
|
-
if (!fs4__namespace.existsSync(migrationsPath)) {
|
|
2434
|
-
return null;
|
|
2435
|
-
}
|
|
2436
|
-
const files = fs4__namespace.readdirSync(migrationsPath);
|
|
2437
|
-
const snapshotFiles = files.filter(
|
|
2438
|
-
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2439
|
-
);
|
|
2440
|
-
if (snapshotFiles.length === 0) {
|
|
2441
|
-
return null;
|
|
2442
|
-
}
|
|
2443
|
-
snapshotFiles.sort().reverse();
|
|
2444
|
-
const latestSnapshot = snapshotFiles[0];
|
|
2445
|
-
if (!latestSnapshot) {
|
|
2446
|
-
return null;
|
|
2447
|
-
}
|
|
2448
|
-
return path4__namespace.join(migrationsPath, latestSnapshot);
|
|
2449
|
-
} catch (error) {
|
|
2450
|
-
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2451
|
-
return null;
|
|
2449
|
+
function resolveCollectionIdToName(collectionId) {
|
|
2450
|
+
if (collectionId === "_pb_users_auth_") {
|
|
2451
|
+
return "Users";
|
|
2452
2452
|
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
if (!migrationsPath) {
|
|
2457
|
-
return null;
|
|
2453
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2454
|
+
if (nameMatch) {
|
|
2455
|
+
return nameMatch[1];
|
|
2458
2456
|
}
|
|
2459
|
-
|
|
2460
|
-
try {
|
|
2461
|
-
const migrationContent = fs4__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2462
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2463
|
-
} catch (error) {
|
|
2464
|
-
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2465
|
-
return null;
|
|
2466
|
-
}
|
|
2467
|
-
}
|
|
2468
|
-
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2469
|
-
if (latestSnapshotPath) {
|
|
2470
|
-
try {
|
|
2471
|
-
const migrationContent = fs4__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2472
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2473
|
-
} catch (error) {
|
|
2474
|
-
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2475
|
-
return null;
|
|
2476
|
-
}
|
|
2477
|
-
}
|
|
2478
|
-
return null;
|
|
2457
|
+
return collectionId;
|
|
2479
2458
|
}
|
|
2480
2459
|
function convertPocketBaseCollection(pbCollection) {
|
|
2481
2460
|
const fields = [];
|
|
@@ -2494,17 +2473,28 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2494
2473
|
type: pbField.type,
|
|
2495
2474
|
required: pbField.required || false
|
|
2496
2475
|
};
|
|
2497
|
-
|
|
2498
|
-
|
|
2476
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
2477
|
+
if (pbField.type === "select") {
|
|
2478
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
2479
|
+
field.options.values = pbField.values;
|
|
2480
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
2481
|
+
field.options.values = pbField.options.values;
|
|
2482
|
+
}
|
|
2499
2483
|
}
|
|
2500
2484
|
if (pbField.type === "relation") {
|
|
2485
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2486
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2501
2487
|
field.relation = {
|
|
2502
|
-
collection:
|
|
2503
|
-
cascadeDelete: pbField.options?.cascadeDelete
|
|
2504
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2505
|
-
minSelect: pbField.options?.minSelect
|
|
2488
|
+
collection: collectionName,
|
|
2489
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
2490
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
2491
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
2506
2492
|
};
|
|
2507
2493
|
}
|
|
2494
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
2495
|
+
if (Object.keys(field.options).length === 0) {
|
|
2496
|
+
delete field.options;
|
|
2497
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
2508
2498
|
fields.push(field);
|
|
2509
2499
|
}
|
|
2510
2500
|
}
|
|
@@ -2569,6 +2559,320 @@ function convertPocketBaseMigration(migrationContent) {
|
|
|
2569
2559
|
}
|
|
2570
2560
|
}
|
|
2571
2561
|
|
|
2562
|
+
// src/migration/migration-parser.ts
|
|
2563
|
+
function extractTimestampFromFilename(filename) {
|
|
2564
|
+
const match = filename.match(/^(\d+)_/);
|
|
2565
|
+
if (match) {
|
|
2566
|
+
return parseInt(match[1], 10);
|
|
2567
|
+
}
|
|
2568
|
+
return null;
|
|
2569
|
+
}
|
|
2570
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
2571
|
+
try {
|
|
2572
|
+
if (!fs5__namespace.existsSync(migrationsPath)) {
|
|
2573
|
+
return [];
|
|
2574
|
+
}
|
|
2575
|
+
const files = fs5__namespace.readdirSync(migrationsPath);
|
|
2576
|
+
const migrationFiles = [];
|
|
2577
|
+
for (const file of files) {
|
|
2578
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
2579
|
+
continue;
|
|
2580
|
+
}
|
|
2581
|
+
if (!file.endsWith(".js")) {
|
|
2582
|
+
continue;
|
|
2583
|
+
}
|
|
2584
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
2585
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
2586
|
+
migrationFiles.push({
|
|
2587
|
+
path: path5__namespace.join(migrationsPath, file),
|
|
2588
|
+
timestamp
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
2593
|
+
return migrationFiles.map((f) => f.path);
|
|
2594
|
+
} catch (error) {
|
|
2595
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
2596
|
+
return [];
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
function parseMigrationOperationsFromContent(content) {
|
|
2600
|
+
const collectionsToCreate = [];
|
|
2601
|
+
const collectionsToDelete = [];
|
|
2602
|
+
try {
|
|
2603
|
+
let searchIndex = 0;
|
|
2604
|
+
while (true) {
|
|
2605
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
2606
|
+
if (collectionStart === -1) {
|
|
2607
|
+
break;
|
|
2608
|
+
}
|
|
2609
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
2610
|
+
let braceCount = 0;
|
|
2611
|
+
let parenCount = 1;
|
|
2612
|
+
let inString = false;
|
|
2613
|
+
let stringChar = null;
|
|
2614
|
+
let i = openParen;
|
|
2615
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
2616
|
+
i++;
|
|
2617
|
+
}
|
|
2618
|
+
if (content[i] !== "{") {
|
|
2619
|
+
searchIndex = i + 1;
|
|
2620
|
+
continue;
|
|
2621
|
+
}
|
|
2622
|
+
const objectStart = i;
|
|
2623
|
+
braceCount = 1;
|
|
2624
|
+
i++;
|
|
2625
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
2626
|
+
const char = content[i];
|
|
2627
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
2628
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2629
|
+
inString = true;
|
|
2630
|
+
stringChar = char;
|
|
2631
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2632
|
+
inString = false;
|
|
2633
|
+
stringChar = null;
|
|
2634
|
+
}
|
|
2635
|
+
if (!inString) {
|
|
2636
|
+
if (char === "{") braceCount++;
|
|
2637
|
+
if (char === "}") braceCount--;
|
|
2638
|
+
if (char === "(") parenCount++;
|
|
2639
|
+
if (char === ")") parenCount--;
|
|
2640
|
+
}
|
|
2641
|
+
i++;
|
|
2642
|
+
}
|
|
2643
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
2644
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
2645
|
+
try {
|
|
2646
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
2647
|
+
if (collectionObj && collectionObj.name) {
|
|
2648
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
2649
|
+
collectionsToCreate.push(schema);
|
|
2650
|
+
}
|
|
2651
|
+
} catch (error) {
|
|
2652
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
searchIndex = i;
|
|
2656
|
+
}
|
|
2657
|
+
const deleteMatches = content.matchAll(
|
|
2658
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
2659
|
+
);
|
|
2660
|
+
for (const match of deleteMatches) {
|
|
2661
|
+
if (match[1]) {
|
|
2662
|
+
collectionsToDelete.push(match[1]);
|
|
2663
|
+
} else {
|
|
2664
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
2665
|
+
if (varNameMatch) {
|
|
2666
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
2667
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
2668
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
2669
|
+
const varDefMatch = beforeDelete.match(
|
|
2670
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
2671
|
+
);
|
|
2672
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
2673
|
+
const collectionDefMatch = beforeDelete.match(
|
|
2674
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
2675
|
+
);
|
|
2676
|
+
if (collectionDefMatch) {
|
|
2677
|
+
try {
|
|
2678
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
2679
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
2680
|
+
if (collectionObj && collectionObj.name) {
|
|
2681
|
+
collectionsToDelete.push(collectionObj.name);
|
|
2682
|
+
}
|
|
2683
|
+
} catch {
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
const findAndDeleteMatches = content.matchAll(
|
|
2691
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
2692
|
+
);
|
|
2693
|
+
for (const match of findAndDeleteMatches) {
|
|
2694
|
+
collectionsToDelete.push(match[1]);
|
|
2695
|
+
}
|
|
2696
|
+
} catch (error) {
|
|
2697
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
2698
|
+
}
|
|
2699
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
2700
|
+
}
|
|
2701
|
+
function parseMigrationOperations(migrationContent) {
|
|
2702
|
+
try {
|
|
2703
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
2704
|
+
if (!migrateMatch) {
|
|
2705
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2706
|
+
}
|
|
2707
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
2708
|
+
let i = startIndex;
|
|
2709
|
+
let parenCount = 0;
|
|
2710
|
+
let foundFirstParen = false;
|
|
2711
|
+
while (i < migrationContent.length) {
|
|
2712
|
+
const char = migrationContent[i];
|
|
2713
|
+
if (char === "(") {
|
|
2714
|
+
parenCount++;
|
|
2715
|
+
foundFirstParen = true;
|
|
2716
|
+
i++;
|
|
2717
|
+
break;
|
|
2718
|
+
}
|
|
2719
|
+
i++;
|
|
2720
|
+
}
|
|
2721
|
+
if (!foundFirstParen) {
|
|
2722
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2723
|
+
}
|
|
2724
|
+
let inString = false;
|
|
2725
|
+
let stringChar = null;
|
|
2726
|
+
let foundBrace = false;
|
|
2727
|
+
let braceStart = -1;
|
|
2728
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
2729
|
+
const char = migrationContent[i];
|
|
2730
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2731
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2732
|
+
inString = true;
|
|
2733
|
+
stringChar = char;
|
|
2734
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2735
|
+
inString = false;
|
|
2736
|
+
stringChar = null;
|
|
2737
|
+
}
|
|
2738
|
+
if (!inString) {
|
|
2739
|
+
if (char === "(") parenCount++;
|
|
2740
|
+
if (char === ")") {
|
|
2741
|
+
parenCount--;
|
|
2742
|
+
if (parenCount === 0) {
|
|
2743
|
+
i++;
|
|
2744
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2745
|
+
i++;
|
|
2746
|
+
}
|
|
2747
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
2748
|
+
i += 2;
|
|
2749
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2750
|
+
i++;
|
|
2751
|
+
}
|
|
2752
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
2753
|
+
foundBrace = true;
|
|
2754
|
+
braceStart = i + 1;
|
|
2755
|
+
break;
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
i++;
|
|
2762
|
+
}
|
|
2763
|
+
if (!foundBrace || braceStart === -1) {
|
|
2764
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2765
|
+
}
|
|
2766
|
+
let braceCount = 1;
|
|
2767
|
+
i = braceStart;
|
|
2768
|
+
inString = false;
|
|
2769
|
+
stringChar = null;
|
|
2770
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2771
|
+
const char = migrationContent[i];
|
|
2772
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2773
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2774
|
+
inString = true;
|
|
2775
|
+
stringChar = char;
|
|
2776
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2777
|
+
inString = false;
|
|
2778
|
+
stringChar = null;
|
|
2779
|
+
}
|
|
2780
|
+
if (!inString) {
|
|
2781
|
+
if (char === "{") braceCount++;
|
|
2782
|
+
if (char === "}") braceCount--;
|
|
2783
|
+
}
|
|
2784
|
+
i++;
|
|
2785
|
+
}
|
|
2786
|
+
if (braceCount === 0) {
|
|
2787
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2788
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2789
|
+
}
|
|
2790
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2791
|
+
} catch (error) {
|
|
2792
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2793
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
({
|
|
2797
|
+
workspaceRoot: process.cwd()});
|
|
2798
|
+
function findLatestSnapshot(migrationsPath) {
|
|
2799
|
+
try {
|
|
2800
|
+
if (!fs5__namespace.existsSync(migrationsPath)) {
|
|
2801
|
+
return null;
|
|
2802
|
+
}
|
|
2803
|
+
const files = fs5__namespace.readdirSync(migrationsPath);
|
|
2804
|
+
const snapshotFiles = files.filter(
|
|
2805
|
+
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2806
|
+
);
|
|
2807
|
+
if (snapshotFiles.length === 0) {
|
|
2808
|
+
return null;
|
|
2809
|
+
}
|
|
2810
|
+
snapshotFiles.sort().reverse();
|
|
2811
|
+
const latestSnapshot = snapshotFiles[0];
|
|
2812
|
+
if (!latestSnapshot) {
|
|
2813
|
+
return null;
|
|
2814
|
+
}
|
|
2815
|
+
return path5__namespace.join(migrationsPath, latestSnapshot);
|
|
2816
|
+
} catch (error) {
|
|
2817
|
+
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2818
|
+
return null;
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2822
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2823
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2824
|
+
updatedCollections.delete(collectionName);
|
|
2825
|
+
}
|
|
2826
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2827
|
+
updatedCollections.set(collection.name, collection);
|
|
2828
|
+
}
|
|
2829
|
+
return {
|
|
2830
|
+
...snapshot,
|
|
2831
|
+
collections: updatedCollections
|
|
2832
|
+
};
|
|
2833
|
+
}
|
|
2834
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2835
|
+
const migrationsPath = config.migrationsPath;
|
|
2836
|
+
if (!migrationsPath) {
|
|
2837
|
+
return null;
|
|
2838
|
+
}
|
|
2839
|
+
if (fs5__namespace.existsSync(migrationsPath) && fs5__namespace.statSync(migrationsPath).isFile()) {
|
|
2840
|
+
try {
|
|
2841
|
+
const migrationContent = fs5__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2842
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2843
|
+
} catch (error) {
|
|
2844
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2845
|
+
return null;
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2849
|
+
if (!latestSnapshotPath) {
|
|
2850
|
+
return null;
|
|
2851
|
+
}
|
|
2852
|
+
try {
|
|
2853
|
+
const migrationContent = fs5__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2854
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2855
|
+
const snapshotFilename = path5__namespace.basename(latestSnapshotPath);
|
|
2856
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2857
|
+
if (snapshotTimestamp) {
|
|
2858
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2859
|
+
for (const migrationFile of migrationFiles) {
|
|
2860
|
+
try {
|
|
2861
|
+
const migrationContent2 = fs5__namespace.readFileSync(migrationFile, "utf-8");
|
|
2862
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2863
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2864
|
+
} catch (error) {
|
|
2865
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
return snapshot;
|
|
2870
|
+
} catch (error) {
|
|
2871
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2872
|
+
return null;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2572
2876
|
// src/migration/validation.ts
|
|
2573
2877
|
function detectCollectionDeletions(diff) {
|
|
2574
2878
|
const changes = [];
|
|
@@ -2737,8 +3041,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
2737
3041
|
};
|
|
2738
3042
|
function findConfigFile(directory) {
|
|
2739
3043
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
2740
|
-
const filePath =
|
|
2741
|
-
if (
|
|
3044
|
+
const filePath = path5__namespace.join(directory, fileName);
|
|
3045
|
+
if (fs5__namespace.existsSync(filePath)) {
|
|
2742
3046
|
return filePath;
|
|
2743
3047
|
}
|
|
2744
3048
|
}
|
|
@@ -2746,7 +3050,7 @@ function findConfigFile(directory) {
|
|
|
2746
3050
|
}
|
|
2747
3051
|
function loadJsonConfig(configPath) {
|
|
2748
3052
|
try {
|
|
2749
|
-
const content =
|
|
3053
|
+
const content = fs5__namespace.readFileSync(configPath, "utf-8");
|
|
2750
3054
|
return JSON.parse(content);
|
|
2751
3055
|
} catch (error) {
|
|
2752
3056
|
if (error instanceof SyntaxError) {
|
|
@@ -2775,10 +3079,10 @@ async function loadJsConfig(configPath) {
|
|
|
2775
3079
|
}
|
|
2776
3080
|
}
|
|
2777
3081
|
async function loadConfigFile(configPath) {
|
|
2778
|
-
if (!
|
|
3082
|
+
if (!fs5__namespace.existsSync(configPath)) {
|
|
2779
3083
|
return null;
|
|
2780
3084
|
}
|
|
2781
|
-
const ext =
|
|
3085
|
+
const ext = path5__namespace.extname(configPath).toLowerCase();
|
|
2782
3086
|
if (ext === ".json") {
|
|
2783
3087
|
return loadJsonConfig(configPath);
|
|
2784
3088
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -2845,10 +3149,10 @@ function validateConfig(config, configPath) {
|
|
|
2845
3149
|
}
|
|
2846
3150
|
const cwd = process.cwd();
|
|
2847
3151
|
const possiblePaths = [
|
|
2848
|
-
|
|
2849
|
-
|
|
3152
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
3153
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
2850
3154
|
];
|
|
2851
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
3155
|
+
const schemaDir = possiblePaths.find((p) => fs5__namespace.existsSync(p));
|
|
2852
3156
|
if (!schemaDir) {
|
|
2853
3157
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
2854
3158
|
"schema.directory"
|
|
@@ -2860,15 +3164,15 @@ async function loadConfig(options = {}) {
|
|
|
2860
3164
|
let configFilePath;
|
|
2861
3165
|
const cwd = process.cwd();
|
|
2862
3166
|
if (options.config) {
|
|
2863
|
-
const explicitPath =
|
|
2864
|
-
if (!
|
|
3167
|
+
const explicitPath = path5__namespace.resolve(cwd, options.config);
|
|
3168
|
+
if (!fs5__namespace.existsSync(explicitPath)) {
|
|
2865
3169
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
2866
3170
|
}
|
|
2867
3171
|
configFilePath = explicitPath;
|
|
2868
3172
|
} else {
|
|
2869
|
-
const searchDirs = [cwd,
|
|
3173
|
+
const searchDirs = [cwd, path5__namespace.join(cwd, "shared")];
|
|
2870
3174
|
for (const dir of searchDirs) {
|
|
2871
|
-
if (
|
|
3175
|
+
if (fs5__namespace.existsSync(dir)) {
|
|
2872
3176
|
const found = findConfigFile(dir);
|
|
2873
3177
|
if (found) {
|
|
2874
3178
|
configFilePath = found;
|
|
@@ -2897,18 +3201,18 @@ async function loadConfig(options = {}) {
|
|
|
2897
3201
|
function getSchemaDirectory(config) {
|
|
2898
3202
|
const cwd = process.cwd();
|
|
2899
3203
|
const possiblePaths = [
|
|
2900
|
-
|
|
2901
|
-
|
|
3204
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
3205
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
2902
3206
|
];
|
|
2903
|
-
return possiblePaths.find((p) =>
|
|
3207
|
+
return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
|
|
2904
3208
|
}
|
|
2905
3209
|
function getMigrationsDirectory(config) {
|
|
2906
3210
|
const cwd = process.cwd();
|
|
2907
3211
|
const possiblePaths = [
|
|
2908
|
-
|
|
2909
|
-
|
|
3212
|
+
path5__namespace.resolve(cwd, config.migrations.directory),
|
|
3213
|
+
path5__namespace.resolve(cwd, "shared", config.migrations.directory)
|
|
2910
3214
|
];
|
|
2911
|
-
return possiblePaths.find((p) =>
|
|
3215
|
+
return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
|
|
2912
3216
|
}
|
|
2913
3217
|
var currentVerbosity = "normal";
|
|
2914
3218
|
function setVerbosity(level) {
|
|
@@ -3125,7 +3429,7 @@ async function executeGenerate(options) {
|
|
|
3125
3429
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3126
3430
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
3127
3431
|
logInfo("Loading previous snapshot...");
|
|
3128
|
-
const previousSnapshot =
|
|
3432
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3129
3433
|
migrationsPath: migrationsDir,
|
|
3130
3434
|
workspaceRoot: process.cwd()
|
|
3131
3435
|
});
|
|
@@ -3152,7 +3456,7 @@ async function executeGenerate(options) {
|
|
|
3152
3456
|
"Creating migration file...",
|
|
3153
3457
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
3154
3458
|
);
|
|
3155
|
-
logSuccess(`Migration file created: ${
|
|
3459
|
+
logSuccess(`Migration file created: ${path5__namespace.basename(migrationPath)}`);
|
|
3156
3460
|
logSection("\u2705 Next Steps");
|
|
3157
3461
|
console.log();
|
|
3158
3462
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -3330,7 +3634,7 @@ async function executeStatus(options) {
|
|
|
3330
3634
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3331
3635
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
3332
3636
|
logInfo("Loading previous snapshot...");
|
|
3333
|
-
const previousSnapshot =
|
|
3637
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3334
3638
|
migrationsPath: migrationsDir,
|
|
3335
3639
|
workspaceRoot: process.cwd()
|
|
3336
3640
|
});
|
|
@@ -3446,9 +3750,9 @@ Examples:
|
|
|
3446
3750
|
function getVersion() {
|
|
3447
3751
|
try {
|
|
3448
3752
|
const __filename2 = url.fileURLToPath(importMetaUrl);
|
|
3449
|
-
const __dirname =
|
|
3450
|
-
const packageJsonPath =
|
|
3451
|
-
const packageJson = JSON.parse(
|
|
3753
|
+
const __dirname = path5.dirname(__filename2);
|
|
3754
|
+
const packageJsonPath = path5.join(__dirname, "../../package.json");
|
|
3755
|
+
const packageJson = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
|
|
3452
3756
|
return packageJson.version || "0.0.0";
|
|
3453
3757
|
} catch {
|
|
3454
3758
|
console.warn("Warning: Could not read version from package.json");
|