pocketbase-zod-schema 0.1.2 → 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 +15 -0
- package/README.md +329 -99
- package/dist/cli/index.cjs +577 -152
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +575 -150
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/migrate.cjs +595 -153
- package/dist/cli/migrate.cjs.map +1 -1
- package/dist/cli/migrate.js +592 -151
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/utils/index.cjs +1 -1
- package/dist/cli/utils/index.cjs.map +1 -1
- package/dist/cli/utils/index.js +1 -1
- package/dist/cli/utils/index.js.map +1 -1
- package/dist/index.cjs +688 -231
- 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 +685 -230
- package/dist/index.js.map +1 -1
- package/dist/migration/analyzer.cjs +101 -28
- package/dist/migration/analyzer.cjs.map +1 -1
- package/dist/migration/analyzer.js +101 -28
- package/dist/migration/analyzer.js.map +1 -1
- package/dist/migration/diff.cjs +21 -3
- package/dist/migration/diff.cjs.map +1 -1
- package/dist/migration/diff.js +21 -3
- package/dist/migration/diff.js.map +1 -1
- package/dist/migration/generator.cjs +60 -25
- package/dist/migration/generator.cjs.map +1 -1
- package/dist/migration/generator.d.cts +9 -5
- package/dist/migration/generator.d.ts +9 -5
- package/dist/migration/generator.js +60 -25
- package/dist/migration/generator.js.map +1 -1
- package/dist/migration/index.cjs +614 -171
- 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 +613 -171
- package/dist/migration/index.js.map +1 -1
- package/dist/migration/snapshot.cjs +432 -117
- 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 -116
- package/dist/migration/snapshot.js.map +1 -1
- package/dist/migration/utils/index.cjs +19 -17
- package/dist/migration/utils/index.cjs.map +1 -1
- package/dist/migration/utils/index.d.cts +3 -1
- package/dist/migration/utils/index.d.ts +3 -1
- package/dist/migration/utils/index.js +19 -17
- package/dist/migration/utils/index.js.map +1 -1
- package/dist/mutator.cjs +9 -11
- package/dist/mutator.cjs.map +1 -1
- package/dist/mutator.d.cts +5 -9
- package/dist/mutator.d.ts +5 -9
- package/dist/mutator.js +9 -11
- package/dist/mutator.js.map +1 -1
- package/dist/schema.cjs +54 -23
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +94 -12
- package/dist/schema.d.ts +94 -12
- package/dist/schema.js +54 -24
- package/dist/schema.js.map +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/{user-jS1aYoeD.d.cts → user-_AM523hb.d.cts} +6 -6
- package/dist/{user-jS1aYoeD.d.ts → user-_AM523hb.d.ts} +6 -6
- package/package.json +2 -4
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,12 +26,41 @@ 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
|
|
|
34
34
|
// src/cli/commands/generate.ts
|
|
35
|
+
({
|
|
36
|
+
id: zod.z.string().describe("unique id"),
|
|
37
|
+
collectionId: zod.z.string().describe("collection id"),
|
|
38
|
+
collectionName: zod.z.string().describe("collection name"),
|
|
39
|
+
expand: zod.z.record(zod.z.any()).describe("expandable fields")
|
|
40
|
+
});
|
|
41
|
+
({
|
|
42
|
+
created: zod.z.string().describe("creation timestamp"),
|
|
43
|
+
updated: zod.z.string().describe("last update timestamp")
|
|
44
|
+
});
|
|
45
|
+
({
|
|
46
|
+
thumbnailURL: zod.z.string().optional(),
|
|
47
|
+
imageFiles: zod.z.array(zod.z.string())
|
|
48
|
+
});
|
|
49
|
+
({
|
|
50
|
+
imageFiles: zod.z.array(zod.z.instanceof(File))
|
|
51
|
+
});
|
|
52
|
+
var RELATION_METADATA_KEY = "__pocketbase_relation__";
|
|
53
|
+
function extractRelationMetadata(description) {
|
|
54
|
+
if (!description) return null;
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(description);
|
|
57
|
+
if (parsed[RELATION_METADATA_KEY]) {
|
|
58
|
+
return parsed[RELATION_METADATA_KEY];
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
35
64
|
|
|
36
65
|
// src/migration/errors.ts
|
|
37
66
|
var MigrationError = class _MigrationError extends Error {
|
|
@@ -130,10 +159,10 @@ var FileSystemError = class _FileSystemError extends MigrationError {
|
|
|
130
159
|
operation;
|
|
131
160
|
code;
|
|
132
161
|
originalError;
|
|
133
|
-
constructor(message,
|
|
162
|
+
constructor(message, path7, operation, code, originalError) {
|
|
134
163
|
super(message);
|
|
135
164
|
this.name = "FileSystemError";
|
|
136
|
-
this.path =
|
|
165
|
+
this.path = path7;
|
|
137
166
|
this.operation = operation;
|
|
138
167
|
this.code = code;
|
|
139
168
|
this.originalError = originalError;
|
|
@@ -196,7 +225,7 @@ Cause: ${this.originalError.message}`);
|
|
|
196
225
|
}
|
|
197
226
|
};
|
|
198
227
|
|
|
199
|
-
// src/
|
|
228
|
+
// src/utils/permission-templates.ts
|
|
200
229
|
var PermissionTemplates = {
|
|
201
230
|
/**
|
|
202
231
|
* Public access - anyone can perform all operations
|
|
@@ -855,26 +884,28 @@ function getMaxSelect(fieldName, zodType) {
|
|
|
855
884
|
return 1;
|
|
856
885
|
}
|
|
857
886
|
function getMinSelect(fieldName, zodType) {
|
|
858
|
-
if (
|
|
859
|
-
return
|
|
860
|
-
}
|
|
861
|
-
let unwrappedType = zodType;
|
|
862
|
-
if (zodType instanceof zod.z.ZodOptional) {
|
|
863
|
-
unwrappedType = zodType._def.innerType;
|
|
864
|
-
}
|
|
865
|
-
if (unwrappedType instanceof zod.z.ZodNullable) {
|
|
866
|
-
unwrappedType = unwrappedType._def.innerType;
|
|
867
|
-
}
|
|
868
|
-
if (unwrappedType instanceof zod.z.ZodDefault) {
|
|
869
|
-
unwrappedType = unwrappedType._def.innerType;
|
|
887
|
+
if (isSingleRelationField(fieldName, zodType)) {
|
|
888
|
+
return 0;
|
|
870
889
|
}
|
|
871
|
-
if (
|
|
872
|
-
|
|
873
|
-
if (
|
|
874
|
-
|
|
890
|
+
if (isMultipleRelationField(fieldName, zodType)) {
|
|
891
|
+
let unwrappedType = zodType;
|
|
892
|
+
if (zodType instanceof zod.z.ZodOptional) {
|
|
893
|
+
unwrappedType = zodType._def.innerType;
|
|
894
|
+
}
|
|
895
|
+
if (unwrappedType instanceof zod.z.ZodNullable) {
|
|
896
|
+
unwrappedType = unwrappedType._def.innerType;
|
|
897
|
+
}
|
|
898
|
+
if (unwrappedType instanceof zod.z.ZodDefault) {
|
|
899
|
+
unwrappedType = unwrappedType._def.innerType;
|
|
900
|
+
}
|
|
901
|
+
if (unwrappedType instanceof zod.z.ZodArray) {
|
|
902
|
+
const arrayDef = unwrappedType._def;
|
|
903
|
+
if (arrayDef.minLength) {
|
|
904
|
+
return arrayDef.minLength.value;
|
|
905
|
+
}
|
|
875
906
|
}
|
|
876
907
|
}
|
|
877
|
-
return
|
|
908
|
+
return 0;
|
|
878
909
|
}
|
|
879
910
|
function mapZodStringType(zodType) {
|
|
880
911
|
const checks = zodType._def.checks || [];
|
|
@@ -1072,20 +1103,20 @@ function mergeConfig(config) {
|
|
|
1072
1103
|
}
|
|
1073
1104
|
function resolveSchemaDir(config) {
|
|
1074
1105
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1075
|
-
if (
|
|
1106
|
+
if (path5__namespace.isAbsolute(config.schemaDir)) {
|
|
1076
1107
|
return config.schemaDir;
|
|
1077
1108
|
}
|
|
1078
|
-
return
|
|
1109
|
+
return path5__namespace.join(workspaceRoot, config.schemaDir);
|
|
1079
1110
|
}
|
|
1080
1111
|
function discoverSchemaFiles(config) {
|
|
1081
1112
|
const normalizedConfig = typeof config === "string" ? { schemaDir: config } : config;
|
|
1082
1113
|
const mergedConfig = mergeConfig(normalizedConfig);
|
|
1083
1114
|
const schemaDir = resolveSchemaDir(normalizedConfig);
|
|
1084
1115
|
try {
|
|
1085
|
-
if (!
|
|
1116
|
+
if (!fs5__namespace.existsSync(schemaDir)) {
|
|
1086
1117
|
throw new FileSystemError(`Schema directory not found: ${schemaDir}`, schemaDir, "access", "ENOENT");
|
|
1087
1118
|
}
|
|
1088
|
-
const files =
|
|
1119
|
+
const files = fs5__namespace.readdirSync(schemaDir);
|
|
1089
1120
|
const schemaFiles = files.filter((file) => {
|
|
1090
1121
|
const hasValidExtension = mergedConfig.includeExtensions.some((ext) => file.endsWith(ext));
|
|
1091
1122
|
if (!hasValidExtension) return false;
|
|
@@ -1101,7 +1132,7 @@ function discoverSchemaFiles(config) {
|
|
|
1101
1132
|
});
|
|
1102
1133
|
return schemaFiles.map((file) => {
|
|
1103
1134
|
const ext = mergedConfig.includeExtensions.find((ext2) => file.endsWith(ext2)) || ".ts";
|
|
1104
|
-
return
|
|
1135
|
+
return path5__namespace.join(schemaDir, file.replace(new RegExp(`\\${ext}$`), ""));
|
|
1105
1136
|
});
|
|
1106
1137
|
} catch (error) {
|
|
1107
1138
|
if (error instanceof FileSystemError) {
|
|
@@ -1132,13 +1163,32 @@ async function importSchemaModule(filePath, config) {
|
|
|
1132
1163
|
if (config?.pathTransformer) {
|
|
1133
1164
|
importPath = config.pathTransformer(filePath);
|
|
1134
1165
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1166
|
+
let resolvedPath = null;
|
|
1167
|
+
const jsPath = `${importPath}.js`;
|
|
1168
|
+
const tsPath = `${importPath}.ts`;
|
|
1169
|
+
if (fs5__namespace.existsSync(jsPath)) {
|
|
1170
|
+
resolvedPath = jsPath;
|
|
1171
|
+
} else if (fs5__namespace.existsSync(tsPath)) {
|
|
1172
|
+
resolvedPath = tsPath;
|
|
1173
|
+
} else {
|
|
1174
|
+
resolvedPath = jsPath;
|
|
1137
1175
|
}
|
|
1138
|
-
const fileUrl = new URL(`file://${
|
|
1176
|
+
const fileUrl = new URL(`file://${path5__namespace.resolve(resolvedPath)}`);
|
|
1139
1177
|
const module = await import(fileUrl.href);
|
|
1140
1178
|
return module;
|
|
1141
1179
|
} catch (error) {
|
|
1180
|
+
const tsPath = `${filePath}.ts`;
|
|
1181
|
+
const isTypeScriptFile = fs5__namespace.existsSync(tsPath);
|
|
1182
|
+
if (isTypeScriptFile) {
|
|
1183
|
+
throw new SchemaParsingError(
|
|
1184
|
+
`Failed to import TypeScript schema file. Node.js cannot import TypeScript files directly.
|
|
1185
|
+
Please either:
|
|
1186
|
+
1. Compile your schema files to JavaScript first, or
|
|
1187
|
+
2. Use tsx to run the migration tool (e.g., "npx tsx package/dist/cli/migrate.js status" or "tsx package/dist/cli/migrate.js status")`,
|
|
1188
|
+
filePath,
|
|
1189
|
+
error
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1142
1192
|
throw new SchemaParsingError(
|
|
1143
1193
|
`Failed to import schema module. Make sure the schema files are compiled to JavaScript.`,
|
|
1144
1194
|
filePath,
|
|
@@ -1147,7 +1197,7 @@ async function importSchemaModule(filePath, config) {
|
|
|
1147
1197
|
}
|
|
1148
1198
|
}
|
|
1149
1199
|
function getCollectionNameFromFile(filePath) {
|
|
1150
|
-
const filename =
|
|
1200
|
+
const filename = path5__namespace.basename(filePath).replace(/\.(ts|js)$/, "");
|
|
1151
1201
|
return toCollectionName(filename);
|
|
1152
1202
|
}
|
|
1153
1203
|
function extractSchemaDefinitions(module, patterns = ["Schema", "InputSchema"]) {
|
|
@@ -1201,7 +1251,17 @@ function buildFieldDefinition(fieldName, zodType) {
|
|
|
1201
1251
|
required,
|
|
1202
1252
|
options
|
|
1203
1253
|
};
|
|
1204
|
-
|
|
1254
|
+
const relationMetadata = extractRelationMetadata(zodType.description);
|
|
1255
|
+
if (relationMetadata) {
|
|
1256
|
+
fieldDef.type = "relation";
|
|
1257
|
+
fieldDef.relation = {
|
|
1258
|
+
collection: relationMetadata.collection,
|
|
1259
|
+
maxSelect: relationMetadata.maxSelect,
|
|
1260
|
+
minSelect: relationMetadata.minSelect,
|
|
1261
|
+
cascadeDelete: relationMetadata.cascadeDelete
|
|
1262
|
+
};
|
|
1263
|
+
fieldDef.options = void 0;
|
|
1264
|
+
} else if (isRelationField(fieldName, zodType)) {
|
|
1205
1265
|
fieldDef.type = "relation";
|
|
1206
1266
|
const targetCollection = resolveTargetCollection(fieldName);
|
|
1207
1267
|
const maxSelect = getMaxSelect(fieldName, zodType);
|
|
@@ -1213,6 +1273,13 @@ function buildFieldDefinition(fieldName, zodType) {
|
|
|
1213
1273
|
cascadeDelete: false
|
|
1214
1274
|
// Default to false, can be configured later
|
|
1215
1275
|
};
|
|
1276
|
+
if (fieldDef.options) {
|
|
1277
|
+
const { min, max, pattern, ...relationSafeOptions } = fieldDef.options;
|
|
1278
|
+
console.log("min", min);
|
|
1279
|
+
console.log("max", max);
|
|
1280
|
+
console.log("pattern", pattern);
|
|
1281
|
+
fieldDef.options = Object.keys(relationSafeOptions).length > 0 ? relationSafeOptions : void 0;
|
|
1282
|
+
}
|
|
1216
1283
|
}
|
|
1217
1284
|
return fieldDef;
|
|
1218
1285
|
}
|
|
@@ -1265,11 +1332,12 @@ function convertZodSchemaToCollectionSchema(collectionName, zodSchema) {
|
|
|
1265
1332
|
fields,
|
|
1266
1333
|
indexes,
|
|
1267
1334
|
rules: {
|
|
1268
|
-
listRule: null,
|
|
1269
|
-
viewRule: null,
|
|
1270
|
-
createRule: null,
|
|
1271
|
-
updateRule: null,
|
|
1272
|
-
deleteRule: null
|
|
1335
|
+
listRule: permissions?.listRule ?? null,
|
|
1336
|
+
viewRule: permissions?.viewRule ?? null,
|
|
1337
|
+
createRule: permissions?.createRule ?? null,
|
|
1338
|
+
updateRule: permissions?.updateRule ?? null,
|
|
1339
|
+
deleteRule: permissions?.deleteRule ?? null,
|
|
1340
|
+
manageRule: permissions?.manageRule ?? null
|
|
1273
1341
|
},
|
|
1274
1342
|
permissions
|
|
1275
1343
|
};
|
|
@@ -1293,7 +1361,12 @@ async function buildSchemaDefinition(config) {
|
|
|
1293
1361
|
if (normalizedConfig.pathTransformer) {
|
|
1294
1362
|
importPath = normalizedConfig.pathTransformer(filePath);
|
|
1295
1363
|
} else if (mergedConfig.useCompiledFiles) {
|
|
1296
|
-
|
|
1364
|
+
const distPath = filePath.replace(/\/src\//, "/dist/");
|
|
1365
|
+
if (fs5__namespace.existsSync(`${distPath}.js`) || fs5__namespace.existsSync(`${distPath}.mjs`)) {
|
|
1366
|
+
importPath = distPath;
|
|
1367
|
+
} else {
|
|
1368
|
+
importPath = filePath;
|
|
1369
|
+
}
|
|
1297
1370
|
}
|
|
1298
1371
|
const module = await importSchemaModule(importPath, normalizedConfig);
|
|
1299
1372
|
const schemas = extractSchemaDefinitions(module, mergedConfig.schemaPatterns);
|
|
@@ -1466,6 +1539,9 @@ function compareFieldOptions(currentField, previousField) {
|
|
|
1466
1539
|
for (const key of allKeys) {
|
|
1467
1540
|
const currentValue = currentOptions[key];
|
|
1468
1541
|
const previousValue = previousOptions[key];
|
|
1542
|
+
if (currentValue === void 0 && previousValue === void 0) {
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1469
1545
|
if (!areValuesEqual(currentValue, previousValue)) {
|
|
1470
1546
|
changes.push({
|
|
1471
1547
|
property: `options.${key}`,
|
|
@@ -1486,11 +1562,26 @@ function compareRelationConfigurations(currentField, previousField) {
|
|
|
1486
1562
|
if (!currentRelation || !previousRelation) {
|
|
1487
1563
|
return changes;
|
|
1488
1564
|
}
|
|
1489
|
-
|
|
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) {
|
|
1490
1579
|
changes.push({
|
|
1491
1580
|
property: "relation.collection",
|
|
1492
|
-
oldValue:
|
|
1493
|
-
|
|
1581
|
+
oldValue: normalizedPrevious,
|
|
1582
|
+
// Use normalized value for clarity
|
|
1583
|
+
newValue: normalizedCurrent
|
|
1584
|
+
// Use normalized value for clarity
|
|
1494
1585
|
});
|
|
1495
1586
|
}
|
|
1496
1587
|
if (currentRelation.cascadeDelete !== previousRelation.cascadeDelete) {
|
|
@@ -1691,10 +1782,8 @@ function compare(currentSchema, previousSnapshot, config) {
|
|
|
1691
1782
|
var DEFAULT_TEMPLATE = `/// <reference path="{{TYPES_PATH}}" />
|
|
1692
1783
|
migrate((app) => {
|
|
1693
1784
|
{{UP_CODE}}
|
|
1694
|
-
return true;
|
|
1695
1785
|
}, (app) => {
|
|
1696
1786
|
{{DOWN_CODE}}
|
|
1697
|
-
return true;
|
|
1698
1787
|
});
|
|
1699
1788
|
`;
|
|
1700
1789
|
var DEFAULT_CONFIG3 = {
|
|
@@ -1712,10 +1801,10 @@ function mergeConfig3(config) {
|
|
|
1712
1801
|
}
|
|
1713
1802
|
function resolveMigrationDir(config) {
|
|
1714
1803
|
const workspaceRoot = config.workspaceRoot || process.cwd();
|
|
1715
|
-
if (
|
|
1804
|
+
if (path5__namespace.isAbsolute(config.migrationDir)) {
|
|
1716
1805
|
return config.migrationDir;
|
|
1717
1806
|
}
|
|
1718
|
-
return
|
|
1807
|
+
return path5__namespace.join(workspaceRoot, config.migrationDir);
|
|
1719
1808
|
}
|
|
1720
1809
|
function generateTimestamp(config) {
|
|
1721
1810
|
if (config?.timestampGenerator) {
|
|
@@ -1773,9 +1862,9 @@ function createMigrationFileStructure(upCode, downCode, config) {
|
|
|
1773
1862
|
}
|
|
1774
1863
|
function writeMigrationFile(migrationDir, filename, content) {
|
|
1775
1864
|
try {
|
|
1776
|
-
if (!
|
|
1865
|
+
if (!fs5__namespace.existsSync(migrationDir)) {
|
|
1777
1866
|
try {
|
|
1778
|
-
|
|
1867
|
+
fs5__namespace.mkdirSync(migrationDir, { recursive: true });
|
|
1779
1868
|
} catch (error) {
|
|
1780
1869
|
const fsError = error;
|
|
1781
1870
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
@@ -1796,15 +1885,15 @@ function writeMigrationFile(migrationDir, filename, content) {
|
|
|
1796
1885
|
);
|
|
1797
1886
|
}
|
|
1798
1887
|
}
|
|
1799
|
-
const filePath =
|
|
1800
|
-
|
|
1888
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
1889
|
+
fs5__namespace.writeFileSync(filePath, content, "utf-8");
|
|
1801
1890
|
return filePath;
|
|
1802
1891
|
} catch (error) {
|
|
1803
1892
|
if (error instanceof FileSystemError) {
|
|
1804
1893
|
throw error;
|
|
1805
1894
|
}
|
|
1806
1895
|
const fsError = error;
|
|
1807
|
-
const filePath =
|
|
1896
|
+
const filePath = path5__namespace.join(migrationDir, filename);
|
|
1808
1897
|
if (fsError.code === "EACCES" || fsError.code === "EPERM") {
|
|
1809
1898
|
throw new FileSystemError(
|
|
1810
1899
|
`Permission denied writing migration file. Check file and directory permissions.`,
|
|
@@ -1859,7 +1948,8 @@ function generateFieldDefinitionObject(field) {
|
|
|
1859
1948
|
}
|
|
1860
1949
|
}
|
|
1861
1950
|
if (field.relation) {
|
|
1862
|
-
const
|
|
1951
|
+
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
1952
|
+
const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
1863
1953
|
parts.push(` collectionId: ${collectionIdPlaceholder}`);
|
|
1864
1954
|
if (field.relation.maxSelect !== void 0) {
|
|
1865
1955
|
parts.push(` maxSelect: ${field.relation.maxSelect}`);
|
|
@@ -1943,7 +2033,7 @@ function generateIndexesArray(indexes) {
|
|
|
1943
2033
|
${indexStrings.join(",\n ")},
|
|
1944
2034
|
]`;
|
|
1945
2035
|
}
|
|
1946
|
-
function generateCollectionCreation(collection, varName = "collection") {
|
|
2036
|
+
function generateCollectionCreation(collection, varName = "collection", isLast = false) {
|
|
1947
2037
|
const lines = [];
|
|
1948
2038
|
lines.push(` const ${varName} = new Collection({`);
|
|
1949
2039
|
lines.push(` name: "${collection.name}",`);
|
|
@@ -1959,7 +2049,7 @@ function generateCollectionCreation(collection, varName = "collection") {
|
|
|
1959
2049
|
lines.push(` indexes: ${generateIndexesArray(collection.indexes)},`);
|
|
1960
2050
|
lines.push(` });`);
|
|
1961
2051
|
lines.push(``);
|
|
1962
|
-
lines.push(` app.save(${varName});`);
|
|
2052
|
+
lines.push(isLast ? ` return app.save(${varName});` : ` app.save(${varName});`);
|
|
1963
2053
|
return lines.join("\n");
|
|
1964
2054
|
}
|
|
1965
2055
|
function getFieldConstructorName(fieldType) {
|
|
@@ -1990,7 +2080,8 @@ function generateFieldConstructorOptions(field) {
|
|
|
1990
2080
|
}
|
|
1991
2081
|
}
|
|
1992
2082
|
if (field.relation && field.type === "relation") {
|
|
1993
|
-
const
|
|
2083
|
+
const isUsersCollection = field.relation.collection.toLowerCase() === "users";
|
|
2084
|
+
const collectionIdPlaceholder = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${field.relation.collection}").id`;
|
|
1994
2085
|
parts.push(` collectionId: ${collectionIdPlaceholder}`);
|
|
1995
2086
|
if (field.relation.maxSelect !== void 0) {
|
|
1996
2087
|
parts.push(` maxSelect: ${field.relation.maxSelect}`);
|
|
@@ -2004,7 +2095,7 @@ function generateFieldConstructorOptions(field) {
|
|
|
2004
2095
|
}
|
|
2005
2096
|
return parts.join(",\n");
|
|
2006
2097
|
}
|
|
2007
|
-
function generateFieldAddition(collectionName, field, varName) {
|
|
2098
|
+
function generateFieldAddition(collectionName, field, varName, isLast = false) {
|
|
2008
2099
|
const lines = [];
|
|
2009
2100
|
const constructorName = getFieldConstructorName(field.type);
|
|
2010
2101
|
const collectionVar = varName || `collection_${collectionName}_${field.name}`;
|
|
@@ -2014,10 +2105,10 @@ function generateFieldAddition(collectionName, field, varName) {
|
|
|
2014
2105
|
lines.push(generateFieldConstructorOptions(field));
|
|
2015
2106
|
lines.push(` }));`);
|
|
2016
2107
|
lines.push(``);
|
|
2017
|
-
lines.push(` app.save(${collectionVar});`);
|
|
2108
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2018
2109
|
return lines.join("\n");
|
|
2019
2110
|
}
|
|
2020
|
-
function generateFieldModification(collectionName, modification, varName) {
|
|
2111
|
+
function generateFieldModification(collectionName, modification, varName, isLast = false) {
|
|
2021
2112
|
const lines = [];
|
|
2022
2113
|
const collectionVar = varName || `collection_${collectionName}_${modification.fieldName}`;
|
|
2023
2114
|
const fieldVar = `${collectionVar}_field`;
|
|
@@ -2031,7 +2122,8 @@ function generateFieldModification(collectionName, modification, varName) {
|
|
|
2031
2122
|
} else if (change.property.startsWith("relation.")) {
|
|
2032
2123
|
const relationKey = change.property.replace("relation.", "");
|
|
2033
2124
|
if (relationKey === "collection") {
|
|
2034
|
-
const
|
|
2125
|
+
const isUsersCollection = String(change.newValue).toLowerCase() === "users";
|
|
2126
|
+
const collectionIdValue = isUsersCollection ? '"_pb_users_auth_"' : `app.findCollectionByNameOrId("${change.newValue}").id`;
|
|
2035
2127
|
lines.push(` ${fieldVar}.collectionId = ${collectionIdValue};`);
|
|
2036
2128
|
} else {
|
|
2037
2129
|
lines.push(` ${fieldVar}.${relationKey} = ${formatValue(change.newValue)};`);
|
|
@@ -2041,10 +2133,10 @@ function generateFieldModification(collectionName, modification, varName) {
|
|
|
2041
2133
|
}
|
|
2042
2134
|
}
|
|
2043
2135
|
lines.push(``);
|
|
2044
|
-
lines.push(` app.save(${collectionVar});`);
|
|
2136
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2045
2137
|
return lines.join("\n");
|
|
2046
2138
|
}
|
|
2047
|
-
function generateFieldDeletion(collectionName, fieldName, varName) {
|
|
2139
|
+
function generateFieldDeletion(collectionName, fieldName, varName, isLast = false) {
|
|
2048
2140
|
const lines = [];
|
|
2049
2141
|
const collectionVar = varName || `collection_${collectionName}_${fieldName}`;
|
|
2050
2142
|
const fieldVar = `${collectionVar}_field`;
|
|
@@ -2053,18 +2145,18 @@ function generateFieldDeletion(collectionName, fieldName, varName) {
|
|
|
2053
2145
|
lines.push(``);
|
|
2054
2146
|
lines.push(` ${collectionVar}.fields.remove(${fieldVar}.id);`);
|
|
2055
2147
|
lines.push(``);
|
|
2056
|
-
lines.push(` app.save(${collectionVar});`);
|
|
2148
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2057
2149
|
return lines.join("\n");
|
|
2058
2150
|
}
|
|
2059
|
-
function generateIndexAddition(collectionName, index, varName) {
|
|
2151
|
+
function generateIndexAddition(collectionName, index, varName, isLast = false) {
|
|
2060
2152
|
const lines = [];
|
|
2061
2153
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
2062
2154
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
2063
2155
|
lines.push(` ${collectionVar}.indexes.push("${index}");`);
|
|
2064
|
-
lines.push(` app.save(${collectionVar});`);
|
|
2156
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2065
2157
|
return lines.join("\n");
|
|
2066
2158
|
}
|
|
2067
|
-
function generateIndexRemoval(collectionName, index, varName) {
|
|
2159
|
+
function generateIndexRemoval(collectionName, index, varName, isLast = false) {
|
|
2068
2160
|
const lines = [];
|
|
2069
2161
|
const collectionVar = varName || `collection_${collectionName}_idx`;
|
|
2070
2162
|
const indexVar = `${collectionVar}_indexToRemove`;
|
|
@@ -2073,29 +2165,29 @@ function generateIndexRemoval(collectionName, index, varName) {
|
|
|
2073
2165
|
lines.push(` if (${indexVar} !== -1) {`);
|
|
2074
2166
|
lines.push(` ${collectionVar}.indexes.splice(${indexVar}, 1);`);
|
|
2075
2167
|
lines.push(` }`);
|
|
2076
|
-
lines.push(` app.save(${collectionVar});`);
|
|
2168
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2077
2169
|
return lines.join("\n");
|
|
2078
2170
|
}
|
|
2079
|
-
function generateRuleUpdate(collectionName, ruleType, newValue, varName) {
|
|
2171
|
+
function generateRuleUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
|
|
2080
2172
|
const lines = [];
|
|
2081
2173
|
const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
|
|
2082
2174
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
2083
2175
|
lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
|
|
2084
|
-
lines.push(` app.save(${collectionVar});`);
|
|
2176
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2085
2177
|
return lines.join("\n");
|
|
2086
2178
|
}
|
|
2087
|
-
function generatePermissionUpdate(collectionName, ruleType, newValue, varName) {
|
|
2179
|
+
function generatePermissionUpdate(collectionName, ruleType, newValue, varName, isLast = false) {
|
|
2088
2180
|
const lines = [];
|
|
2089
2181
|
const collectionVar = varName || `collection_${collectionName}_${ruleType}`;
|
|
2090
2182
|
lines.push(` const ${collectionVar} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
2091
2183
|
lines.push(` ${collectionVar}.${ruleType} = ${formatValue(newValue)};`);
|
|
2092
|
-
lines.push(` app.save(${collectionVar});`);
|
|
2184
|
+
lines.push(isLast ? ` return app.save(${collectionVar});` : ` app.save(${collectionVar});`);
|
|
2093
2185
|
return lines.join("\n");
|
|
2094
2186
|
}
|
|
2095
|
-
function generateCollectionDeletion(collectionName, varName = "collection") {
|
|
2187
|
+
function generateCollectionDeletion(collectionName, varName = "collection", isLast = false) {
|
|
2096
2188
|
const lines = [];
|
|
2097
2189
|
lines.push(` const ${varName} = app.findCollectionByNameOrId("${collectionName}");`);
|
|
2098
|
-
lines.push(` app.delete(${varName});`);
|
|
2190
|
+
lines.push(isLast ? ` return app.delete(${varName});` : ` app.delete(${varName});`);
|
|
2099
2191
|
return lines.join("\n");
|
|
2100
2192
|
}
|
|
2101
2193
|
function generateUpMigration(diff) {
|
|
@@ -2187,7 +2279,24 @@ function generateUpMigration(diff) {
|
|
|
2187
2279
|
lines.push(` // No changes detected`);
|
|
2188
2280
|
lines.push(``);
|
|
2189
2281
|
}
|
|
2190
|
-
|
|
2282
|
+
let code = lines.join("\n");
|
|
2283
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
2284
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
2285
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
2286
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
2287
|
+
const allMatches = [
|
|
2288
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
2289
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
2290
|
+
].sort((a, b) => b.index - a.index);
|
|
2291
|
+
if (allMatches.length > 0) {
|
|
2292
|
+
const lastMatch = allMatches[0];
|
|
2293
|
+
if (lastMatch.type === "save") {
|
|
2294
|
+
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);
|
|
2295
|
+
} else {
|
|
2296
|
+
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);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
return code;
|
|
2191
2300
|
}
|
|
2192
2301
|
function generateDownMigration(diff) {
|
|
2193
2302
|
const lines = [];
|
|
@@ -2289,7 +2398,24 @@ function generateDownMigration(diff) {
|
|
|
2289
2398
|
lines.push(` // No changes to revert`);
|
|
2290
2399
|
lines.push(``);
|
|
2291
2400
|
}
|
|
2292
|
-
|
|
2401
|
+
let code = lines.join("\n");
|
|
2402
|
+
const savePattern = /^(\s*)app\.save\((\w+)\);$/gm;
|
|
2403
|
+
const deletePattern = /^(\s*)app\.delete\((\w+)\);$/gm;
|
|
2404
|
+
const saveMatches = [...code.matchAll(savePattern)];
|
|
2405
|
+
const deleteMatches = [...code.matchAll(deletePattern)];
|
|
2406
|
+
const allMatches = [
|
|
2407
|
+
...saveMatches.map((m) => ({ match: m, type: "save", index: m.index })),
|
|
2408
|
+
...deleteMatches.map((m) => ({ match: m, type: "delete", index: m.index }))
|
|
2409
|
+
].sort((a, b) => b.index - a.index);
|
|
2410
|
+
if (allMatches.length > 0) {
|
|
2411
|
+
const lastMatch = allMatches[0];
|
|
2412
|
+
if (lastMatch.type === "save") {
|
|
2413
|
+
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);
|
|
2414
|
+
} else {
|
|
2415
|
+
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);
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
return code;
|
|
2293
2419
|
}
|
|
2294
2420
|
function generate(diff, config) {
|
|
2295
2421
|
const normalizedConfig = typeof config === "string" ? { migrationDir: config } : config;
|
|
@@ -2312,57 +2438,18 @@ function generate(diff, config) {
|
|
|
2312
2438
|
);
|
|
2313
2439
|
}
|
|
2314
2440
|
}
|
|
2441
|
+
|
|
2442
|
+
// src/migration/pocketbase-converter.ts
|
|
2315
2443
|
var SNAPSHOT_VERSION = "1.0.0";
|
|
2316
|
-
({
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
try {
|
|
2320
|
-
if (!fs4__namespace.existsSync(migrationsPath)) {
|
|
2321
|
-
return null;
|
|
2322
|
-
}
|
|
2323
|
-
const files = fs4__namespace.readdirSync(migrationsPath);
|
|
2324
|
-
const snapshotFiles = files.filter(
|
|
2325
|
-
(file) => file.endsWith("_collections_snapshot.js") || file.endsWith("_snapshot.js")
|
|
2326
|
-
);
|
|
2327
|
-
if (snapshotFiles.length === 0) {
|
|
2328
|
-
return null;
|
|
2329
|
-
}
|
|
2330
|
-
snapshotFiles.sort().reverse();
|
|
2331
|
-
const latestSnapshot = snapshotFiles[0];
|
|
2332
|
-
if (!latestSnapshot) {
|
|
2333
|
-
return null;
|
|
2334
|
-
}
|
|
2335
|
-
return path4__namespace.join(migrationsPath, latestSnapshot);
|
|
2336
|
-
} catch (error) {
|
|
2337
|
-
console.warn(`Error finding latest snapshot: ${error}`);
|
|
2338
|
-
return null;
|
|
2444
|
+
function resolveCollectionIdToName(collectionId) {
|
|
2445
|
+
if (collectionId === "_pb_users_auth_") {
|
|
2446
|
+
return "Users";
|
|
2339
2447
|
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
if (!migrationsPath) {
|
|
2344
|
-
return null;
|
|
2448
|
+
const nameMatch = collectionId.match(/app\.findCollectionByNameOrId\s*\(\s*["']([^"']+)["']\s*\)/);
|
|
2449
|
+
if (nameMatch) {
|
|
2450
|
+
return nameMatch[1];
|
|
2345
2451
|
}
|
|
2346
|
-
|
|
2347
|
-
try {
|
|
2348
|
-
const migrationContent = fs4__namespace.readFileSync(migrationsPath, "utf-8");
|
|
2349
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2350
|
-
} catch (error) {
|
|
2351
|
-
console.warn(`Failed to load snapshot from ${migrationsPath}: ${error}`);
|
|
2352
|
-
return null;
|
|
2353
|
-
}
|
|
2354
|
-
}
|
|
2355
|
-
const latestSnapshotPath = findLatestSnapshot(migrationsPath);
|
|
2356
|
-
if (latestSnapshotPath) {
|
|
2357
|
-
try {
|
|
2358
|
-
const migrationContent = fs4__namespace.readFileSync(latestSnapshotPath, "utf-8");
|
|
2359
|
-
return convertPocketBaseMigration(migrationContent);
|
|
2360
|
-
} catch (error) {
|
|
2361
|
-
console.warn(`Failed to load snapshot from ${latestSnapshotPath}: ${error}`);
|
|
2362
|
-
return null;
|
|
2363
|
-
}
|
|
2364
|
-
}
|
|
2365
|
-
return null;
|
|
2452
|
+
return collectionId;
|
|
2366
2453
|
}
|
|
2367
2454
|
function convertPocketBaseCollection(pbCollection) {
|
|
2368
2455
|
const fields = [];
|
|
@@ -2381,17 +2468,28 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2381
2468
|
type: pbField.type,
|
|
2382
2469
|
required: pbField.required || false
|
|
2383
2470
|
};
|
|
2384
|
-
|
|
2385
|
-
|
|
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
|
+
}
|
|
2386
2478
|
}
|
|
2387
2479
|
if (pbField.type === "relation") {
|
|
2480
|
+
const collectionId = pbField.collectionId || pbField.options?.collectionId || "";
|
|
2481
|
+
const collectionName = resolveCollectionIdToName(collectionId);
|
|
2388
2482
|
field.relation = {
|
|
2389
|
-
collection:
|
|
2390
|
-
cascadeDelete: pbField.options?.cascadeDelete
|
|
2391
|
-
maxSelect: pbField.options?.maxSelect,
|
|
2392
|
-
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
|
|
2393
2487
|
};
|
|
2394
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) ;
|
|
2395
2493
|
fields.push(field);
|
|
2396
2494
|
}
|
|
2397
2495
|
}
|
|
@@ -2412,6 +2510,7 @@ function convertPocketBaseCollection(pbCollection) {
|
|
|
2412
2510
|
if (pbCollection.manageRule !== void 0) rules.manageRule = pbCollection.manageRule;
|
|
2413
2511
|
if (Object.keys(rules).length > 0) {
|
|
2414
2512
|
schema.rules = rules;
|
|
2513
|
+
schema.permissions = { ...rules };
|
|
2415
2514
|
}
|
|
2416
2515
|
return schema;
|
|
2417
2516
|
}
|
|
@@ -2455,6 +2554,320 @@ function convertPocketBaseMigration(migrationContent) {
|
|
|
2455
2554
|
}
|
|
2456
2555
|
}
|
|
2457
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
|
+
|
|
2458
2871
|
// src/migration/validation.ts
|
|
2459
2872
|
function detectCollectionDeletions(diff) {
|
|
2460
2873
|
const changes = [];
|
|
@@ -2623,8 +3036,8 @@ var DEFAULT_CONFIG5 = {
|
|
|
2623
3036
|
};
|
|
2624
3037
|
function findConfigFile(directory) {
|
|
2625
3038
|
for (const fileName of CONFIG_FILE_NAMES) {
|
|
2626
|
-
const filePath =
|
|
2627
|
-
if (
|
|
3039
|
+
const filePath = path5__namespace.join(directory, fileName);
|
|
3040
|
+
if (fs5__namespace.existsSync(filePath)) {
|
|
2628
3041
|
return filePath;
|
|
2629
3042
|
}
|
|
2630
3043
|
}
|
|
@@ -2632,7 +3045,7 @@ function findConfigFile(directory) {
|
|
|
2632
3045
|
}
|
|
2633
3046
|
function loadJsonConfig(configPath) {
|
|
2634
3047
|
try {
|
|
2635
|
-
const content =
|
|
3048
|
+
const content = fs5__namespace.readFileSync(configPath, "utf-8");
|
|
2636
3049
|
return JSON.parse(content);
|
|
2637
3050
|
} catch (error) {
|
|
2638
3051
|
if (error instanceof SyntaxError) {
|
|
@@ -2661,10 +3074,10 @@ async function loadJsConfig(configPath) {
|
|
|
2661
3074
|
}
|
|
2662
3075
|
}
|
|
2663
3076
|
async function loadConfigFile(configPath) {
|
|
2664
|
-
if (!
|
|
3077
|
+
if (!fs5__namespace.existsSync(configPath)) {
|
|
2665
3078
|
return null;
|
|
2666
3079
|
}
|
|
2667
|
-
const ext =
|
|
3080
|
+
const ext = path5__namespace.extname(configPath).toLowerCase();
|
|
2668
3081
|
if (ext === ".json") {
|
|
2669
3082
|
return loadJsonConfig(configPath);
|
|
2670
3083
|
} else if (ext === ".js" || ext === ".mjs") {
|
|
@@ -2731,10 +3144,10 @@ function validateConfig(config, configPath) {
|
|
|
2731
3144
|
}
|
|
2732
3145
|
const cwd = process.cwd();
|
|
2733
3146
|
const possiblePaths = [
|
|
2734
|
-
|
|
2735
|
-
|
|
3147
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
3148
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
2736
3149
|
];
|
|
2737
|
-
const schemaDir = possiblePaths.find((p) =>
|
|
3150
|
+
const schemaDir = possiblePaths.find((p) => fs5__namespace.existsSync(p));
|
|
2738
3151
|
if (!schemaDir) {
|
|
2739
3152
|
throw new ConfigurationError(`Schema directory not found. Tried: ${possiblePaths.join(", ")}`, configPath, [
|
|
2740
3153
|
"schema.directory"
|
|
@@ -2746,15 +3159,15 @@ async function loadConfig(options = {}) {
|
|
|
2746
3159
|
let configFilePath;
|
|
2747
3160
|
const cwd = process.cwd();
|
|
2748
3161
|
if (options.config) {
|
|
2749
|
-
const explicitPath =
|
|
2750
|
-
if (!
|
|
3162
|
+
const explicitPath = path5__namespace.resolve(cwd, options.config);
|
|
3163
|
+
if (!fs5__namespace.existsSync(explicitPath)) {
|
|
2751
3164
|
throw new ConfigurationError(`Configuration file not found: ${explicitPath}`, explicitPath);
|
|
2752
3165
|
}
|
|
2753
3166
|
configFilePath = explicitPath;
|
|
2754
3167
|
} else {
|
|
2755
|
-
const searchDirs = [cwd,
|
|
3168
|
+
const searchDirs = [cwd, path5__namespace.join(cwd, "shared")];
|
|
2756
3169
|
for (const dir of searchDirs) {
|
|
2757
|
-
if (
|
|
3170
|
+
if (fs5__namespace.existsSync(dir)) {
|
|
2758
3171
|
const found = findConfigFile(dir);
|
|
2759
3172
|
if (found) {
|
|
2760
3173
|
configFilePath = found;
|
|
@@ -2783,18 +3196,18 @@ async function loadConfig(options = {}) {
|
|
|
2783
3196
|
function getSchemaDirectory(config) {
|
|
2784
3197
|
const cwd = process.cwd();
|
|
2785
3198
|
const possiblePaths = [
|
|
2786
|
-
|
|
2787
|
-
|
|
3199
|
+
path5__namespace.resolve(cwd, config.schema.directory),
|
|
3200
|
+
path5__namespace.resolve(cwd, "shared", config.schema.directory)
|
|
2788
3201
|
];
|
|
2789
|
-
return possiblePaths.find((p) =>
|
|
3202
|
+
return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
|
|
2790
3203
|
}
|
|
2791
3204
|
function getMigrationsDirectory(config) {
|
|
2792
3205
|
const cwd = process.cwd();
|
|
2793
3206
|
const possiblePaths = [
|
|
2794
|
-
|
|
2795
|
-
|
|
3207
|
+
path5__namespace.resolve(cwd, config.migrations.directory),
|
|
3208
|
+
path5__namespace.resolve(cwd, "shared", config.migrations.directory)
|
|
2796
3209
|
];
|
|
2797
|
-
return possiblePaths.find((p) =>
|
|
3210
|
+
return possiblePaths.find((p) => fs5__namespace.existsSync(p)) || possiblePaths[0];
|
|
2798
3211
|
}
|
|
2799
3212
|
var currentVerbosity = "normal";
|
|
2800
3213
|
function setVerbosity(level) {
|
|
@@ -3062,10 +3475,16 @@ async function executeGenerate(options) {
|
|
|
3062
3475
|
const schemaDir = getSchemaDirectory(config);
|
|
3063
3476
|
const migrationsDir = getMigrationsDirectory(config);
|
|
3064
3477
|
logSection("\u{1F50D} Analyzing Schema");
|
|
3065
|
-
const
|
|
3478
|
+
const analyzerConfig = {
|
|
3479
|
+
schemaDir,
|
|
3480
|
+
excludePatterns: config.schema.exclude,
|
|
3481
|
+
useCompiledFiles: false
|
|
3482
|
+
// Use source files since we're in development/testing
|
|
3483
|
+
};
|
|
3484
|
+
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3066
3485
|
logSuccess(`Found ${currentSchema.collections.size} collection(s)`);
|
|
3067
3486
|
logInfo("Loading previous snapshot...");
|
|
3068
|
-
const previousSnapshot =
|
|
3487
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3069
3488
|
migrationsPath: migrationsDir,
|
|
3070
3489
|
workspaceRoot: process.cwd()
|
|
3071
3490
|
});
|
|
@@ -3092,7 +3511,7 @@ async function executeGenerate(options) {
|
|
|
3092
3511
|
"Creating migration file...",
|
|
3093
3512
|
() => Promise.resolve(generate(diff, migrationsDir))
|
|
3094
3513
|
);
|
|
3095
|
-
logSuccess(`Migration file created: ${
|
|
3514
|
+
logSuccess(`Migration file created: ${path5__namespace.basename(migrationPath)}`);
|
|
3096
3515
|
logSection("\u2705 Next Steps");
|
|
3097
3516
|
console.log();
|
|
3098
3517
|
console.log(" 1. Review the generated migration file:");
|
|
@@ -3249,10 +3668,16 @@ async function executeStatus(options) {
|
|
|
3249
3668
|
const schemaDir = getSchemaDirectory(config);
|
|
3250
3669
|
const migrationsDir = getMigrationsDirectory(config);
|
|
3251
3670
|
logSection("\u{1F50D} Checking Migration Status");
|
|
3252
|
-
const
|
|
3671
|
+
const analyzerConfig = {
|
|
3672
|
+
schemaDir,
|
|
3673
|
+
excludePatterns: config.schema.exclude,
|
|
3674
|
+
useCompiledFiles: false
|
|
3675
|
+
// Use source files since we're in development/testing
|
|
3676
|
+
};
|
|
3677
|
+
const currentSchema = await withProgress("Parsing Zod schemas...", () => parseSchemaFiles(analyzerConfig));
|
|
3253
3678
|
logSuccess(`Found ${currentSchema.collections.size} collection(s) in schema`);
|
|
3254
3679
|
logInfo("Loading previous snapshot...");
|
|
3255
|
-
const previousSnapshot =
|
|
3680
|
+
const previousSnapshot = loadSnapshotWithMigrations({
|
|
3256
3681
|
migrationsPath: migrationsDir,
|
|
3257
3682
|
workspaceRoot: process.cwd()
|
|
3258
3683
|
});
|