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/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var path5 = require('path');
|
|
4
|
+
var fs5 = require('fs');
|
|
5
5
|
var zod = require('zod');
|
|
6
6
|
var chalk = require('chalk');
|
|
7
7
|
var ora = require('ora');
|
|
@@ -26,8 +26,8 @@ function _interopNamespace(e) {
|
|
|
26
26
|
return Object.freeze(n);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
var
|
|
30
|
-
var
|
|
29
|
+
var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
|
|
30
|
+
var fs5__namespace = /*#__PURE__*/_interopNamespace(fs5);
|
|
31
31
|
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
32
32
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
33
33
|
|
|
@@ -159,10 +159,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
159
159
|
operation;
|
|
160
160
|
code;
|
|
161
161
|
originalError;
|
|
162
|
-
constructor(message,
|
|
162
|
+
constructor(message, path7, operation, code, originalError) {
|
|
163
163
|
super(message);
|
|
164
164
|
this.name = "FileSystemError";
|
|
165
|
-
this.path =
|
|
165
|
+
this.path = path7;
|
|
166
166
|
this.operation = operation;
|
|
167
167
|
this.code = code;
|
|
168
168
|
this.originalError = originalError;
|
|
@@ -1103,20 +1103,20 @@ function mergeConfig(config) {
|
|
|
1103
1103
|
}
|
|
1104
1104
|
function resolveSchemaDir(config) {
|
|
1105
1105
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1106
|
-
if (
|
|
1106
|
+
if (path5__namespace.isAbsolute(config.schemaDir)) {
|
|
1107
1107
|
return config.schemaDir;
|
|
1108
1108
|
}
|
|
1109
|
-
return
|
|
1109
|
+
return path5__namespace.join(workspaceRoot, config.schemaDir);
|
|
1110
1110
|
}
|
|
1111
1111
|
function discoverSchemaFiles(config) {
|
|
1112
1112
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1113
1113
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1114
1114
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1115
1115
|
try {
|
|
1116
|
-
if (!
|
|
1116
|
+
if (!fs5__namespace.existsSync(schemaDir)) {
|
|
1117
1117
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1118
1118
|
}
|
|
1119
|
-
const files =
|
|
1119
|
+
const files = fs5__namespace.readdirSync(schemaDir);
|
|
1120
1120
|
const schemaFiles = files.filter((file) => {
|
|
1121
1121
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1122
1122
|
if (!hasValidExtension) return false;
|
|
@@ -1132,7 +1132,7 @@ function discoverSchemaFiles(config) {
|
|
|
1132
1132
|
});
|
|
1133
1133
|
return schemaFiles.map((file) => {
|
|
1134
1134
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1135
|
-
return
|
|
1135
|
+
return path5__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1136
1136
|
});
|
|
1137
1137
|
} catch (error) {
|
|
1138
1138
|
if (error instanceof FileSystemError) {
|
|
@@ -1166,19 +1166,19 @@ async function importSchemaModule(filePath, config) {
|
|
|
1166
1166
|
let resolvedPath = null;
|
|
1167
1167
|
const jsPath = `${importPath}.js`;
|
|
1168
1168
|
const tsPath = `${importPath}.ts`;
|
|
1169
|
-
if (
|
|
1169
|
+
if (fs5__namespace.existsSync(jsPath)) {
|
|
1170
1170
|
resolvedPath = jsPath;
|
|
1171
|
-
} else if (
|
|
1171
|
+
} else if (fs5__namespace.existsSync(tsPath)) {
|
|
1172
1172
|
resolvedPath = tsPath;
|
|
1173
1173
|
} else {
|
|
1174
1174
|
resolvedPath = jsPath;
|
|
1175
1175
|
}
|
|
1176
|
-
const fileUrl = new URL(`file://${
|
|
1176
|
+
const fileUrl = new URL(`file://${path5__namespace.resolve(resolvedPath)}`);
|
|
1177
1177
|
const module = await import(fileUrl.href);
|
|
1178
1178
|
return module;
|
|
1179
1179
|
} catch (error) {
|
|
1180
1180
|
const tsPath = `${filePath}.ts`;
|
|
1181
|
-
const isTypeScriptFile =
|
|
1181
|
+
const isTypeScriptFile = fs5__namespace.existsSync(tsPath);
|
|
1182
1182
|
if (isTypeScriptFile) {
|
|
1183
1183
|
throw new SchemaParsingError(
|
|
1184
1184
|
`Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
|
|
@@ -1197,7 +1197,7 @@ Please either:
|
|
|
1197
1197
|
}
|
|
1198
1198
|
}
|
|
1199
1199
|
function getCollectionNameFromFile(filePath) {
|
|
1200
|
-
const filename =
|
|
1200
|
+
const filename = path5__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
1201
1201
|
return toCollectionName(filename);
|
|
1202
1202
|
}
|
|
1203
1203
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
@@ -1362,7 +1362,7 @@ async function buildSchemaDefinition(config) {
|
|
|
1362
1362
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
1363
1363
|
} else if (mergedConfig.useCompiledFiles) {
|
|
1364
1364
|
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
1365
|
-
if (
|
|
1365
|
+
if (fs5__namespace.existsSync(`${distPath}.js`) || fs5__namespace.existsSync(`${distPath}.mjs`)) {
|
|
1366
1366
|
importPath = distPath;
|
|
1367
1367
|
} else {
|
|
1368
1368
|
importPath = filePath;
|
|
@@ -1539,6 +1539,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
1539
1539
|
for (const key of allKeys) {
|
|
1540
1540
|
const currentValue = currentOptions[key];
|
|
1541
1541
|
const previousValue = previousOptions[key];
|
|
1542
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1542
1545
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
1543
1546
|
changes.push({
|
|
1544
1547
|
property: `options.${key}`,
|
|
@@ -1559,11 +1562,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1559
1562
|
if (!currentRelation || !previousRelation) {
|
|
1560
1563
|
return changes;
|
|
1561
1564
|
}
|
|
1562
|
-
|
|
1565
|
+
const normalizeCollection = (collection) => {
|
|
1566
|
+
if (!collection) return collection;
|
|
1567
|
+
if (collection === "_pb_users_auth_") {
|
|
1568
|
+
return "Users";
|
|
1569
|
+
}
|
|
1570
|
+
const nameMatch = collection.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
1571
|
+
if (nameMatch) {
|
|
1572
|
+
return nameMatch[1];
|
|
1573
|
+
}
|
|
1574
|
+
return collection;
|
|
1575
|
+
};
|
|
1576
|
+
const normalizedCurrent = normalizeCollection(currentRelation.collection);
|
|
1577
|
+
const normalizedPrevious = normalizeCollection(previousRelation.collection);
|
|
1578
|
+
if (normalizedCurrent !== normalizedPrevious) {
|
|
1563
1579
|
changes.push({
|
|
1564
1580
|
property: "relation.collection",
|
|
1565
|
-
oldValue:
|
|
1566
|
-
|
|
1581
|
+
oldValue: normalizedPrevious,
|
|
1582
|
+
// Use normalized value for clarity
|
|
1583
|
+
newValue: normalizedCurrent
|
|
1584
|
+
// Use normalized value for clarity
|
|
1567
1585
|
});
|
|
1568
1586
|
}
|
|
1569
1587
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -1783,10 +1801,10 @@ function mergeConfig3(config) {
|
|
|
1783
1801
|
}
|
|
1784
1802
|
function resolveMigrationDir(config) {
|
|
1785
1803
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1786
|
-
if (
|
|
1804
|
+
if (path5__namespace.isAbsolute(config.migrationDir)) {
|
|
1787
1805
|
return config.migrationDir;
|
|
1788
1806
|
}
|
|
1789
|
-
return
|
|
1807
|
+
return path5__namespace.join(workspaceRoot, config.migrationDir);
|
|
1790
1808
|
}
|
|
1791
1809
|
function generateTimestamp(config) {
|
|
1792
1810
|
if (config?.timestampGenerator) {
|
|
@@ -1844,9 +1862,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
1844
1862
|
}
|
|
1845
1863
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
1846
1864
|
try {
|
|
1847
|
-
if (!
|
|
1865
|
+
if (!fs5__namespace.existsSync(migrationDir)) {
|
|
1848
1866
|
try {
|
|
1849
|
-
|
|
1867
|
+
fs5__namespace.mkdirSync(migrationDir, { recursive: true });
|
|
1850
1868
|
} catch (error) {
|
|
1851
1869
|
const fsError = error;
|
|
1852
1870
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -1867,15 +1885,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
1867
1885
|
);
|
|
1868
1886
|
}
|
|
1869
1887
|
}
|
|
1870
|
-
const filePath =
|
|
1871
|
-
|
|
1888
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
1889
|
+
fs5__namespace.writeFileSync(filePath, content, "utf-8");
|
|
1872
1890
|
return filePath;
|
|
1873
1891
|
} catch (error) {
|
|
1874
1892
|
if (error instanceof FileSystemError) {
|
|
1875
1893
|
throw error;
|
|
1876
1894
|
}
|
|
1877
1895
|
const fsError = error;
|
|
1878
|
-
const filePath =
|
|
1896
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
1879
1897
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
1880
1898
|
throw new FileSystemError(
|
|
1881
1899
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -2420,57 +2438,18 @@ function generate(diff, config) {
|
|
|
2420
2438
|
);
|
|
2421
2439
|
}
|
|
2422
2440
|
}
|
|
2441
|
+
|
|
2442
|
+
// src/migration/pocketbase-converter.ts
|
|
2423
2443
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2424
|
-
({
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
try {
|
|
2428
|
-
if (!fs4__namespace.existsSync(migrationsPath)) {
|
|
2429
|
-
return null;
|
|
2430
|
-
}
|
|
2431
|
-
const files = fs4__namespace.readdirSync(migrationsPath);
|
|
2432
|
-
const snapshotFiles = files.filter(
|
|
2433
|
-
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2434
|
-
);
|
|
2435
|
-
if (snapshotFiles.length === 0) {
|
|
2436
|
-
return null;
|
|
2437
|
-
}
|
|
2438
|
-
snapshotFiles.sort().reverse();
|
|
2439
|
-
const latestSnapshot = snapshotFiles[0];
|
|
2440
|
-
if (!latestSnapshot) {
|
|
2441
|
-
return null;
|
|
2442
|
-
}
|
|
2443
|
-
return path4__namespace.join(migrationsPath, latestSnapshot);
|
|
2444
|
-
} catch (error) {
|
|
2445
|
-
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2446
|
-
return null;
|
|
2444
|
+
function resolveCollectionIdToName(collectionId) {
|
|
2445
|
+
if (collectionId === "_pb_users_auth_") {
|
|
2446
|
+
return "Users";
|
|
2447
2447
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
if (!migrationsPath) {
|
|
2452
|
-
return null;
|
|
2448
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2449
|
+
if (nameMatch) {
|
|
2450
|
+
return nameMatch[1];
|
|
2453
2451
|
}
|
|
2454
|
-
|
|
2455
|
-
try {
|
|
2456
|
-
const migrationContent = fs4__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2457
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2458
|
-
} catch (error) {
|
|
2459
|
-
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2460
|
-
return null;
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2464
|
-
if (latestSnapshotPath) {
|
|
2465
|
-
try {
|
|
2466
|
-
const migrationContent = fs4__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2467
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2468
|
-
} catch (error) {
|
|
2469
|
-
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2470
|
-
return null;
|
|
2471
|
-
}
|
|
2472
|
-
}
|
|
2473
|
-
return null;
|
|
2452
|
+
return collectionId;
|
|
2474
2453
|
}
|
|
2475
2454
|
function convertPocketBaseCollection(pbCollection) {
|
|
2476
2455
|
const fields = [];
|
|
@@ -2489,17 +2468,28 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2489
2468
|
type: pbField.type,
|
|
2490
2469
|
required: pbField.required || false
|
|
2491
2470
|
};
|
|
2492
|
-
|
|
2493
|
-
|
|
2471
|
+
field.options = pbField.options ? { ...pbField.options } : {};
|
|
2472
|
+
if (pbField.type === "select") {
|
|
2473
|
+
if (pbField.values && Array.isArray(pbField.values)) {
|
|
2474
|
+
field.options.values = pbField.values;
|
|
2475
|
+
} else if (pbField.options?.values && Array.isArray(pbField.options.values)) {
|
|
2476
|
+
field.options.values = pbField.options.values;
|
|
2477
|
+
}
|
|
2494
2478
|
}
|
|
2495
2479
|
if (pbField.type === "relation") {
|
|
2480
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2481
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2496
2482
|
field.relation = {
|
|
2497
|
-
collection:
|
|
2498
|
-
cascadeDelete: pbField.options?.cascadeDelete
|
|
2499
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2500
|
-
minSelect: pbField.options?.minSelect
|
|
2483
|
+
collection: collectionName,
|
|
2484
|
+
cascadeDelete: pbField.cascadeDelete ?? pbField.options?.cascadeDelete ?? false,
|
|
2485
|
+
maxSelect: pbField.maxSelect ?? pbField.options?.maxSelect,
|
|
2486
|
+
minSelect: pbField.minSelect ?? pbField.options?.minSelect
|
|
2501
2487
|
};
|
|
2502
2488
|
}
|
|
2489
|
+
const hasOnlyValues = Object.keys(field.options).length === 1 && field.options.values !== void 0;
|
|
2490
|
+
if (Object.keys(field.options).length === 0) {
|
|
2491
|
+
delete field.options;
|
|
2492
|
+
} else if (pbField.type === "select" && hasOnlyValues) ;
|
|
2503
2493
|
fields.push(field);
|
|
2504
2494
|
}
|
|
2505
2495
|
}
|
|
@@ -2564,6 +2554,320 @@ function convertPocketBaseMigration(migrationContent) {
|
|
|
2564
2554
|
}
|
|
2565
2555
|
}
|
|
2566
2556
|
|
|
2557
|
+
// src/migration/migration-parser.ts
|
|
2558
|
+
function extractTimestampFromFilename(filename) {
|
|
2559
|
+
const match = filename.match(/^(\d+)_/);
|
|
2560
|
+
if (match) {
|
|
2561
|
+
return parseInt(match[1], 10);
|
|
2562
|
+
}
|
|
2563
|
+
return null;
|
|
2564
|
+
}
|
|
2565
|
+
function findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp) {
|
|
2566
|
+
try {
|
|
2567
|
+
if (!fs5__namespace.existsSync(migrationsPath)) {
|
|
2568
|
+
return [];
|
|
2569
|
+
}
|
|
2570
|
+
const files = fs5__namespace.readdirSync(migrationsPath);
|
|
2571
|
+
const migrationFiles = [];
|
|
2572
|
+
for (const file of files) {
|
|
2573
|
+
if (file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")) {
|
|
2574
|
+
continue;
|
|
2575
|
+
}
|
|
2576
|
+
if (!file.endsWith(".js")) {
|
|
2577
|
+
continue;
|
|
2578
|
+
}
|
|
2579
|
+
const timestamp = extractTimestampFromFilename(file);
|
|
2580
|
+
if (timestamp && timestamp > snapshotTimestamp) {
|
|
2581
|
+
migrationFiles.push({
|
|
2582
|
+
path: path5__namespace.join(migrationsPath, file),
|
|
2583
|
+
timestamp
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
migrationFiles.sort((a, b) => a.timestamp - b.timestamp);
|
|
2588
|
+
return migrationFiles.map((f) => f.path);
|
|
2589
|
+
} catch (error) {
|
|
2590
|
+
console.warn(`Error finding migrations after snapshot: ${error}`);
|
|
2591
|
+
return [];
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
function parseMigrationOperationsFromContent(content) {
|
|
2595
|
+
const collectionsToCreate = [];
|
|
2596
|
+
const collectionsToDelete = [];
|
|
2597
|
+
try {
|
|
2598
|
+
let searchIndex = 0;
|
|
2599
|
+
while (true) {
|
|
2600
|
+
const collectionStart = content.indexOf("new Collection(", searchIndex);
|
|
2601
|
+
if (collectionStart === -1) {
|
|
2602
|
+
break;
|
|
2603
|
+
}
|
|
2604
|
+
const openParen = collectionStart + "new Collection(".length;
|
|
2605
|
+
let braceCount = 0;
|
|
2606
|
+
let parenCount = 1;
|
|
2607
|
+
let inString = false;
|
|
2608
|
+
let stringChar = null;
|
|
2609
|
+
let i = openParen;
|
|
2610
|
+
while (i < content.length && /\s/.test(content[i])) {
|
|
2611
|
+
i++;
|
|
2612
|
+
}
|
|
2613
|
+
if (content[i] !== "{") {
|
|
2614
|
+
searchIndex = i + 1;
|
|
2615
|
+
continue;
|
|
2616
|
+
}
|
|
2617
|
+
const objectStart = i;
|
|
2618
|
+
braceCount = 1;
|
|
2619
|
+
i++;
|
|
2620
|
+
while (i < content.length && (braceCount > 0 || parenCount > 0)) {
|
|
2621
|
+
const char = content[i];
|
|
2622
|
+
const prevChar = i > 0 ? content[i - 1] : "";
|
|
2623
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2624
|
+
inString = true;
|
|
2625
|
+
stringChar = char;
|
|
2626
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2627
|
+
inString = false;
|
|
2628
|
+
stringChar = null;
|
|
2629
|
+
}
|
|
2630
|
+
if (!inString) {
|
|
2631
|
+
if (char === "{") braceCount++;
|
|
2632
|
+
if (char === "}") braceCount--;
|
|
2633
|
+
if (char === "(") parenCount++;
|
|
2634
|
+
if (char === ")") parenCount--;
|
|
2635
|
+
}
|
|
2636
|
+
i++;
|
|
2637
|
+
}
|
|
2638
|
+
if (braceCount === 0 && parenCount === 0) {
|
|
2639
|
+
const objectContent = content.substring(objectStart, i - 1);
|
|
2640
|
+
try {
|
|
2641
|
+
const collectionObj = new Function(`return ${objectContent}`)();
|
|
2642
|
+
if (collectionObj && collectionObj.name) {
|
|
2643
|
+
const schema = convertPocketBaseCollection(collectionObj);
|
|
2644
|
+
collectionsToCreate.push(schema);
|
|
2645
|
+
}
|
|
2646
|
+
} catch (error) {
|
|
2647
|
+
console.warn(`Failed to parse collection definition: ${error}`);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
searchIndex = i;
|
|
2651
|
+
}
|
|
2652
|
+
const deleteMatches = content.matchAll(
|
|
2653
|
+
/app\.delete\s*\(\s*(?:collection_\w+|app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\))\s*\)/g
|
|
2654
|
+
);
|
|
2655
|
+
for (const match of deleteMatches) {
|
|
2656
|
+
if (match[1]) {
|
|
2657
|
+
collectionsToDelete.push(match[1]);
|
|
2658
|
+
} else {
|
|
2659
|
+
const varNameMatch = match[0].match(/collection_(\w+)/);
|
|
2660
|
+
if (varNameMatch) {
|
|
2661
|
+
const varName = `collection_${varNameMatch[1]}`;
|
|
2662
|
+
const deleteIndex = content.indexOf(match[0]);
|
|
2663
|
+
const beforeDelete = content.substring(0, deleteIndex);
|
|
2664
|
+
const varDefMatch = beforeDelete.match(
|
|
2665
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`, "g")
|
|
2666
|
+
);
|
|
2667
|
+
if (varDefMatch && varDefMatch.length > 0) {
|
|
2668
|
+
const collectionDefMatch = beforeDelete.match(
|
|
2669
|
+
new RegExp(`const\\s+${varName}\\s*=\\s*new\\s+Collection\\(\\s*(\\{[\\s\\S]*?\\})\\s*\\)`)
|
|
2670
|
+
);
|
|
2671
|
+
if (collectionDefMatch) {
|
|
2672
|
+
try {
|
|
2673
|
+
const collectionDefStr = collectionDefMatch[1];
|
|
2674
|
+
const collectionObj = new Function(`return ${collectionDefStr}`)();
|
|
2675
|
+
if (collectionObj && collectionObj.name) {
|
|
2676
|
+
collectionsToDelete.push(collectionObj.name);
|
|
2677
|
+
}
|
|
2678
|
+
} catch {
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
const findAndDeleteMatches = content.matchAll(
|
|
2686
|
+
/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)[\s\S]*?app\.delete/g
|
|
2687
|
+
);
|
|
2688
|
+
for (const match of findAndDeleteMatches) {
|
|
2689
|
+
collectionsToDelete.push(match[1]);
|
|
2690
|
+
}
|
|
2691
|
+
} catch (error) {
|
|
2692
|
+
console.warn(`Failed to parse migration operations from content: ${error}`);
|
|
2693
|
+
}
|
|
2694
|
+
return { collectionsToCreate, collectionsToDelete };
|
|
2695
|
+
}
|
|
2696
|
+
function parseMigrationOperations(migrationContent) {
|
|
2697
|
+
try {
|
|
2698
|
+
const migrateMatch = migrationContent.match(/migrate\s*\(\s*/);
|
|
2699
|
+
if (!migrateMatch) {
|
|
2700
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2701
|
+
}
|
|
2702
|
+
const startIndex = migrateMatch.index + migrateMatch[0].length;
|
|
2703
|
+
let i = startIndex;
|
|
2704
|
+
let parenCount = 0;
|
|
2705
|
+
let foundFirstParen = false;
|
|
2706
|
+
while (i < migrationContent.length) {
|
|
2707
|
+
const char = migrationContent[i];
|
|
2708
|
+
if (char === "(") {
|
|
2709
|
+
parenCount++;
|
|
2710
|
+
foundFirstParen = true;
|
|
2711
|
+
i++;
|
|
2712
|
+
break;
|
|
2713
|
+
}
|
|
2714
|
+
i++;
|
|
2715
|
+
}
|
|
2716
|
+
if (!foundFirstParen) {
|
|
2717
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2718
|
+
}
|
|
2719
|
+
let inString = false;
|
|
2720
|
+
let stringChar = null;
|
|
2721
|
+
let foundBrace = false;
|
|
2722
|
+
let braceStart = -1;
|
|
2723
|
+
while (i < migrationContent.length && !foundBrace) {
|
|
2724
|
+
const char = migrationContent[i];
|
|
2725
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2726
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2727
|
+
inString = true;
|
|
2728
|
+
stringChar = char;
|
|
2729
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2730
|
+
inString = false;
|
|
2731
|
+
stringChar = null;
|
|
2732
|
+
}
|
|
2733
|
+
if (!inString) {
|
|
2734
|
+
if (char === "(") parenCount++;
|
|
2735
|
+
if (char === ")") {
|
|
2736
|
+
parenCount--;
|
|
2737
|
+
if (parenCount === 0) {
|
|
2738
|
+
i++;
|
|
2739
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2740
|
+
i++;
|
|
2741
|
+
}
|
|
2742
|
+
if (i < migrationContent.length - 1 && migrationContent[i] === "=" && migrationContent[i + 1] === ">") {
|
|
2743
|
+
i += 2;
|
|
2744
|
+
while (i < migrationContent.length && /\s/.test(migrationContent[i])) {
|
|
2745
|
+
i++;
|
|
2746
|
+
}
|
|
2747
|
+
if (i < migrationContent.length && migrationContent[i] === "{") {
|
|
2748
|
+
foundBrace = true;
|
|
2749
|
+
braceStart = i + 1;
|
|
2750
|
+
break;
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
i++;
|
|
2757
|
+
}
|
|
2758
|
+
if (!foundBrace || braceStart === -1) {
|
|
2759
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2760
|
+
}
|
|
2761
|
+
let braceCount = 1;
|
|
2762
|
+
i = braceStart;
|
|
2763
|
+
inString = false;
|
|
2764
|
+
stringChar = null;
|
|
2765
|
+
while (i < migrationContent.length && braceCount > 0) {
|
|
2766
|
+
const char = migrationContent[i];
|
|
2767
|
+
const prevChar = i > 0 ? migrationContent[i - 1] : "";
|
|
2768
|
+
if (!inString && (char === '"' || char === "'")) {
|
|
2769
|
+
inString = true;
|
|
2770
|
+
stringChar = char;
|
|
2771
|
+
} else if (inString && char === stringChar && prevChar !== "\\") {
|
|
2772
|
+
inString = false;
|
|
2773
|
+
stringChar = null;
|
|
2774
|
+
}
|
|
2775
|
+
if (!inString) {
|
|
2776
|
+
if (char === "{") braceCount++;
|
|
2777
|
+
if (char === "}") braceCount--;
|
|
2778
|
+
}
|
|
2779
|
+
i++;
|
|
2780
|
+
}
|
|
2781
|
+
if (braceCount === 0) {
|
|
2782
|
+
const upMigrationContent = migrationContent.substring(braceStart, i - 1);
|
|
2783
|
+
return parseMigrationOperationsFromContent(upMigrationContent);
|
|
2784
|
+
}
|
|
2785
|
+
return parseMigrationOperationsFromContent(migrationContent);
|
|
2786
|
+
} catch (error) {
|
|
2787
|
+
console.warn(`Failed to parse migration operations: ${error}`);
|
|
2788
|
+
return { collectionsToCreate: [], collectionsToDelete: [] };
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
({
|
|
2792
|
+
workspaceRoot: process.cwd()});
|
|
2793
|
+
function findLatestSnapshot(migrationsPath) {
|
|
2794
|
+
try {
|
|
2795
|
+
if (!fs5__namespace.existsSync(migrationsPath)) {
|
|
2796
|
+
return null;
|
|
2797
|
+
}
|
|
2798
|
+
const files = fs5__namespace.readdirSync(migrationsPath);
|
|
2799
|
+
const snapshotFiles = files.filter(
|
|
2800
|
+
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2801
|
+
);
|
|
2802
|
+
if (snapshotFiles.length === 0) {
|
|
2803
|
+
return null;
|
|
2804
|
+
}
|
|
2805
|
+
snapshotFiles.sort().reverse();
|
|
2806
|
+
const latestSnapshot = snapshotFiles[0];
|
|
2807
|
+
if (!latestSnapshot) {
|
|
2808
|
+
return null;
|
|
2809
|
+
}
|
|
2810
|
+
return path5__namespace.join(migrationsPath, latestSnapshot);
|
|
2811
|
+
} catch (error) {
|
|
2812
|
+
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2813
|
+
return null;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
function applyMigrationOperations(snapshot, operations) {
|
|
2817
|
+
const updatedCollections = new Map(snapshot.collections);
|
|
2818
|
+
for (const collectionName of operations.collectionsToDelete) {
|
|
2819
|
+
updatedCollections.delete(collectionName);
|
|
2820
|
+
}
|
|
2821
|
+
for (const collection of operations.collectionsToCreate) {
|
|
2822
|
+
updatedCollections.set(collection.name, collection);
|
|
2823
|
+
}
|
|
2824
|
+
return {
|
|
2825
|
+
...snapshot,
|
|
2826
|
+
collections: updatedCollections
|
|
2827
|
+
};
|
|
2828
|
+
}
|
|
2829
|
+
function loadSnapshotWithMigrations(config = {}) {
|
|
2830
|
+
const migrationsPath = config.migrationsPath;
|
|
2831
|
+
if (!migrationsPath) {
|
|
2832
|
+
return null;
|
|
2833
|
+
}
|
|
2834
|
+
if (fs5__namespace.existsSync(migrationsPath) && fs5__namespace.statSync(migrationsPath).isFile()) {
|
|
2835
|
+
try {
|
|
2836
|
+
const migrationContent = fs5__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2837
|
+
return convertPocketBaseMigration(migrationContent);
|
|
2838
|
+
} catch (error) {
|
|
2839
|
+
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2840
|
+
return null;
|
|
2841
|
+
}
|
|
2842
|
+
}
|
|
2843
|
+
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2844
|
+
if (!latestSnapshotPath) {
|
|
2845
|
+
return null;
|
|
2846
|
+
}
|
|
2847
|
+
try {
|
|
2848
|
+
const migrationContent = fs5__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2849
|
+
let snapshot = convertPocketBaseMigration(migrationContent);
|
|
2850
|
+
const snapshotFilename = path5__namespace.basename(latestSnapshotPath);
|
|
2851
|
+
const snapshotTimestamp = extractTimestampFromFilename(snapshotFilename);
|
|
2852
|
+
if (snapshotTimestamp) {
|
|
2853
|
+
const migrationFiles = findMigrationsAfterSnapshot(migrationsPath, snapshotTimestamp);
|
|
2854
|
+
for (const migrationFile of migrationFiles) {
|
|
2855
|
+
try {
|
|
2856
|
+
const migrationContent2 = fs5__namespace.readFileSync(migrationFile, "utf-8");
|
|
2857
|
+
const operations = parseMigrationOperations(migrationContent2);
|
|
2858
|
+
snapshot = applyMigrationOperations(snapshot, operations);
|
|
2859
|
+
} catch (error) {
|
|
2860
|
+
console.warn(`Failed to apply migration ${migrationFile}: ${error}`);
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
return snapshot;
|
|
2865
|
+
} catch (error) {
|
|
2866
|
+
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2567
2871
|
// src/migration/validation.ts
|
|
2568
2872
|
function detectCollectionDeletions(diff) {
|
|
2569
2873
|
const changes = [];
|
|
@@ -2732,8 +3036,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
2732
3036
|
};
|
|
2733
3037
|
function findConfigFile(directory) {
|
|
2734
3038
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
2735
|
-
const filePath =
|
|
2736
|
-
if (
|
|
3039
|
+
const filePath = path5__namespace.join(directory, fileName);
|
|
3040
|
+
if (fs5__namespace.existsSync(filePath)) {
|
|
2737
3041
|
return filePath;
|
|
2738
3042
|
}
|
|
2739
3043
|
}
|
|
@@ -2741,7 +3045,7 @@ function findConfigFile(directory) {
|
|
|
2741
3045
|
}
|
|
2742
3046
|
function loadJsonConfig(configPath) {
|
|
2743
3047
|
try {
|
|
2744
|
-
const content =
|
|
3048
|
+
const content = fs5__namespace.readFileSync(configPath, "utf-8");
|
|
2745
3049
|
return JSON.parse(content);
|
|
2746
3050
|
} catch (error) {
|
|
2747
3051
|
if (error instanceof SyntaxError) {
|
|
@@ -2770,10 +3074,10 @@ async function loadJsConfig(configPath) {
|
|
|
2770
3074
|
}
|
|
2771
3075
|
}
|
|
2772
3076
|
async function loadConfigFile(configPath) {
|
|
2773
|
-
if (!
|
|
3077
|
+
if (!fs5__namespace.existsSync(configPath)) {
|
|
2774
3078
|
return null;
|
|
2775
3079
|
}
|
|
2776
|
-
const ext =
|
|
3080
|
+
const ext = path5__namespace.extname(configPath).toLowerCase();
|
|
2777
3081
|
if (ext === ".json") {
|
|
2778
3082
|
return loadJsonConfig(configPath);
|
|
2779
3083
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -2840,10 +3144,10 @@ function validateConfig(config, configPath) {
|
|
|
2840
3144
|
}
|
|
2841
3145
|
const cwd = process.cwd();
|
|
2842
3146
|
const possiblePaths = [
|
|
2843
|
-
|
|
2844
|
-
|
|
3147
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
3148
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
2845
3149
|
];
|
|
2846
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
3150
|
+
const schemaDir = possiblePaths.find((p) => fs5__namespace.existsSync(p));
|
|
2847
3151
|
if (!schemaDir) {
|
|
2848
3152
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
2849
3153
|
"schema.directory"
|
|
@@ -2855,15 +3159,15 @@ async function loadConfig(options = {}) {
|
|
|
2855
3159
|
let configFilePath;
|
|
2856
3160
|
const cwd = process.cwd();
|
|
2857
3161
|
if (options.config) {
|
|
2858
|
-
const explicitPath =
|
|
2859
|
-
if (!
|
|
3162
|
+
const explicitPath = path5__namespace.resolve(cwd, options.config);
|
|
3163
|
+
if (!fs5__namespace.existsSync(explicitPath)) {
|
|
2860
3164
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
2861
3165
|
}
|
|
2862
3166
|
configFilePath = explicitPath;
|
|
2863
3167
|
} else {
|
|
2864
|
-
const searchDirs = [cwd,
|
|
3168
|
+
const searchDirs = [cwd, path5__namespace.join(cwd, "shared")];
|
|
2865
3169
|
for (const dir of searchDirs) {
|
|
2866
|
-
if (
|
|
3170
|
+
if (fs5__namespace.existsSync(dir)) {
|
|
2867
3171
|
const found = findConfigFile(dir);
|
|
2868
3172
|
if (found) {
|
|
2869
3173
|
configFilePath = found;
|
|
@@ -2892,18 +3196,18 @@ async function loadConfig(options = {}) {
|
|
|
2892
3196
|
function getSchemaDirectory(config) {
|
|
2893
3197
|
const cwd = process.cwd();
|
|
2894
3198
|
const possiblePaths = [
|
|
2895
|
-
|
|
2896
|
-
|
|
3199
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
3200
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
2897
3201
|
];
|
|
2898
|
-
return possiblePaths.find((p) =>
|
|
3202
|
+
return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
|
|
2899
3203
|
}
|
|
2900
3204
|
function getMigrationsDirectory(config) {
|
|
2901
3205
|
const cwd = process.cwd();
|
|
2902
3206
|
const possiblePaths = [
|
|
2903
|
-
|
|
2904
|
-
|
|
3207
|
+
path5__namespace.resolve(cwd, config.migrations.directory),
|
|
3208
|
+
path5__namespace.resolve(cwd, "shared", config.migrations.directory)
|
|
2905
3209
|
];
|
|
2906
|
-
return possiblePaths.find((p) =>
|
|
3210
|
+
return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
|
|
2907
3211
|
}
|
|
2908
3212
|
var currentVerbosity = "normal";
|
|
2909
3213
|
function setVerbosity(level) {
|
|
@@ -3180,7 +3484,7 @@ async function executeGenerate(options) {
|
|
|
3180
3484
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3181
3485
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
3182
3486
|
logInfo("Loading previous snapshot...");
|
|
3183
|
-
const previousSnapshot =
|
|
3487
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3184
3488
|
migrationsPath: migrationsDir,
|
|
3185
3489
|
workspaceRoot: process.cwd()
|
|
3186
3490
|
});
|
|
@@ -3207,7 +3511,7 @@ async function executeGenerate(options) {
|
|
|
3207
3511
|
"Creating migration file...",
|
|
3208
3512
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
3209
3513
|
);
|
|
3210
|
-
logSuccess(`Migration file created: ${
|
|
3514
|
+
logSuccess(`Migration file created: ${path5__namespace.basename(migrationPath)}`);
|
|
3211
3515
|
logSection("\u2705 Next Steps");
|
|
3212
3516
|
console.log();
|
|
3213
3517
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -3373,7 +3677,7 @@ async function executeStatus(options) {
|
|
|
3373
3677
|
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3374
3678
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
3375
3679
|
logInfo("Loading previous snapshot...");
|
|
3376
|
-
const previousSnapshot =
|
|
3680
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3377
3681
|
migrationsPath: migrationsDir,
|
|
3378
3682
|
workspaceRoot: process.cwd()
|
|
3379
3683
|
});
|