@elek-io/core 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.browser.js +3 -4
- package/dist/browser/index.browser.js.map +1 -1
- package/dist/node/index.node.js +990 -950
- package/dist/node/index.node.js.map +1 -1
- package/package.json +11 -10
- package/dist/browser/index.browser.cjs +0 -1082
- package/dist/browser/index.browser.cjs.map +0 -1
- package/dist/browser/index.browser.d.cts +0 -12551
- package/dist/node/index.node.cjs +0 -3409
- package/dist/node/index.node.cjs.map +0 -1
- package/dist/node/index.node.d.cts +0 -13384
package/dist/node/index.node.js
CHANGED
|
@@ -444,7 +444,7 @@ var resolvedValueSchema = z4.union([
|
|
|
444
444
|
function getValueContentSchemaFromDefinition(definition) {
|
|
445
445
|
switch (definition.valueType) {
|
|
446
446
|
case ValueTypeSchema.Enum.boolean:
|
|
447
|
-
return getBooleanValueContentSchema(
|
|
447
|
+
return getBooleanValueContentSchema();
|
|
448
448
|
case ValueTypeSchema.Enum.number:
|
|
449
449
|
return getNumberValueContentSchema(definition);
|
|
450
450
|
case ValueTypeSchema.Enum.string:
|
|
@@ -458,7 +458,7 @@ function getValueContentSchemaFromDefinition(definition) {
|
|
|
458
458
|
);
|
|
459
459
|
}
|
|
460
460
|
}
|
|
461
|
-
function getBooleanValueContentSchema(
|
|
461
|
+
function getBooleanValueContentSchema() {
|
|
462
462
|
return z4.boolean();
|
|
463
463
|
}
|
|
464
464
|
function getNumberValueContentSchema(definition) {
|
|
@@ -1082,6 +1082,12 @@ async function files(path, extension) {
|
|
|
1082
1082
|
|
|
1083
1083
|
// src/service/AbstractCrudService.ts
|
|
1084
1084
|
var AbstractCrudService = class {
|
|
1085
|
+
type;
|
|
1086
|
+
options;
|
|
1087
|
+
/**
|
|
1088
|
+
* Dynamically generated git messages for operations
|
|
1089
|
+
*/
|
|
1090
|
+
gitMessage;
|
|
1085
1091
|
/**
|
|
1086
1092
|
* Do not instantiate directly as this is an abstract class
|
|
1087
1093
|
*/
|
|
@@ -1161,7 +1167,7 @@ var AbstractCrudService = class {
|
|
|
1161
1167
|
possibleFiles.map(async (possibleFile) => {
|
|
1162
1168
|
const fileNameArray = possibleFile.name.split(".");
|
|
1163
1169
|
const fileReference = {
|
|
1164
|
-
id: fileNameArray[0],
|
|
1170
|
+
id: fileNameArray[0] || "",
|
|
1165
1171
|
language: fileNameArray.length === 3 ? fileNameArray[1] : void 0,
|
|
1166
1172
|
extension: fileNameArray.length === 2 ? fileNameArray[1] : fileNameArray[2]
|
|
1167
1173
|
};
|
|
@@ -1177,8 +1183,9 @@ var AbstractCrudService = class {
|
|
|
1177
1183
|
};
|
|
1178
1184
|
|
|
1179
1185
|
// src/service/AssetService.ts
|
|
1180
|
-
import
|
|
1181
|
-
import
|
|
1186
|
+
import { fileTypeFromFile } from "file-type";
|
|
1187
|
+
import Fs2 from "fs-extra";
|
|
1188
|
+
import isSvg from "is-svg";
|
|
1182
1189
|
|
|
1183
1190
|
// src/util/shared.ts
|
|
1184
1191
|
import slugify from "slugify";
|
|
@@ -1194,8 +1201,7 @@ function slug(string) {
|
|
|
1194
1201
|
return Slugify(string, {
|
|
1195
1202
|
replacement: "-",
|
|
1196
1203
|
// replace spaces with replacement character, defaults to `-`
|
|
1197
|
-
remove:
|
|
1198
|
-
// remove characters that match regex, defaults to `undefined`
|
|
1204
|
+
// remove: undefined, // remove characters that match regex, defaults to `undefined`
|
|
1199
1205
|
lower: true,
|
|
1200
1206
|
// convert to lower case, defaults to `false`
|
|
1201
1207
|
strict: true
|
|
@@ -1203,81 +1209,10 @@ function slug(string) {
|
|
|
1203
1209
|
});
|
|
1204
1210
|
}
|
|
1205
1211
|
|
|
1206
|
-
// src/service/JsonFileService.ts
|
|
1207
|
-
import Fs2 from "fs-extra";
|
|
1208
|
-
var JsonFileService = class extends AbstractCrudService {
|
|
1209
|
-
constructor(options) {
|
|
1210
|
-
super(serviceTypeSchema.Enum.JsonFile, options);
|
|
1211
|
-
this.cache = /* @__PURE__ */ new Map();
|
|
1212
|
-
}
|
|
1213
|
-
/**
|
|
1214
|
-
* Creates a new file on disk. Fails if path already exists
|
|
1215
|
-
*
|
|
1216
|
-
* @param data Data to write into the file
|
|
1217
|
-
* @param path Path to write the file to
|
|
1218
|
-
* @param schema Schema of the file to validate against
|
|
1219
|
-
* @returns Validated content of the file from disk
|
|
1220
|
-
*/
|
|
1221
|
-
async create(data, path, schema) {
|
|
1222
|
-
const parsedData = schema.parse(data);
|
|
1223
|
-
const string = this.serialize(parsedData);
|
|
1224
|
-
await Fs2.writeFile(path, string, {
|
|
1225
|
-
flag: "wx",
|
|
1226
|
-
encoding: "utf8"
|
|
1227
|
-
});
|
|
1228
|
-
this.cache.set(path, parsedData);
|
|
1229
|
-
return parsedData;
|
|
1230
|
-
}
|
|
1231
|
-
/**
|
|
1232
|
-
* Reads the content of a file on disk. Fails if path does not exist
|
|
1233
|
-
*
|
|
1234
|
-
* @param path Path to read the file from
|
|
1235
|
-
* @param schema Schema of the file to validate against
|
|
1236
|
-
* @returns Validated content of the file from disk
|
|
1237
|
-
*/
|
|
1238
|
-
async read(path, schema) {
|
|
1239
|
-
if (this.cache.has(path)) {
|
|
1240
|
-
return this.cache.get(path);
|
|
1241
|
-
}
|
|
1242
|
-
const data = await Fs2.readFile(path, {
|
|
1243
|
-
flag: "r",
|
|
1244
|
-
encoding: "utf8"
|
|
1245
|
-
});
|
|
1246
|
-
const json = this.deserialize(data);
|
|
1247
|
-
const parsedData = schema.parse(json);
|
|
1248
|
-
this.cache.set(path, parsedData);
|
|
1249
|
-
return parsedData;
|
|
1250
|
-
}
|
|
1251
|
-
/**
|
|
1252
|
-
* Overwrites an existing file on disk
|
|
1253
|
-
*
|
|
1254
|
-
* @todo Check how to error out if the file does not exist already
|
|
1255
|
-
*
|
|
1256
|
-
* @param data Data to write into the file
|
|
1257
|
-
* @param path Path to the file to overwrite
|
|
1258
|
-
* @param schema Schema of the file to validate against
|
|
1259
|
-
* @returns Validated content of the file from disk
|
|
1260
|
-
*/
|
|
1261
|
-
async update(data, path, schema) {
|
|
1262
|
-
const parsedData = schema.parse(data);
|
|
1263
|
-
const string = this.serialize(parsedData);
|
|
1264
|
-
await Fs2.writeFile(path, string, {
|
|
1265
|
-
flag: "w",
|
|
1266
|
-
encoding: "utf8"
|
|
1267
|
-
});
|
|
1268
|
-
this.cache.set(path, parsedData);
|
|
1269
|
-
return parsedData;
|
|
1270
|
-
}
|
|
1271
|
-
serialize(data) {
|
|
1272
|
-
return JSON.stringify(data, null, this.options.file.json.indentation);
|
|
1273
|
-
}
|
|
1274
|
-
deserialize(data) {
|
|
1275
|
-
return JSON.parse(data);
|
|
1276
|
-
}
|
|
1277
|
-
};
|
|
1278
|
-
|
|
1279
1212
|
// src/service/AssetService.ts
|
|
1280
1213
|
var AssetService = class extends AbstractCrudService {
|
|
1214
|
+
jsonFileService;
|
|
1215
|
+
gitService;
|
|
1281
1216
|
constructor(options, jsonFileService, gitService) {
|
|
1282
1217
|
super(serviceTypeSchema.Enum.Asset, options);
|
|
1283
1218
|
this.jsonFileService = jsonFileService;
|
|
@@ -1310,7 +1245,7 @@ var AssetService = class extends AbstractCrudService {
|
|
|
1310
1245
|
size
|
|
1311
1246
|
};
|
|
1312
1247
|
try {
|
|
1313
|
-
await
|
|
1248
|
+
await Fs2.copyFile(props.filePath, assetPath);
|
|
1314
1249
|
await this.jsonFileService.create(
|
|
1315
1250
|
assetFile,
|
|
1316
1251
|
assetFilePath,
|
|
@@ -1371,8 +1306,8 @@ var AssetService = class extends AbstractCrudService {
|
|
|
1371
1306
|
props.language,
|
|
1372
1307
|
fileType.extension
|
|
1373
1308
|
);
|
|
1374
|
-
await
|
|
1375
|
-
await
|
|
1309
|
+
await Fs2.remove(prevAssetPath);
|
|
1310
|
+
await Fs2.copyFile(props.newFilePath, assetPath);
|
|
1376
1311
|
assetFile.extension = fileType.extension;
|
|
1377
1312
|
assetFile.mimeType = fileType.mimeType;
|
|
1378
1313
|
assetFile.size = size;
|
|
@@ -1403,8 +1338,8 @@ var AssetService = class extends AbstractCrudService {
|
|
|
1403
1338
|
props.language,
|
|
1404
1339
|
props.extension
|
|
1405
1340
|
);
|
|
1406
|
-
await
|
|
1407
|
-
await
|
|
1341
|
+
await Fs2.remove(assetPath);
|
|
1342
|
+
await Fs2.remove(assetFilePath);
|
|
1408
1343
|
await this.gitService.add(projectPath, [assetFilePath, assetPath]);
|
|
1409
1344
|
await this.gitService.commit(projectPath, this.gitMessage.delete);
|
|
1410
1345
|
}
|
|
@@ -1453,7 +1388,7 @@ var AssetService = class extends AbstractCrudService {
|
|
|
1453
1388
|
* @param path Path of the Asset to get the size from
|
|
1454
1389
|
*/
|
|
1455
1390
|
async getAssetSize(path) {
|
|
1456
|
-
return (await
|
|
1391
|
+
return (await Fs2.stat(path)).size;
|
|
1457
1392
|
}
|
|
1458
1393
|
/**
|
|
1459
1394
|
* Creates an Asset from given AssetFile
|
|
@@ -1481,17 +1416,16 @@ var AssetService = class extends AbstractCrudService {
|
|
|
1481
1416
|
* @param filePath Path to the file to check
|
|
1482
1417
|
*/
|
|
1483
1418
|
async getSupportedFileTypeOrThrow(filePath) {
|
|
1484
|
-
const fileSize = (await
|
|
1419
|
+
const fileSize = (await Fs2.stat(filePath)).size;
|
|
1485
1420
|
if (fileSize / 1e3 <= 500) {
|
|
1486
|
-
const fileBuffer = await
|
|
1487
|
-
if (
|
|
1421
|
+
const fileBuffer = await Fs2.readFile(filePath);
|
|
1422
|
+
if (isSvg(fileBuffer.toString()) === true) {
|
|
1488
1423
|
return {
|
|
1489
1424
|
extension: supportedAssetExtensionSchema.Enum.svg,
|
|
1490
1425
|
mimeType: supportedAssetMimeTypeSchema.Enum["image/svg+xml"]
|
|
1491
1426
|
};
|
|
1492
1427
|
}
|
|
1493
1428
|
}
|
|
1494
|
-
const { fileTypeFromFile } = await import("file-type");
|
|
1495
1429
|
const fileType = await fileTypeFromFile(filePath);
|
|
1496
1430
|
const result = supportedAssetTypeSchema.parse({
|
|
1497
1431
|
extension: fileType?.ext,
|
|
@@ -1502,448 +1436,855 @@ var AssetService = class extends AbstractCrudService {
|
|
|
1502
1436
|
};
|
|
1503
1437
|
|
|
1504
1438
|
// src/service/CollectionService.ts
|
|
1505
|
-
import
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
import { EOL } from "os";
|
|
1514
|
-
var GitTagService = class extends AbstractCrudService {
|
|
1515
|
-
constructor(options, git) {
|
|
1516
|
-
super(serviceTypeSchema.Enum.GitTag, options);
|
|
1517
|
-
this.git = git;
|
|
1439
|
+
import Fs3 from "fs-extra";
|
|
1440
|
+
var CollectionService = class extends AbstractCrudService {
|
|
1441
|
+
jsonFileService;
|
|
1442
|
+
gitService;
|
|
1443
|
+
constructor(options, jsonFileService, gitService) {
|
|
1444
|
+
super(serviceTypeSchema.Enum.Collection, options);
|
|
1445
|
+
this.jsonFileService = jsonFileService;
|
|
1446
|
+
this.gitService = gitService;
|
|
1518
1447
|
}
|
|
1519
1448
|
/**
|
|
1520
|
-
* Creates a new
|
|
1521
|
-
*
|
|
1522
|
-
* @see https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---annotate
|
|
1449
|
+
* Creates a new Collection
|
|
1523
1450
|
*/
|
|
1524
1451
|
async create(props) {
|
|
1525
|
-
|
|
1452
|
+
createCollectionSchema.parse(props);
|
|
1526
1453
|
const id = uuid();
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1454
|
+
const projectPath = pathTo.project(props.projectId);
|
|
1455
|
+
const collectionPath = pathTo.collection(props.projectId, id);
|
|
1456
|
+
const collectionFilePath = pathTo.collectionFile(props.projectId, id);
|
|
1457
|
+
const collectionFile = {
|
|
1458
|
+
...props,
|
|
1459
|
+
objectType: "collection",
|
|
1460
|
+
id,
|
|
1461
|
+
slug: {
|
|
1462
|
+
singular: slug(props.slug.singular),
|
|
1463
|
+
plural: slug(props.slug.plural)
|
|
1464
|
+
},
|
|
1465
|
+
created: currentTimestamp(),
|
|
1466
|
+
updated: null
|
|
1467
|
+
};
|
|
1468
|
+
await Fs3.ensureDir(collectionPath);
|
|
1469
|
+
await this.jsonFileService.create(
|
|
1470
|
+
collectionFile,
|
|
1471
|
+
collectionFilePath,
|
|
1472
|
+
collectionFileSchema
|
|
1473
|
+
);
|
|
1474
|
+
await this.gitService.add(projectPath, [collectionFilePath]);
|
|
1475
|
+
await this.gitService.commit(projectPath, this.gitMessage.create);
|
|
1476
|
+
return collectionFile;
|
|
1535
1477
|
}
|
|
1536
1478
|
/**
|
|
1537
|
-
* Returns a
|
|
1538
|
-
*
|
|
1539
|
-
* Internally uses list() but only returns the tag with matching ID.
|
|
1479
|
+
* Returns a Collection by ID
|
|
1540
1480
|
*/
|
|
1541
1481
|
async read(props) {
|
|
1542
|
-
|
|
1543
|
-
const
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
throw new GitError(
|
|
1549
|
-
`Provided tag with UUID "${props.id}" did not match any known tags`
|
|
1550
|
-
);
|
|
1551
|
-
}
|
|
1552
|
-
return tag;
|
|
1482
|
+
readCollectionSchema.parse(props);
|
|
1483
|
+
const collection = await this.jsonFileService.read(
|
|
1484
|
+
pathTo.collectionFile(props.projectId, props.id),
|
|
1485
|
+
collectionFileSchema
|
|
1486
|
+
);
|
|
1487
|
+
return collection;
|
|
1553
1488
|
}
|
|
1554
1489
|
/**
|
|
1555
|
-
*
|
|
1556
|
-
* Please delete the old and create a new one
|
|
1490
|
+
* Updates given Collection
|
|
1557
1491
|
*
|
|
1558
|
-
* @
|
|
1492
|
+
* @todo finish implementing checks for FieldDefinitions and extract methods
|
|
1493
|
+
*
|
|
1494
|
+
* @param projectId Project ID of the collection to update
|
|
1495
|
+
* @param collection Collection to write to disk
|
|
1496
|
+
* @returns An object containing information about the actions needed to be taken,
|
|
1497
|
+
* before given update can be executed or void if the update was executed successfully
|
|
1559
1498
|
*/
|
|
1560
|
-
async update() {
|
|
1561
|
-
|
|
1562
|
-
|
|
1499
|
+
async update(props) {
|
|
1500
|
+
updateCollectionSchema.parse(props);
|
|
1501
|
+
const projectPath = pathTo.project(props.projectId);
|
|
1502
|
+
const collectionFilePath = pathTo.collectionFile(props.projectId, props.id);
|
|
1503
|
+
const prevCollectionFile = await this.read(props);
|
|
1504
|
+
const collectionFile = {
|
|
1505
|
+
...prevCollectionFile,
|
|
1506
|
+
...props,
|
|
1507
|
+
updated: currentTimestamp()
|
|
1508
|
+
};
|
|
1509
|
+
await this.jsonFileService.update(
|
|
1510
|
+
collectionFile,
|
|
1511
|
+
collectionFilePath,
|
|
1512
|
+
collectionFileSchema
|
|
1563
1513
|
);
|
|
1514
|
+
await this.gitService.add(projectPath, [collectionFilePath]);
|
|
1515
|
+
await this.gitService.commit(projectPath, this.gitMessage.update);
|
|
1516
|
+
return collectionFile;
|
|
1564
1517
|
}
|
|
1565
1518
|
/**
|
|
1566
|
-
* Deletes
|
|
1567
|
-
*
|
|
1568
|
-
* @see https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---delete
|
|
1519
|
+
* Deletes given Collection (folder), including it's items
|
|
1569
1520
|
*
|
|
1570
|
-
*
|
|
1571
|
-
* @param id UUID of the tag to delete
|
|
1521
|
+
* The Fields that Collection used are not deleted.
|
|
1572
1522
|
*/
|
|
1573
1523
|
async delete(props) {
|
|
1574
|
-
|
|
1575
|
-
const
|
|
1576
|
-
|
|
1524
|
+
deleteCollectionSchema.parse(props);
|
|
1525
|
+
const projectPath = pathTo.project(props.projectId);
|
|
1526
|
+
const collectionPath = pathTo.collection(props.projectId, props.id);
|
|
1527
|
+
await Fs3.remove(collectionPath);
|
|
1528
|
+
await this.gitService.add(projectPath, [collectionPath]);
|
|
1529
|
+
await this.gitService.commit(projectPath, this.gitMessage.delete);
|
|
1577
1530
|
}
|
|
1578
|
-
/**
|
|
1579
|
-
* Gets all local tags or filter them by pattern
|
|
1580
|
-
*
|
|
1581
|
-
* They are sorted by authordate of the commit, not the timestamp the tag is created.
|
|
1582
|
-
* This ensures tags are sorted correctly in the timeline of their commits.
|
|
1583
|
-
*
|
|
1584
|
-
* @see https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---list
|
|
1585
|
-
*/
|
|
1586
1531
|
async list(props) {
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
const
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
const
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
},
|
|
1607
|
-
timestamp: parseInt(lineArray[4])
|
|
1608
|
-
};
|
|
1609
|
-
});
|
|
1610
|
-
const gitTags = lineObjArr.filter(this.isGitTag.bind(this));
|
|
1532
|
+
listCollectionsSchema.parse(props);
|
|
1533
|
+
const offset = props.offset || 0;
|
|
1534
|
+
const limit = props.limit || 15;
|
|
1535
|
+
const collectionReferences = await this.listReferences(
|
|
1536
|
+
objectTypeSchema.Enum.collection,
|
|
1537
|
+
props.projectId
|
|
1538
|
+
);
|
|
1539
|
+
const partialCollectionReferences = collectionReferences.slice(
|
|
1540
|
+
offset,
|
|
1541
|
+
limit
|
|
1542
|
+
);
|
|
1543
|
+
const collections = await returnResolved(
|
|
1544
|
+
partialCollectionReferences.map((reference) => {
|
|
1545
|
+
return this.read({
|
|
1546
|
+
projectId: props.projectId,
|
|
1547
|
+
id: reference.id
|
|
1548
|
+
});
|
|
1549
|
+
})
|
|
1550
|
+
);
|
|
1611
1551
|
return {
|
|
1612
|
-
total:
|
|
1613
|
-
limit
|
|
1614
|
-
offset
|
|
1615
|
-
list:
|
|
1552
|
+
total: collectionReferences.length,
|
|
1553
|
+
limit,
|
|
1554
|
+
offset,
|
|
1555
|
+
list: collections
|
|
1616
1556
|
};
|
|
1617
1557
|
}
|
|
1618
|
-
/**
|
|
1619
|
-
* Returns the total number of tags inside given repository
|
|
1620
|
-
*
|
|
1621
|
-
* Internally uses list(), so do not use count()
|
|
1622
|
-
* in conjuncion with it to avoid multiple git calls.
|
|
1623
|
-
*
|
|
1624
|
-
* @param path Path to the repository
|
|
1625
|
-
*/
|
|
1626
1558
|
async count(props) {
|
|
1627
|
-
|
|
1628
|
-
const
|
|
1629
|
-
|
|
1559
|
+
countCollectionsSchema.parse(props);
|
|
1560
|
+
const count = (await this.listReferences(
|
|
1561
|
+
objectTypeSchema.Enum.collection,
|
|
1562
|
+
props.projectId
|
|
1563
|
+
)).length;
|
|
1564
|
+
return count;
|
|
1630
1565
|
}
|
|
1631
1566
|
/**
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1634
|
-
* @param obj The object to check
|
|
1567
|
+
* Checks if given object is of type Collection
|
|
1635
1568
|
*/
|
|
1636
|
-
|
|
1637
|
-
return
|
|
1569
|
+
isCollection(obj) {
|
|
1570
|
+
return collectionFileSchema.safeParse(obj).success;
|
|
1638
1571
|
}
|
|
1639
1572
|
};
|
|
1640
1573
|
|
|
1641
|
-
// src/service/
|
|
1642
|
-
|
|
1643
|
-
|
|
1574
|
+
// src/service/EntryService.ts
|
|
1575
|
+
import Fs4 from "fs-extra";
|
|
1576
|
+
var EntryService = class extends AbstractCrudService {
|
|
1577
|
+
jsonFileService;
|
|
1578
|
+
gitService;
|
|
1579
|
+
collectionService;
|
|
1580
|
+
assetService;
|
|
1581
|
+
// private sharedValueService: SharedValueService;
|
|
1582
|
+
constructor(options, jsonFileService, gitService, collectionService, assetService) {
|
|
1583
|
+
super(serviceTypeSchema.Enum.Entry, options);
|
|
1644
1584
|
this.jsonFileService = jsonFileService;
|
|
1585
|
+
this.gitService = gitService;
|
|
1586
|
+
this.collectionService = collectionService;
|
|
1587
|
+
this.assetService = assetService;
|
|
1645
1588
|
}
|
|
1646
1589
|
/**
|
|
1647
|
-
*
|
|
1590
|
+
* Creates a new Entry for given Collection
|
|
1648
1591
|
*/
|
|
1649
|
-
async
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1592
|
+
async create(props) {
|
|
1593
|
+
createEntrySchema.parse(props);
|
|
1594
|
+
const id = uuid();
|
|
1595
|
+
const projectPath = pathTo.project(props.projectId);
|
|
1596
|
+
const entryFilePath = pathTo.entryFile(
|
|
1597
|
+
props.projectId,
|
|
1598
|
+
props.collectionId,
|
|
1599
|
+
id
|
|
1600
|
+
);
|
|
1601
|
+
const collection = await this.collectionService.read({
|
|
1602
|
+
projectId: props.projectId,
|
|
1603
|
+
id: props.collectionId
|
|
1604
|
+
});
|
|
1605
|
+
const entryFile = {
|
|
1606
|
+
objectType: "entry",
|
|
1607
|
+
id,
|
|
1608
|
+
values: props.values,
|
|
1609
|
+
created: currentTimestamp(),
|
|
1610
|
+
updated: null
|
|
1611
|
+
};
|
|
1612
|
+
const entry = await this.toEntry({
|
|
1613
|
+
projectId: props.projectId,
|
|
1614
|
+
collectionId: props.collectionId,
|
|
1615
|
+
entryFile
|
|
1616
|
+
});
|
|
1617
|
+
this.validateValues({
|
|
1618
|
+
collectionId: props.collectionId,
|
|
1619
|
+
valueDefinitions: collection.valueDefinitions,
|
|
1620
|
+
values: entry.values
|
|
1621
|
+
});
|
|
1622
|
+
await this.jsonFileService.create(
|
|
1623
|
+
entryFile,
|
|
1624
|
+
entryFilePath,
|
|
1625
|
+
entryFileSchema
|
|
1626
|
+
);
|
|
1627
|
+
await this.gitService.add(projectPath, [entryFilePath]);
|
|
1628
|
+
await this.gitService.commit(projectPath, this.gitMessage.create);
|
|
1629
|
+
return entry;
|
|
1655
1630
|
}
|
|
1656
1631
|
/**
|
|
1657
|
-
*
|
|
1658
|
-
*
|
|
1659
|
-
* By doing so all git operations are done with the signature of this User
|
|
1632
|
+
* Returns an Entry from given Collection by ID and language
|
|
1660
1633
|
*/
|
|
1661
|
-
async
|
|
1662
|
-
|
|
1663
|
-
const
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1634
|
+
async read(props) {
|
|
1635
|
+
readEntrySchema.parse(props);
|
|
1636
|
+
const entryFile = await this.jsonFileService.read(
|
|
1637
|
+
pathTo.entryFile(props.projectId, props.collectionId, props.id),
|
|
1638
|
+
entryFileSchema
|
|
1639
|
+
);
|
|
1640
|
+
return await this.toEntry({
|
|
1641
|
+
projectId: props.projectId,
|
|
1642
|
+
collectionId: props.collectionId,
|
|
1643
|
+
entryFile
|
|
1644
|
+
});
|
|
1671
1645
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
if (line.startsWith("remotes/")) {
|
|
1697
|
-
remote.push(line.replace("remotes/", ""));
|
|
1698
|
-
} else {
|
|
1699
|
-
local.push(line);
|
|
1700
|
-
}
|
|
1701
|
-
});
|
|
1702
|
-
return {
|
|
1703
|
-
local,
|
|
1704
|
-
remote
|
|
1705
|
-
};
|
|
1706
|
-
},
|
|
1707
|
-
/**
|
|
1708
|
-
* Returns the name of the current branch. In detached HEAD state, an empty string is returned.
|
|
1709
|
-
*
|
|
1710
|
-
* @see https://www.git-scm.com/docs/git-branch#Documentation/git-branch.txt---show-current
|
|
1711
|
-
*
|
|
1712
|
-
* @param path Path to the repository
|
|
1713
|
-
*/
|
|
1714
|
-
current: async (path) => {
|
|
1715
|
-
const args = ["branch", "--show-current"];
|
|
1716
|
-
const result = await this.git(path, args);
|
|
1717
|
-
return result.stdout.trim();
|
|
1718
|
-
},
|
|
1719
|
-
/**
|
|
1720
|
-
* Switch branches
|
|
1721
|
-
*
|
|
1722
|
-
* @see https://git-scm.com/docs/git-switch/
|
|
1723
|
-
*
|
|
1724
|
-
* @param path Path to the repository
|
|
1725
|
-
* @param branch Name of the branch to switch to
|
|
1726
|
-
* @param options Options specific to the switch operation
|
|
1727
|
-
*/
|
|
1728
|
-
switch: async (path, branch, options) => {
|
|
1729
|
-
await this.checkBranchOrTagName(path, branch);
|
|
1730
|
-
let args = ["switch"];
|
|
1731
|
-
if (options?.isNew === true) {
|
|
1732
|
-
args = [...args, "--create", branch];
|
|
1733
|
-
} else {
|
|
1734
|
-
args = [...args, branch];
|
|
1735
|
-
}
|
|
1736
|
-
await this.git(path, args);
|
|
1737
|
-
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Updates an Entry of given Collection with new Values and shared Values
|
|
1648
|
+
*/
|
|
1649
|
+
async update(props) {
|
|
1650
|
+
updateEntrySchema.parse(props);
|
|
1651
|
+
const projectPath = pathTo.project(props.projectId);
|
|
1652
|
+
const entryFilePath = pathTo.entryFile(
|
|
1653
|
+
props.projectId,
|
|
1654
|
+
props.collectionId,
|
|
1655
|
+
props.id
|
|
1656
|
+
);
|
|
1657
|
+
const collection = await this.collectionService.read({
|
|
1658
|
+
projectId: props.projectId,
|
|
1659
|
+
id: props.collectionId
|
|
1660
|
+
});
|
|
1661
|
+
const prevEntryFile = await this.read({
|
|
1662
|
+
projectId: props.projectId,
|
|
1663
|
+
collectionId: props.collectionId,
|
|
1664
|
+
id: props.id
|
|
1665
|
+
});
|
|
1666
|
+
const entryFile = {
|
|
1667
|
+
...prevEntryFile,
|
|
1668
|
+
values: props.values,
|
|
1669
|
+
updated: currentTimestamp()
|
|
1738
1670
|
};
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1671
|
+
const entry = await this.toEntry({
|
|
1672
|
+
projectId: props.projectId,
|
|
1673
|
+
collectionId: props.collectionId,
|
|
1674
|
+
entryFile
|
|
1675
|
+
});
|
|
1676
|
+
this.validateValues({
|
|
1677
|
+
collectionId: props.collectionId,
|
|
1678
|
+
valueDefinitions: collection.valueDefinitions,
|
|
1679
|
+
values: entry.values
|
|
1680
|
+
});
|
|
1681
|
+
await this.jsonFileService.update(
|
|
1682
|
+
entryFile,
|
|
1683
|
+
entryFilePath,
|
|
1684
|
+
entryFileSchema
|
|
1685
|
+
);
|
|
1686
|
+
await this.gitService.add(projectPath, [entryFilePath]);
|
|
1687
|
+
await this.gitService.commit(projectPath, this.gitMessage.update);
|
|
1688
|
+
return entry;
|
|
1689
|
+
}
|
|
1690
|
+
/**
|
|
1691
|
+
* Deletes given Entry from it's Collection
|
|
1692
|
+
*/
|
|
1693
|
+
async delete(props) {
|
|
1694
|
+
deleteEntrySchema.parse(props);
|
|
1695
|
+
const projectPath = pathTo.project(props.projectId);
|
|
1696
|
+
const entryFilePath = pathTo.entryFile(
|
|
1697
|
+
props.projectId,
|
|
1698
|
+
props.collectionId,
|
|
1699
|
+
props.id
|
|
1700
|
+
);
|
|
1701
|
+
await Fs4.remove(entryFilePath);
|
|
1702
|
+
await this.gitService.add(projectPath, [entryFilePath]);
|
|
1703
|
+
await this.gitService.commit(projectPath, this.gitMessage.delete);
|
|
1704
|
+
}
|
|
1705
|
+
async list(props) {
|
|
1706
|
+
listEntriesSchema.parse(props);
|
|
1707
|
+
const offset = props.offset || 0;
|
|
1708
|
+
const limit = props.limit || 15;
|
|
1709
|
+
const entryReferences = await this.listReferences(
|
|
1710
|
+
objectTypeSchema.Enum.entry,
|
|
1711
|
+
props.projectId,
|
|
1712
|
+
props.collectionId
|
|
1713
|
+
);
|
|
1714
|
+
const partialEntryReferences = entryReferences.slice(offset, limit);
|
|
1715
|
+
const entries = await returnResolved(
|
|
1716
|
+
partialEntryReferences.map((reference) => {
|
|
1717
|
+
return this.read({
|
|
1718
|
+
projectId: props.projectId,
|
|
1719
|
+
collectionId: props.collectionId,
|
|
1720
|
+
id: reference.id
|
|
1752
1721
|
});
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
hasOrigin: async (path) => {
|
|
1761
|
-
const remotes = await this.remotes.list(path);
|
|
1762
|
-
if (remotes.includes("origin")) {
|
|
1763
|
-
return true;
|
|
1764
|
-
}
|
|
1765
|
-
return false;
|
|
1766
|
-
},
|
|
1767
|
-
/**
|
|
1768
|
-
* Adds the `origin` remote with given URL
|
|
1769
|
-
*
|
|
1770
|
-
* Throws if `origin` remote is added already.
|
|
1771
|
-
*
|
|
1772
|
-
* @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emaddem
|
|
1773
|
-
*
|
|
1774
|
-
* @param path Path to the repository
|
|
1775
|
-
*/
|
|
1776
|
-
addOrigin: async (path, url) => {
|
|
1777
|
-
const args = ["remote", "add", "origin", url];
|
|
1778
|
-
await this.git(path, args);
|
|
1779
|
-
},
|
|
1780
|
-
/**
|
|
1781
|
-
* Returns the current `origin` remote URL
|
|
1782
|
-
*
|
|
1783
|
-
* Throws if no `origin` remote is added yet.
|
|
1784
|
-
*
|
|
1785
|
-
* @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emget-urlem
|
|
1786
|
-
*
|
|
1787
|
-
* @param path Path to the repository
|
|
1788
|
-
*/
|
|
1789
|
-
getOriginUrl: async (path) => {
|
|
1790
|
-
const args = ["remote", "get-url", "origin"];
|
|
1791
|
-
const result = (await this.git(path, args)).stdout.trim();
|
|
1792
|
-
return result.length === 0 ? null : result;
|
|
1793
|
-
},
|
|
1794
|
-
/**
|
|
1795
|
-
* Sets the current `origin` remote URL
|
|
1796
|
-
*
|
|
1797
|
-
* Throws if no `origin` remote is added yet.
|
|
1798
|
-
*
|
|
1799
|
-
* @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emset-urlem
|
|
1800
|
-
*
|
|
1801
|
-
* @param path Path to the repository
|
|
1802
|
-
*/
|
|
1803
|
-
setOriginUrl: async (path, url) => {
|
|
1804
|
-
const args = ["remote", "set-url", "origin", url];
|
|
1805
|
-
await this.git(path, args);
|
|
1806
|
-
}
|
|
1722
|
+
})
|
|
1723
|
+
);
|
|
1724
|
+
return {
|
|
1725
|
+
total: entryReferences.length,
|
|
1726
|
+
limit,
|
|
1727
|
+
offset,
|
|
1728
|
+
list: entries
|
|
1807
1729
|
};
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
this.updateVersion();
|
|
1817
|
-
this.updateGitPath();
|
|
1730
|
+
}
|
|
1731
|
+
async count(props) {
|
|
1732
|
+
countEntriesSchema.parse(props);
|
|
1733
|
+
return (await this.listReferences(
|
|
1734
|
+
objectTypeSchema.Enum.entry,
|
|
1735
|
+
props.projectId,
|
|
1736
|
+
props.collectionId
|
|
1737
|
+
)).length;
|
|
1818
1738
|
}
|
|
1819
1739
|
/**
|
|
1820
|
-
*
|
|
1740
|
+
* Checks if given object is of type Entry
|
|
1821
1741
|
*/
|
|
1822
|
-
|
|
1823
|
-
return
|
|
1742
|
+
isEntry(obj) {
|
|
1743
|
+
return entrySchema.safeParse(obj).success;
|
|
1824
1744
|
}
|
|
1825
1745
|
/**
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1828
|
-
* @see https://git-scm.com/docs/git-init
|
|
1829
|
-
*
|
|
1830
|
-
* @param path Path to initialize in. Fails if path does not exist
|
|
1831
|
-
* @param options Options specific to the init operation
|
|
1746
|
+
* Returns a Value definition by ID
|
|
1832
1747
|
*/
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1748
|
+
getValueDefinitionById(props) {
|
|
1749
|
+
const definition = props.valueDefinitions.find((def) => {
|
|
1750
|
+
if (def.id === props.id) {
|
|
1751
|
+
return true;
|
|
1752
|
+
}
|
|
1753
|
+
return false;
|
|
1754
|
+
});
|
|
1755
|
+
if (!definition) {
|
|
1756
|
+
throw new Error(
|
|
1757
|
+
`No definition with ID "${props.id}" found in Collection "${props.collectionId}" for given Value reference`
|
|
1758
|
+
);
|
|
1759
|
+
}
|
|
1760
|
+
return definition;
|
|
1841
1761
|
}
|
|
1842
1762
|
/**
|
|
1843
|
-
*
|
|
1844
|
-
*
|
|
1845
|
-
* @see https://git-scm.com/docs/git-clone
|
|
1846
|
-
*
|
|
1847
|
-
* @todo Implement progress callback / events
|
|
1848
|
-
*
|
|
1849
|
-
* @param url The remote repository URL to clone from
|
|
1850
|
-
* @param path The destination path for the cloned repository.
|
|
1851
|
-
* Which is only working if the directory is existing and empty.
|
|
1852
|
-
* @param options Options specific to the clone operation
|
|
1763
|
+
* Validates given Values against it's Collections definitions
|
|
1853
1764
|
*/
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1765
|
+
validateValues(props) {
|
|
1766
|
+
props.values.map((value) => {
|
|
1767
|
+
const definition = this.getValueDefinitionById({
|
|
1768
|
+
collectionId: props.collectionId,
|
|
1769
|
+
valueDefinitions: props.valueDefinitions,
|
|
1770
|
+
id: value.definitionId
|
|
1771
|
+
});
|
|
1772
|
+
const schema = getValueContentSchemaFromDefinition(definition);
|
|
1773
|
+
try {
|
|
1774
|
+
for (const [, content] of Object.entries(value.content)) {
|
|
1775
|
+
schema.parse(content);
|
|
1776
|
+
}
|
|
1777
|
+
} catch (error) {
|
|
1778
|
+
console.log("Definition:", definition);
|
|
1779
|
+
console.log("Value:", value);
|
|
1780
|
+
throw error;
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
/**
|
|
1785
|
+
* Validates given shared Value references against it's Collections definitions
|
|
1786
|
+
*/
|
|
1787
|
+
// private validateResolvedSharedValues(props: {
|
|
1788
|
+
// collectionId: string;
|
|
1789
|
+
// valueDefinitions: ValueDefinition[];
|
|
1790
|
+
// resolvedSharedValues: ResolvedSharedValueReference[];
|
|
1791
|
+
// }) {
|
|
1792
|
+
// props.resolvedSharedValues.map((value) => {
|
|
1793
|
+
// const definition = this.getValueDefinitionById({
|
|
1794
|
+
// collectionId: props.collectionId,
|
|
1795
|
+
// valueDefinitions: props.valueDefinitions,
|
|
1796
|
+
// id: value.definitionId,
|
|
1797
|
+
// });
|
|
1798
|
+
// const schema = getValueSchemaFromDefinition(definition);
|
|
1799
|
+
// schema.parse(value.resolved.content);
|
|
1800
|
+
// });
|
|
1801
|
+
// }
|
|
1802
|
+
async resolveValueContentReference(props) {
|
|
1803
|
+
switch (props.valueContentReference.objectType) {
|
|
1804
|
+
case objectTypeSchema.Enum.asset:
|
|
1805
|
+
return await this.assetService.read({
|
|
1806
|
+
projectId: props.projectId,
|
|
1807
|
+
id: props.valueContentReference.id,
|
|
1808
|
+
language: props.valueContentReference.language
|
|
1809
|
+
});
|
|
1810
|
+
case objectTypeSchema.Enum.entry:
|
|
1811
|
+
return await this.read({
|
|
1812
|
+
projectId: props.projectId,
|
|
1813
|
+
collectionId: props.collectionId,
|
|
1814
|
+
id: props.valueContentReference.id
|
|
1815
|
+
});
|
|
1816
|
+
default:
|
|
1817
|
+
throw new Error(
|
|
1818
|
+
// @ts-ignore
|
|
1819
|
+
`Tried to resolve unsupported Value reference "${props.valueContentReference.referenceObjectType}"`
|
|
1820
|
+
);
|
|
1861
1821
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1822
|
+
}
|
|
1823
|
+
async resolveValueContentReferences(props) {
|
|
1824
|
+
let resolvedContent = {};
|
|
1825
|
+
for (const language in props.valueReference.content) {
|
|
1826
|
+
const referencesOfLanguage = props.valueReference.content[language];
|
|
1827
|
+
if (!referencesOfLanguage) {
|
|
1828
|
+
throw new Error(
|
|
1829
|
+
`Trying to access content references by language "${language}" failed`
|
|
1830
|
+
);
|
|
1831
|
+
}
|
|
1832
|
+
const resolvedReferencesOfLanguage = await Promise.all(
|
|
1833
|
+
referencesOfLanguage.map(async (reference) => {
|
|
1834
|
+
return await this.resolveValueContentReference({
|
|
1835
|
+
projectId: props.projectId,
|
|
1836
|
+
collectionId: props.collectionId,
|
|
1837
|
+
valueContentReference: reference
|
|
1838
|
+
});
|
|
1839
|
+
})
|
|
1840
|
+
);
|
|
1841
|
+
resolvedContent = {
|
|
1842
|
+
...resolvedContent,
|
|
1843
|
+
[language]: resolvedReferencesOfLanguage
|
|
1844
|
+
};
|
|
1864
1845
|
}
|
|
1865
|
-
|
|
1866
|
-
await this.setLocalConfig(path);
|
|
1846
|
+
return resolvedContent;
|
|
1867
1847
|
}
|
|
1868
1848
|
/**
|
|
1869
|
-
*
|
|
1870
|
-
*
|
|
1871
|
-
* @see https://git-scm.com/docs/git-add
|
|
1872
|
-
*
|
|
1873
|
-
* @param path Path to the repository
|
|
1874
|
-
* @param files Files to add
|
|
1849
|
+
* Creates an Entry from given EntryFile by resolving it's Values
|
|
1875
1850
|
*/
|
|
1876
|
-
async
|
|
1877
|
-
|
|
1878
|
-
|
|
1851
|
+
async toEntry(props) {
|
|
1852
|
+
return {
|
|
1853
|
+
...props.entryFile,
|
|
1854
|
+
// @ts-ignore @todo fixme - I have no idea why this happens. The types seem to be compatible to me and they work
|
|
1855
|
+
values: await Promise.all(
|
|
1856
|
+
props.entryFile.values.map(async (value) => {
|
|
1857
|
+
if (value.valueType === ValueTypeSchema.Enum.reference) {
|
|
1858
|
+
const resolvedContentReferences = await this.resolveValueContentReferences({
|
|
1859
|
+
projectId: props.projectId,
|
|
1860
|
+
collectionId: props.collectionId,
|
|
1861
|
+
valueReference: value
|
|
1862
|
+
});
|
|
1863
|
+
return {
|
|
1864
|
+
...value,
|
|
1865
|
+
content: resolvedContentReferences
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
return value;
|
|
1869
|
+
})
|
|
1870
|
+
)
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
};
|
|
1874
|
+
|
|
1875
|
+
// src/service/GitService.ts
|
|
1876
|
+
import { GitProcess } from "dugite";
|
|
1877
|
+
import { EOL as EOL2 } from "os";
|
|
1878
|
+
import PQueue from "p-queue";
|
|
1879
|
+
|
|
1880
|
+
// src/service/GitTagService.ts
|
|
1881
|
+
import { EOL } from "os";
|
|
1882
|
+
var GitTagService = class extends AbstractCrudService {
|
|
1883
|
+
git;
|
|
1884
|
+
constructor(options, git) {
|
|
1885
|
+
super(serviceTypeSchema.Enum.GitTag, options);
|
|
1886
|
+
this.git = git;
|
|
1879
1887
|
}
|
|
1880
1888
|
/**
|
|
1881
|
-
*
|
|
1882
|
-
*
|
|
1883
|
-
* @todo maybe add more options
|
|
1884
|
-
* @see https://git-scm.com/docs/git-reset
|
|
1889
|
+
* Creates a new tag
|
|
1885
1890
|
*
|
|
1886
|
-
* @
|
|
1887
|
-
* @param mode Modifies the working tree depending on given mode
|
|
1888
|
-
* @param commit Resets the current branch head to this commit / tag
|
|
1891
|
+
* @see https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---annotate
|
|
1889
1892
|
*/
|
|
1890
|
-
async
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
+
async create(props) {
|
|
1894
|
+
createGitTagSchema.parse(props);
|
|
1895
|
+
const id = uuid();
|
|
1896
|
+
let args = ["tag", "--annotate", id];
|
|
1897
|
+
if (props.hash) {
|
|
1898
|
+
args = [...args, props.hash];
|
|
1899
|
+
}
|
|
1900
|
+
args = [...args, "-m", props.message];
|
|
1901
|
+
await this.git(props.path, args);
|
|
1902
|
+
const tag = await this.read({ path: props.path, id });
|
|
1903
|
+
return tag;
|
|
1893
1904
|
}
|
|
1894
1905
|
/**
|
|
1895
|
-
*
|
|
1896
|
-
*
|
|
1897
|
-
* @see https://git-scm.com/docs/git-restore/
|
|
1898
|
-
*
|
|
1899
|
-
* @todo It's probably a good idea to not use restore
|
|
1900
|
-
* for a use case where someone just wants to have a look
|
|
1901
|
-
* and maybe copy something from a deleted file.
|
|
1902
|
-
* We should use `checkout` without `add .` and `commit` for that
|
|
1906
|
+
* Returns a tag by ID
|
|
1903
1907
|
*
|
|
1904
|
-
*
|
|
1905
|
-
* @param source Git commit SHA or tag name to restore to
|
|
1906
|
-
* @param files Files to restore
|
|
1908
|
+
* Internally uses list() but only returns the tag with matching ID.
|
|
1907
1909
|
*/
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1910
|
+
async read(props) {
|
|
1911
|
+
readGitTagSchema.parse(props);
|
|
1912
|
+
const tags = await this.list({ path: props.path });
|
|
1913
|
+
const tag = tags.list.find((tag2) => {
|
|
1914
|
+
return tag2.id === props.id;
|
|
1915
|
+
});
|
|
1916
|
+
if (!tag) {
|
|
1917
|
+
throw new GitError(
|
|
1918
|
+
`Provided tag with UUID "${props.id}" did not match any known tags`
|
|
1919
|
+
);
|
|
1920
|
+
}
|
|
1921
|
+
return tag;
|
|
1922
|
+
}
|
|
1916
1923
|
/**
|
|
1917
|
-
*
|
|
1918
|
-
*
|
|
1919
|
-
* @see https://www.git-scm.com/docs/git-fetch
|
|
1924
|
+
* Updating a git tag is not supported.
|
|
1925
|
+
* Please delete the old and create a new one
|
|
1920
1926
|
*
|
|
1921
|
-
* @
|
|
1927
|
+
* @see https://git-scm.com/docs/git-tag#_on_re_tagging
|
|
1922
1928
|
*/
|
|
1923
|
-
async
|
|
1924
|
-
|
|
1925
|
-
|
|
1929
|
+
async update() {
|
|
1930
|
+
throw new Error(
|
|
1931
|
+
"Updating a git tag is not supported. Please delete the old and create a new one"
|
|
1932
|
+
);
|
|
1926
1933
|
}
|
|
1927
1934
|
/**
|
|
1928
|
-
*
|
|
1935
|
+
* Deletes a tag
|
|
1929
1936
|
*
|
|
1930
|
-
* @see https://git-scm.com/docs/git-
|
|
1937
|
+
* @see https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---delete
|
|
1931
1938
|
*
|
|
1932
|
-
* @param path
|
|
1939
|
+
* @param path Path to the repository
|
|
1940
|
+
* @param id UUID of the tag to delete
|
|
1933
1941
|
*/
|
|
1934
|
-
async
|
|
1935
|
-
|
|
1936
|
-
|
|
1942
|
+
async delete(props) {
|
|
1943
|
+
deleteGitTagSchema.parse(props);
|
|
1944
|
+
const args = ["tag", "--delete", props.id];
|
|
1945
|
+
await this.git(props.path, args);
|
|
1937
1946
|
}
|
|
1938
1947
|
/**
|
|
1939
|
-
*
|
|
1948
|
+
* Gets all local tags or filter them by pattern
|
|
1940
1949
|
*
|
|
1941
|
-
*
|
|
1950
|
+
* They are sorted by authordate of the commit, not the timestamp the tag is created.
|
|
1951
|
+
* This ensures tags are sorted correctly in the timeline of their commits.
|
|
1942
1952
|
*
|
|
1943
|
-
* @
|
|
1953
|
+
* @see https://git-scm.com/docs/git-tag#Documentation/git-tag.txt---list
|
|
1944
1954
|
*/
|
|
1945
|
-
async
|
|
1946
|
-
|
|
1955
|
+
async list(props) {
|
|
1956
|
+
listGitTagsSchema.parse(props);
|
|
1957
|
+
let args = ["tag", "--list"];
|
|
1958
|
+
args = [
|
|
1959
|
+
...args,
|
|
1960
|
+
"--sort=-*authordate",
|
|
1961
|
+
"--format=%(refname:short)|%(subject)|%(*authorname)|%(*authoremail)|%(*authordate:unix)"
|
|
1962
|
+
];
|
|
1963
|
+
const result = await this.git(props.path, args);
|
|
1964
|
+
const noEmptyLinesArr = result.stdout.split(EOL).filter((line) => {
|
|
1965
|
+
return line.trim() !== "";
|
|
1966
|
+
});
|
|
1967
|
+
const lineObjArr = noEmptyLinesArr.map((line) => {
|
|
1968
|
+
const lineArray = line.split("|");
|
|
1969
|
+
return {
|
|
1970
|
+
id: lineArray[0],
|
|
1971
|
+
message: lineArray[1],
|
|
1972
|
+
author: {
|
|
1973
|
+
name: lineArray[2],
|
|
1974
|
+
email: lineArray[3]
|
|
1975
|
+
},
|
|
1976
|
+
timestamp: parseInt(lineArray[4] || "")
|
|
1977
|
+
};
|
|
1978
|
+
});
|
|
1979
|
+
const gitTags = lineObjArr.filter(this.isGitTag.bind(this));
|
|
1980
|
+
return {
|
|
1981
|
+
total: gitTags.length,
|
|
1982
|
+
limit: 0,
|
|
1983
|
+
offset: 0,
|
|
1984
|
+
list: gitTags
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
/**
|
|
1988
|
+
* Returns the total number of tags inside given repository
|
|
1989
|
+
*
|
|
1990
|
+
* Internally uses list(), so do not use count()
|
|
1991
|
+
* in conjuncion with it to avoid multiple git calls.
|
|
1992
|
+
*
|
|
1993
|
+
* @param path Path to the repository
|
|
1994
|
+
*/
|
|
1995
|
+
async count(props) {
|
|
1996
|
+
countGitTagsSchema.parse(props);
|
|
1997
|
+
const gitTags = await this.list({ path: props.path });
|
|
1998
|
+
return gitTags.total;
|
|
1999
|
+
}
|
|
2000
|
+
/**
|
|
2001
|
+
* Type guard for GitTag
|
|
2002
|
+
*
|
|
2003
|
+
* @param obj The object to check
|
|
2004
|
+
*/
|
|
2005
|
+
isGitTag(obj) {
|
|
2006
|
+
return gitTagSchema.safeParse(obj).success;
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
|
|
2010
|
+
// src/service/GitService.ts
|
|
2011
|
+
var GitService = class {
|
|
2012
|
+
version;
|
|
2013
|
+
gitPath;
|
|
2014
|
+
queue;
|
|
2015
|
+
gitTagService;
|
|
2016
|
+
userService;
|
|
2017
|
+
constructor(options, userService) {
|
|
2018
|
+
this.version = null;
|
|
2019
|
+
this.gitPath = null;
|
|
2020
|
+
this.queue = new PQueue({
|
|
2021
|
+
concurrency: 1
|
|
2022
|
+
// No concurrency because git operations are sequencial
|
|
2023
|
+
});
|
|
2024
|
+
this.gitTagService = new GitTagService(options, this.git);
|
|
2025
|
+
this.userService = userService;
|
|
2026
|
+
this.updateVersion();
|
|
2027
|
+
this.updateGitPath();
|
|
2028
|
+
}
|
|
2029
|
+
/**
|
|
2030
|
+
* CRUD methods to work with git tags
|
|
2031
|
+
*/
|
|
2032
|
+
get tags() {
|
|
2033
|
+
return this.gitTagService;
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Create an empty Git repository or reinitialize an existing one
|
|
2037
|
+
*
|
|
2038
|
+
* @see https://git-scm.com/docs/git-init
|
|
2039
|
+
*
|
|
2040
|
+
* @param path Path to initialize in. Fails if path does not exist
|
|
2041
|
+
* @param options Options specific to the init operation
|
|
2042
|
+
*/
|
|
2043
|
+
async init(path, options) {
|
|
2044
|
+
let args = ["init"];
|
|
2045
|
+
if (options?.initialBranch) {
|
|
2046
|
+
args = [...args, `--initial-branch=${options.initialBranch}`];
|
|
2047
|
+
}
|
|
2048
|
+
await this.git(path, args);
|
|
2049
|
+
await this.setLocalConfig(path);
|
|
2050
|
+
await this.installLfs(path);
|
|
2051
|
+
}
|
|
2052
|
+
/**
|
|
2053
|
+
* Clone a repository into a directory
|
|
2054
|
+
*
|
|
2055
|
+
* @see https://git-scm.com/docs/git-clone
|
|
2056
|
+
*
|
|
2057
|
+
* @todo Implement progress callback / events
|
|
2058
|
+
*
|
|
2059
|
+
* @param url The remote repository URL to clone from
|
|
2060
|
+
* @param path The destination path for the cloned repository.
|
|
2061
|
+
* Which is only working if the directory is existing and empty.
|
|
2062
|
+
* @param options Options specific to the clone operation
|
|
2063
|
+
*/
|
|
2064
|
+
async clone(url, path, options) {
|
|
2065
|
+
let args = ["clone", "--progress"];
|
|
2066
|
+
if (options?.branch) {
|
|
2067
|
+
args = [...args, "--branch", options.branch];
|
|
2068
|
+
}
|
|
2069
|
+
if (options?.depth) {
|
|
2070
|
+
args = [...args, "--depth", options.depth.toString()];
|
|
2071
|
+
}
|
|
2072
|
+
if (options?.singleBranch === true) {
|
|
2073
|
+
args = [...args, "--single-branch"];
|
|
2074
|
+
}
|
|
2075
|
+
await this.git("", [...args, url, path]);
|
|
2076
|
+
await this.setLocalConfig(path);
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* Add file contents to the index
|
|
2080
|
+
*
|
|
2081
|
+
* @see https://git-scm.com/docs/git-add
|
|
2082
|
+
*
|
|
2083
|
+
* @param path Path to the repository
|
|
2084
|
+
* @param files Files to add
|
|
2085
|
+
*/
|
|
2086
|
+
async add(path, files2) {
|
|
2087
|
+
const args = ["add", "--", ...files2];
|
|
2088
|
+
await this.git(path, args);
|
|
2089
|
+
}
|
|
2090
|
+
branches = {
|
|
2091
|
+
/**
|
|
2092
|
+
* List branches
|
|
2093
|
+
*
|
|
2094
|
+
* @see https://www.git-scm.com/docs/git-branch
|
|
2095
|
+
*
|
|
2096
|
+
* @param path Path to the repository
|
|
2097
|
+
*/
|
|
2098
|
+
list: async (path) => {
|
|
2099
|
+
const args = ["branch", "--list", "--all"];
|
|
2100
|
+
const result = await this.git(path, args);
|
|
2101
|
+
const normalizedLinesArr = result.stdout.split(EOL2).filter((line) => {
|
|
2102
|
+
return line.trim() !== "";
|
|
2103
|
+
}).map((line) => {
|
|
2104
|
+
return line.trim().replace("* ", "");
|
|
2105
|
+
});
|
|
2106
|
+
const local = [];
|
|
2107
|
+
const remote = [];
|
|
2108
|
+
normalizedLinesArr.forEach((line) => {
|
|
2109
|
+
if (line.startsWith("remotes/")) {
|
|
2110
|
+
remote.push(line.replace("remotes/", ""));
|
|
2111
|
+
} else {
|
|
2112
|
+
local.push(line);
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
return {
|
|
2116
|
+
local,
|
|
2117
|
+
remote
|
|
2118
|
+
};
|
|
2119
|
+
},
|
|
2120
|
+
/**
|
|
2121
|
+
* Returns the name of the current branch. In detached HEAD state, an empty string is returned.
|
|
2122
|
+
*
|
|
2123
|
+
* @see https://www.git-scm.com/docs/git-branch#Documentation/git-branch.txt---show-current
|
|
2124
|
+
*
|
|
2125
|
+
* @param path Path to the repository
|
|
2126
|
+
*/
|
|
2127
|
+
current: async (path) => {
|
|
2128
|
+
const args = ["branch", "--show-current"];
|
|
2129
|
+
const result = await this.git(path, args);
|
|
2130
|
+
return result.stdout.trim();
|
|
2131
|
+
},
|
|
2132
|
+
/**
|
|
2133
|
+
* Switch branches
|
|
2134
|
+
*
|
|
2135
|
+
* @see https://git-scm.com/docs/git-switch/
|
|
2136
|
+
*
|
|
2137
|
+
* @param path Path to the repository
|
|
2138
|
+
* @param branch Name of the branch to switch to
|
|
2139
|
+
* @param options Options specific to the switch operation
|
|
2140
|
+
*/
|
|
2141
|
+
switch: async (path, branch, options) => {
|
|
2142
|
+
await this.checkBranchOrTagName(path, branch);
|
|
2143
|
+
let args = ["switch"];
|
|
2144
|
+
if (options?.isNew === true) {
|
|
2145
|
+
args = [...args, "--create", branch];
|
|
2146
|
+
} else {
|
|
2147
|
+
args = [...args, branch];
|
|
2148
|
+
}
|
|
2149
|
+
await this.git(path, args);
|
|
2150
|
+
}
|
|
2151
|
+
};
|
|
2152
|
+
remotes = {
|
|
2153
|
+
/**
|
|
2154
|
+
* Returns a list of currently tracked remotes
|
|
2155
|
+
*
|
|
2156
|
+
* @see https://git-scm.com/docs/git-remote
|
|
2157
|
+
*
|
|
2158
|
+
* @param path Path to the repository
|
|
2159
|
+
*/
|
|
2160
|
+
list: async (path) => {
|
|
2161
|
+
const args = ["remote"];
|
|
2162
|
+
const result = await this.git(path, args);
|
|
2163
|
+
const normalizedLinesArr = result.stdout.split(EOL2).filter((line) => {
|
|
2164
|
+
return line.trim() !== "";
|
|
2165
|
+
});
|
|
2166
|
+
return normalizedLinesArr;
|
|
2167
|
+
},
|
|
2168
|
+
/**
|
|
2169
|
+
* Returns true if the `origin` remote exists, otherwise false
|
|
2170
|
+
*
|
|
2171
|
+
* @param path Path to the repository
|
|
2172
|
+
*/
|
|
2173
|
+
hasOrigin: async (path) => {
|
|
2174
|
+
const remotes = await this.remotes.list(path);
|
|
2175
|
+
if (remotes.includes("origin")) {
|
|
2176
|
+
return true;
|
|
2177
|
+
}
|
|
2178
|
+
return false;
|
|
2179
|
+
},
|
|
2180
|
+
/**
|
|
2181
|
+
* Adds the `origin` remote with given URL
|
|
2182
|
+
*
|
|
2183
|
+
* Throws if `origin` remote is added already.
|
|
2184
|
+
*
|
|
2185
|
+
* @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emaddem
|
|
2186
|
+
*
|
|
2187
|
+
* @param path Path to the repository
|
|
2188
|
+
*/
|
|
2189
|
+
addOrigin: async (path, url) => {
|
|
2190
|
+
const args = ["remote", "add", "origin", url];
|
|
2191
|
+
await this.git(path, args);
|
|
2192
|
+
},
|
|
2193
|
+
/**
|
|
2194
|
+
* Returns the current `origin` remote URL
|
|
2195
|
+
*
|
|
2196
|
+
* Throws if no `origin` remote is added yet.
|
|
2197
|
+
*
|
|
2198
|
+
* @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emget-urlem
|
|
2199
|
+
*
|
|
2200
|
+
* @param path Path to the repository
|
|
2201
|
+
*/
|
|
2202
|
+
getOriginUrl: async (path) => {
|
|
2203
|
+
const args = ["remote", "get-url", "origin"];
|
|
2204
|
+
const result = (await this.git(path, args)).stdout.trim();
|
|
2205
|
+
return result.length === 0 ? null : result;
|
|
2206
|
+
},
|
|
2207
|
+
/**
|
|
2208
|
+
* Sets the current `origin` remote URL
|
|
2209
|
+
*
|
|
2210
|
+
* Throws if no `origin` remote is added yet.
|
|
2211
|
+
*
|
|
2212
|
+
* @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emset-urlem
|
|
2213
|
+
*
|
|
2214
|
+
* @param path Path to the repository
|
|
2215
|
+
*/
|
|
2216
|
+
setOriginUrl: async (path, url) => {
|
|
2217
|
+
const args = ["remote", "set-url", "origin", url];
|
|
2218
|
+
await this.git(path, args);
|
|
2219
|
+
}
|
|
2220
|
+
};
|
|
2221
|
+
/**
|
|
2222
|
+
* Reset current HEAD to the specified state
|
|
2223
|
+
*
|
|
2224
|
+
* @todo maybe add more options
|
|
2225
|
+
* @see https://git-scm.com/docs/git-reset
|
|
2226
|
+
*
|
|
2227
|
+
* @param path Path to the repository
|
|
2228
|
+
* @param mode Modifies the working tree depending on given mode
|
|
2229
|
+
* @param commit Resets the current branch head to this commit / tag
|
|
2230
|
+
*/
|
|
2231
|
+
async reset(path, mode, commit) {
|
|
2232
|
+
const args = ["reset", `--${mode}`, commit];
|
|
2233
|
+
await this.git(path, args);
|
|
2234
|
+
}
|
|
2235
|
+
/**
|
|
2236
|
+
* Restore working tree files
|
|
2237
|
+
*
|
|
2238
|
+
* @see https://git-scm.com/docs/git-restore/
|
|
2239
|
+
*
|
|
2240
|
+
* @todo It's probably a good idea to not use restore
|
|
2241
|
+
* for a use case where someone just wants to have a look
|
|
2242
|
+
* and maybe copy something from a deleted file.
|
|
2243
|
+
* We should use `checkout` without `add .` and `commit` for that
|
|
2244
|
+
*
|
|
2245
|
+
* @param path Path to the repository
|
|
2246
|
+
* @param source Git commit SHA or tag name to restore to
|
|
2247
|
+
* @param files Files to restore
|
|
2248
|
+
*/
|
|
2249
|
+
// public async restore(
|
|
2250
|
+
// path: string,
|
|
2251
|
+
// source: string,
|
|
2252
|
+
// files: string[]
|
|
2253
|
+
// ): Promise<void> {
|
|
2254
|
+
// const args = ['restore', `--source=${source}`, ...files];
|
|
2255
|
+
// await this.git(path, args);
|
|
2256
|
+
// }
|
|
2257
|
+
/**
|
|
2258
|
+
* Download objects and refs from remote `origin`
|
|
2259
|
+
*
|
|
2260
|
+
* @see https://www.git-scm.com/docs/git-fetch
|
|
2261
|
+
*
|
|
2262
|
+
* @param path Path to the repository
|
|
2263
|
+
*/
|
|
2264
|
+
async fetch(path) {
|
|
2265
|
+
const args = ["fetch"];
|
|
2266
|
+
await this.git(path, args);
|
|
2267
|
+
}
|
|
2268
|
+
/**
|
|
2269
|
+
* Fetch from and integrate (rebase or merge) with a local branch
|
|
2270
|
+
*
|
|
2271
|
+
* @see https://git-scm.com/docs/git-pull
|
|
2272
|
+
*
|
|
2273
|
+
* @param path Path to the repository
|
|
2274
|
+
*/
|
|
2275
|
+
async pull(path) {
|
|
2276
|
+
const args = ["pull"];
|
|
2277
|
+
await this.git(path, args);
|
|
2278
|
+
}
|
|
2279
|
+
/**
|
|
2280
|
+
* Update remote refs along with associated objects to remote `origin`
|
|
2281
|
+
*
|
|
2282
|
+
* @see https://git-scm.com/docs/git-push
|
|
2283
|
+
*
|
|
2284
|
+
* @param path Path to the repository
|
|
2285
|
+
*/
|
|
2286
|
+
async push(path, options) {
|
|
2287
|
+
let args = ["push", "origin"];
|
|
1947
2288
|
if (options?.all === true) {
|
|
1948
2289
|
args = [...args, "--all"];
|
|
1949
2290
|
}
|
|
@@ -2010,8 +2351,8 @@ var GitService2 = class {
|
|
|
2010
2351
|
name: lineArray[2],
|
|
2011
2352
|
email: lineArray[3]
|
|
2012
2353
|
},
|
|
2013
|
-
timestamp: parseInt(lineArray[4]),
|
|
2014
|
-
tag: this.refNameToTagName(lineArray[5])
|
|
2354
|
+
timestamp: parseInt(lineArray[4] || ""),
|
|
2355
|
+
tag: this.refNameToTagName(lineArray[5] || "")
|
|
2015
2356
|
};
|
|
2016
2357
|
});
|
|
2017
2358
|
return lineObjArr.filter(this.isGitCommit.bind(this));
|
|
@@ -2144,475 +2485,118 @@ var GitService2 = class {
|
|
|
2144
2485
|
await this.git(path, autoSetupRemoteArgs);
|
|
2145
2486
|
}
|
|
2146
2487
|
/**
|
|
2147
|
-
* Type guard for GitCommit
|
|
2148
|
-
*
|
|
2149
|
-
* @param obj The object to check
|
|
2150
|
-
*/
|
|
2151
|
-
isGitCommit(obj) {
|
|
2152
|
-
return gitCommitSchema.safeParse(obj).success;
|
|
2153
|
-
}
|
|
2154
|
-
/**
|
|
2155
|
-
* Wraps the execution of any git command
|
|
2156
|
-
* to use a FIFO queue for sequential processing
|
|
2157
|
-
*
|
|
2158
|
-
* @param path Path to the repository
|
|
2159
|
-
* @param args Arguments to append after the `git` command
|
|
2160
|
-
*/
|
|
2161
|
-
async git(path, args) {
|
|
2162
|
-
const result = await this.queue.add(
|
|
2163
|
-
() => GitProcess.exec(args, path, {
|
|
2164
|
-
env: {
|
|
2165
|
-
// @todo Nasty stuff - remove after update to dugite with git > v2.45.2 once available
|
|
2166
|
-
// @see https://github.com/git-lfs/git-lfs/issues/5749
|
|
2167
|
-
GIT_CLONE_PROTECTION_ACTIVE: "false"
|
|
2168
|
-
}
|
|
2169
|
-
})
|
|
2170
|
-
);
|
|
2171
|
-
if (!result) {
|
|
2172
|
-
throw new GitError(
|
|
2173
|
-
`Git ${this.version} (${this.gitPath}) command "git ${args.join(
|
|
2174
|
-
" "
|
|
2175
|
-
)}" failed to return a result`
|
|
2176
|
-
);
|
|
2177
|
-
}
|
|
2178
|
-
if (result.exitCode !== 0) {
|
|
2179
|
-
throw new GitError(
|
|
2180
|
-
`Git ${this.version} (${this.gitPath}) command "git ${args.join(
|
|
2181
|
-
" "
|
|
2182
|
-
)}" failed with exit code "${result.exitCode}" and message "${result.stderr}"`
|
|
2183
|
-
);
|
|
2184
|
-
}
|
|
2185
|
-
return result;
|
|
2186
|
-
}
|
|
2187
|
-
};
|
|
2188
|
-
|
|
2189
|
-
// src/service/CollectionService.ts
|
|
2190
|
-
var CollectionService = class extends AbstractCrudService {
|
|
2191
|
-
constructor(options, jsonFileService, gitService) {
|
|
2192
|
-
super(serviceTypeSchema.Enum.Collection, options);
|
|
2193
|
-
this.jsonFileService = jsonFileService;
|
|
2194
|
-
this.gitService = gitService;
|
|
2195
|
-
}
|
|
2196
|
-
/**
|
|
2197
|
-
* Creates a new Collection
|
|
2198
|
-
*/
|
|
2199
|
-
async create(props) {
|
|
2200
|
-
createCollectionSchema.parse(props);
|
|
2201
|
-
const id = uuid();
|
|
2202
|
-
const projectPath = pathTo.project(props.projectId);
|
|
2203
|
-
const collectionPath = pathTo.collection(props.projectId, id);
|
|
2204
|
-
const collectionFilePath = pathTo.collectionFile(props.projectId, id);
|
|
2205
|
-
const collectionFile = {
|
|
2206
|
-
...props,
|
|
2207
|
-
objectType: "collection",
|
|
2208
|
-
id,
|
|
2209
|
-
slug: {
|
|
2210
|
-
singular: slug(props.slug.singular),
|
|
2211
|
-
plural: slug(props.slug.plural)
|
|
2212
|
-
},
|
|
2213
|
-
created: currentTimestamp(),
|
|
2214
|
-
updated: null
|
|
2215
|
-
};
|
|
2216
|
-
await Fs4.ensureDir(collectionPath);
|
|
2217
|
-
await this.jsonFileService.create(
|
|
2218
|
-
collectionFile,
|
|
2219
|
-
collectionFilePath,
|
|
2220
|
-
collectionFileSchema
|
|
2221
|
-
);
|
|
2222
|
-
await this.gitService.add(projectPath, [collectionFilePath]);
|
|
2223
|
-
await this.gitService.commit(projectPath, this.gitMessage.create);
|
|
2224
|
-
return collectionFile;
|
|
2225
|
-
}
|
|
2226
|
-
/**
|
|
2227
|
-
* Returns a Collection by ID
|
|
2228
|
-
*/
|
|
2229
|
-
async read(props) {
|
|
2230
|
-
readCollectionSchema.parse(props);
|
|
2231
|
-
const collection = await this.jsonFileService.read(
|
|
2232
|
-
pathTo.collectionFile(props.projectId, props.id),
|
|
2233
|
-
collectionFileSchema
|
|
2234
|
-
);
|
|
2235
|
-
return collection;
|
|
2236
|
-
}
|
|
2237
|
-
/**
|
|
2238
|
-
* Updates given Collection
|
|
2239
|
-
*
|
|
2240
|
-
* @todo finish implementing checks for FieldDefinitions and extract methods
|
|
2241
|
-
*
|
|
2242
|
-
* @param projectId Project ID of the collection to update
|
|
2243
|
-
* @param collection Collection to write to disk
|
|
2244
|
-
* @returns An object containing information about the actions needed to be taken,
|
|
2245
|
-
* before given update can be executed or void if the update was executed successfully
|
|
2246
|
-
*/
|
|
2247
|
-
async update(props) {
|
|
2248
|
-
updateCollectionSchema.parse(props);
|
|
2249
|
-
const projectPath = pathTo.project(props.projectId);
|
|
2250
|
-
const collectionFilePath = pathTo.collectionFile(props.projectId, props.id);
|
|
2251
|
-
const prevCollectionFile = await this.read(props);
|
|
2252
|
-
const collectionFile = {
|
|
2253
|
-
...prevCollectionFile,
|
|
2254
|
-
...props,
|
|
2255
|
-
updated: currentTimestamp()
|
|
2256
|
-
};
|
|
2257
|
-
await this.jsonFileService.update(
|
|
2258
|
-
collectionFile,
|
|
2259
|
-
collectionFilePath,
|
|
2260
|
-
collectionFileSchema
|
|
2261
|
-
);
|
|
2262
|
-
await this.gitService.add(projectPath, [collectionFilePath]);
|
|
2263
|
-
await this.gitService.commit(projectPath, this.gitMessage.update);
|
|
2264
|
-
return collectionFile;
|
|
2265
|
-
}
|
|
2266
|
-
/**
|
|
2267
|
-
* Deletes given Collection (folder), including it's items
|
|
2268
|
-
*
|
|
2269
|
-
* The Fields that Collection used are not deleted.
|
|
2270
|
-
*/
|
|
2271
|
-
async delete(props) {
|
|
2272
|
-
deleteCollectionSchema.parse(props);
|
|
2273
|
-
const projectPath = pathTo.project(props.projectId);
|
|
2274
|
-
const collectionPath = pathTo.collection(props.projectId, props.id);
|
|
2275
|
-
await Fs4.remove(collectionPath);
|
|
2276
|
-
await this.gitService.add(projectPath, [collectionPath]);
|
|
2277
|
-
await this.gitService.commit(projectPath, this.gitMessage.delete);
|
|
2278
|
-
}
|
|
2279
|
-
async list(props) {
|
|
2280
|
-
listCollectionsSchema.parse(props);
|
|
2281
|
-
const offset = props.offset || 0;
|
|
2282
|
-
const limit = props.limit || 15;
|
|
2283
|
-
const collectionReferences = await this.listReferences(
|
|
2284
|
-
objectTypeSchema.Enum.collection,
|
|
2285
|
-
props.projectId
|
|
2286
|
-
);
|
|
2287
|
-
const partialCollectionReferences = collectionReferences.slice(
|
|
2288
|
-
offset,
|
|
2289
|
-
limit
|
|
2290
|
-
);
|
|
2291
|
-
const collections = await returnResolved(
|
|
2292
|
-
partialCollectionReferences.map((reference) => {
|
|
2293
|
-
return this.read({
|
|
2294
|
-
projectId: props.projectId,
|
|
2295
|
-
id: reference.id
|
|
2296
|
-
});
|
|
2297
|
-
})
|
|
2298
|
-
);
|
|
2299
|
-
return {
|
|
2300
|
-
total: collectionReferences.length,
|
|
2301
|
-
limit,
|
|
2302
|
-
offset,
|
|
2303
|
-
list: collections
|
|
2304
|
-
};
|
|
2305
|
-
}
|
|
2306
|
-
async count(props) {
|
|
2307
|
-
countCollectionsSchema.parse(props);
|
|
2308
|
-
const count = (await this.listReferences(
|
|
2309
|
-
objectTypeSchema.Enum.collection,
|
|
2310
|
-
props.projectId
|
|
2311
|
-
)).length;
|
|
2312
|
-
return count;
|
|
2313
|
-
}
|
|
2314
|
-
/**
|
|
2315
|
-
* Checks if given object is of type Collection
|
|
2316
|
-
*/
|
|
2317
|
-
isCollection(obj) {
|
|
2318
|
-
return collectionFileSchema.safeParse(obj).success;
|
|
2319
|
-
}
|
|
2320
|
-
};
|
|
2321
|
-
|
|
2322
|
-
// src/service/EntryService.ts
|
|
2323
|
-
import Fs5 from "fs-extra";
|
|
2324
|
-
var EntryService = class extends AbstractCrudService {
|
|
2325
|
-
// private sharedValueService: SharedValueService;
|
|
2326
|
-
constructor(options, jsonFileService, gitService, collectionService, assetService) {
|
|
2327
|
-
super(serviceTypeSchema.Enum.Entry, options);
|
|
2328
|
-
this.jsonFileService = jsonFileService;
|
|
2329
|
-
this.gitService = gitService;
|
|
2330
|
-
this.collectionService = collectionService;
|
|
2331
|
-
this.assetService = assetService;
|
|
2332
|
-
}
|
|
2333
|
-
/**
|
|
2334
|
-
* Creates a new Entry for given Collection
|
|
2335
|
-
*/
|
|
2336
|
-
async create(props) {
|
|
2337
|
-
createEntrySchema.parse(props);
|
|
2338
|
-
const id = uuid();
|
|
2339
|
-
const projectPath = pathTo.project(props.projectId);
|
|
2340
|
-
const entryFilePath = pathTo.entryFile(
|
|
2341
|
-
props.projectId,
|
|
2342
|
-
props.collectionId,
|
|
2343
|
-
id
|
|
2344
|
-
);
|
|
2345
|
-
const collection = await this.collectionService.read({
|
|
2346
|
-
projectId: props.projectId,
|
|
2347
|
-
id: props.collectionId
|
|
2348
|
-
});
|
|
2349
|
-
const entryFile = {
|
|
2350
|
-
objectType: "entry",
|
|
2351
|
-
id,
|
|
2352
|
-
values: props.values,
|
|
2353
|
-
created: currentTimestamp(),
|
|
2354
|
-
updated: null
|
|
2355
|
-
};
|
|
2356
|
-
const entry = await this.toEntry({
|
|
2357
|
-
projectId: props.projectId,
|
|
2358
|
-
collectionId: props.collectionId,
|
|
2359
|
-
entryFile
|
|
2360
|
-
});
|
|
2361
|
-
this.validateValues({
|
|
2362
|
-
collectionId: props.collectionId,
|
|
2363
|
-
valueDefinitions: collection.valueDefinitions,
|
|
2364
|
-
values: entry.values
|
|
2365
|
-
});
|
|
2366
|
-
await this.jsonFileService.create(
|
|
2367
|
-
entryFile,
|
|
2368
|
-
entryFilePath,
|
|
2369
|
-
entryFileSchema
|
|
2370
|
-
);
|
|
2371
|
-
await this.gitService.add(projectPath, [entryFilePath]);
|
|
2372
|
-
await this.gitService.commit(projectPath, this.gitMessage.create);
|
|
2373
|
-
return entry;
|
|
2374
|
-
}
|
|
2375
|
-
/**
|
|
2376
|
-
* Returns an Entry from given Collection by ID and language
|
|
2377
|
-
*/
|
|
2378
|
-
async read(props) {
|
|
2379
|
-
readEntrySchema.parse(props);
|
|
2380
|
-
const entryFile = await this.jsonFileService.read(
|
|
2381
|
-
pathTo.entryFile(props.projectId, props.collectionId, props.id),
|
|
2382
|
-
entryFileSchema
|
|
2383
|
-
);
|
|
2384
|
-
return await this.toEntry({
|
|
2385
|
-
projectId: props.projectId,
|
|
2386
|
-
collectionId: props.collectionId,
|
|
2387
|
-
entryFile
|
|
2388
|
-
});
|
|
2389
|
-
}
|
|
2390
|
-
/**
|
|
2391
|
-
* Updates an Entry of given Collection with new Values and shared Values
|
|
2392
|
-
*/
|
|
2393
|
-
async update(props) {
|
|
2394
|
-
updateEntrySchema.parse(props);
|
|
2395
|
-
const projectPath = pathTo.project(props.projectId);
|
|
2396
|
-
const entryFilePath = pathTo.entryFile(
|
|
2397
|
-
props.projectId,
|
|
2398
|
-
props.collectionId,
|
|
2399
|
-
props.id
|
|
2400
|
-
);
|
|
2401
|
-
const collection = await this.collectionService.read({
|
|
2402
|
-
projectId: props.projectId,
|
|
2403
|
-
id: props.collectionId
|
|
2404
|
-
});
|
|
2405
|
-
const prevEntryFile = await this.read({
|
|
2406
|
-
projectId: props.projectId,
|
|
2407
|
-
collectionId: props.collectionId,
|
|
2408
|
-
id: props.id
|
|
2409
|
-
});
|
|
2410
|
-
const entryFile = {
|
|
2411
|
-
...prevEntryFile,
|
|
2412
|
-
values: props.values,
|
|
2413
|
-
updated: currentTimestamp()
|
|
2414
|
-
};
|
|
2415
|
-
const entry = await this.toEntry({
|
|
2416
|
-
projectId: props.projectId,
|
|
2417
|
-
collectionId: props.collectionId,
|
|
2418
|
-
entryFile
|
|
2419
|
-
});
|
|
2420
|
-
this.validateValues({
|
|
2421
|
-
collectionId: props.collectionId,
|
|
2422
|
-
valueDefinitions: collection.valueDefinitions,
|
|
2423
|
-
values: entry.values
|
|
2424
|
-
});
|
|
2425
|
-
await this.jsonFileService.update(
|
|
2426
|
-
entryFile,
|
|
2427
|
-
entryFilePath,
|
|
2428
|
-
entryFileSchema
|
|
2429
|
-
);
|
|
2430
|
-
await this.gitService.add(projectPath, [entryFilePath]);
|
|
2431
|
-
await this.gitService.commit(projectPath, this.gitMessage.update);
|
|
2432
|
-
return entry;
|
|
2433
|
-
}
|
|
2434
|
-
/**
|
|
2435
|
-
* Deletes given Entry from it's Collection
|
|
2436
|
-
*/
|
|
2437
|
-
async delete(props) {
|
|
2438
|
-
deleteEntrySchema.parse(props);
|
|
2439
|
-
const projectPath = pathTo.project(props.projectId);
|
|
2440
|
-
const entryFilePath = pathTo.entryFile(
|
|
2441
|
-
props.projectId,
|
|
2442
|
-
props.collectionId,
|
|
2443
|
-
props.id
|
|
2444
|
-
);
|
|
2445
|
-
await Fs5.remove(entryFilePath);
|
|
2446
|
-
await this.gitService.add(projectPath, [entryFilePath]);
|
|
2447
|
-
await this.gitService.commit(projectPath, this.gitMessage.delete);
|
|
2448
|
-
}
|
|
2449
|
-
async list(props) {
|
|
2450
|
-
listEntriesSchema.parse(props);
|
|
2451
|
-
const offset = props.offset || 0;
|
|
2452
|
-
const limit = props.limit || 15;
|
|
2453
|
-
const entryReferences = await this.listReferences(
|
|
2454
|
-
objectTypeSchema.Enum.entry,
|
|
2455
|
-
props.projectId,
|
|
2456
|
-
props.collectionId
|
|
2457
|
-
);
|
|
2458
|
-
const partialEntryReferences = entryReferences.slice(offset, limit);
|
|
2459
|
-
const entries = await returnResolved(
|
|
2460
|
-
partialEntryReferences.map((reference) => {
|
|
2461
|
-
return this.read({
|
|
2462
|
-
projectId: props.projectId,
|
|
2463
|
-
collectionId: props.collectionId,
|
|
2464
|
-
id: reference.id
|
|
2465
|
-
});
|
|
2466
|
-
})
|
|
2467
|
-
);
|
|
2468
|
-
return {
|
|
2469
|
-
total: entryReferences.length,
|
|
2470
|
-
limit,
|
|
2471
|
-
offset,
|
|
2472
|
-
list: entries
|
|
2473
|
-
};
|
|
2474
|
-
}
|
|
2475
|
-
async count(props) {
|
|
2476
|
-
countEntriesSchema.parse(props);
|
|
2477
|
-
return (await this.listReferences(
|
|
2478
|
-
objectTypeSchema.Enum.entry,
|
|
2479
|
-
props.projectId,
|
|
2480
|
-
props.collectionId
|
|
2481
|
-
)).length;
|
|
2482
|
-
}
|
|
2483
|
-
/**
|
|
2484
|
-
* Checks if given object is of type Entry
|
|
2488
|
+
* Type guard for GitCommit
|
|
2489
|
+
*
|
|
2490
|
+
* @param obj The object to check
|
|
2485
2491
|
*/
|
|
2486
|
-
|
|
2487
|
-
return
|
|
2492
|
+
isGitCommit(obj) {
|
|
2493
|
+
return gitCommitSchema.safeParse(obj).success;
|
|
2488
2494
|
}
|
|
2489
2495
|
/**
|
|
2490
|
-
*
|
|
2496
|
+
* Wraps the execution of any git command
|
|
2497
|
+
* to use a FIFO queue for sequential processing
|
|
2498
|
+
*
|
|
2499
|
+
* @param path Path to the repository
|
|
2500
|
+
* @param args Arguments to append after the `git` command
|
|
2491
2501
|
*/
|
|
2492
|
-
|
|
2493
|
-
const
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
+
async git(path, args) {
|
|
2503
|
+
const result = await this.queue.add(
|
|
2504
|
+
() => GitProcess.exec(args, path, {
|
|
2505
|
+
env: {
|
|
2506
|
+
// @todo Nasty stuff - remove after update to dugite with git > v2.45.2 once available
|
|
2507
|
+
// @see https://github.com/git-lfs/git-lfs/issues/5749
|
|
2508
|
+
GIT_CLONE_PROTECTION_ACTIVE: "false"
|
|
2509
|
+
}
|
|
2510
|
+
})
|
|
2511
|
+
);
|
|
2512
|
+
if (!result) {
|
|
2513
|
+
throw new GitError(
|
|
2514
|
+
`Git ${this.version} (${this.gitPath}) command "git ${args.join(
|
|
2515
|
+
" "
|
|
2516
|
+
)}" failed to return a result`
|
|
2502
2517
|
);
|
|
2503
2518
|
}
|
|
2504
|
-
|
|
2519
|
+
if (result.exitCode !== 0) {
|
|
2520
|
+
throw new GitError(
|
|
2521
|
+
`Git ${this.version} (${this.gitPath}) command "git ${args.join(
|
|
2522
|
+
" "
|
|
2523
|
+
)}" failed with exit code "${result.exitCode}" and message "${result.stderr}"`
|
|
2524
|
+
);
|
|
2525
|
+
}
|
|
2526
|
+
return result;
|
|
2527
|
+
}
|
|
2528
|
+
};
|
|
2529
|
+
|
|
2530
|
+
// src/service/JsonFileService.ts
|
|
2531
|
+
import Fs5 from "fs-extra";
|
|
2532
|
+
var JsonFileService = class extends AbstractCrudService {
|
|
2533
|
+
cache = /* @__PURE__ */ new Map();
|
|
2534
|
+
constructor(options) {
|
|
2535
|
+
super(serviceTypeSchema.Enum.JsonFile, options);
|
|
2505
2536
|
}
|
|
2506
2537
|
/**
|
|
2507
|
-
*
|
|
2538
|
+
* Creates a new file on disk. Fails if path already exists
|
|
2539
|
+
*
|
|
2540
|
+
* @param data Data to write into the file
|
|
2541
|
+
* @param path Path to write the file to
|
|
2542
|
+
* @param schema Schema of the file to validate against
|
|
2543
|
+
* @returns Validated content of the file from disk
|
|
2508
2544
|
*/
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
});
|
|
2516
|
-
const schema = getValueContentSchemaFromDefinition(definition);
|
|
2517
|
-
try {
|
|
2518
|
-
for (const [language, content] of Object.entries(value.content)) {
|
|
2519
|
-
schema.parse(content);
|
|
2520
|
-
}
|
|
2521
|
-
} catch (error) {
|
|
2522
|
-
console.log("Definition:", definition);
|
|
2523
|
-
console.log("Value:", value);
|
|
2524
|
-
throw error;
|
|
2525
|
-
}
|
|
2545
|
+
async create(data, path, schema) {
|
|
2546
|
+
const parsedData = schema.parse(data);
|
|
2547
|
+
const string = this.serialize(parsedData);
|
|
2548
|
+
await Fs5.writeFile(path, string, {
|
|
2549
|
+
flag: "wx",
|
|
2550
|
+
encoding: "utf8"
|
|
2526
2551
|
});
|
|
2552
|
+
this.cache.set(path, parsedData);
|
|
2553
|
+
return parsedData;
|
|
2527
2554
|
}
|
|
2528
2555
|
/**
|
|
2529
|
-
*
|
|
2556
|
+
* Reads the content of a file on disk. Fails if path does not exist
|
|
2557
|
+
*
|
|
2558
|
+
* @param path Path to read the file from
|
|
2559
|
+
* @param schema Schema of the file to validate against
|
|
2560
|
+
* @returns Validated content of the file from disk
|
|
2530
2561
|
*/
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
// resolvedSharedValues: ResolvedSharedValueReference[];
|
|
2535
|
-
// }) {
|
|
2536
|
-
// props.resolvedSharedValues.map((value) => {
|
|
2537
|
-
// const definition = this.getValueDefinitionById({
|
|
2538
|
-
// collectionId: props.collectionId,
|
|
2539
|
-
// valueDefinitions: props.valueDefinitions,
|
|
2540
|
-
// id: value.definitionId,
|
|
2541
|
-
// });
|
|
2542
|
-
// const schema = getValueSchemaFromDefinition(definition);
|
|
2543
|
-
// schema.parse(value.resolved.content);
|
|
2544
|
-
// });
|
|
2545
|
-
// }
|
|
2546
|
-
async resolveValueContentReference(props) {
|
|
2547
|
-
switch (props.valueContentReference.objectType) {
|
|
2548
|
-
case objectTypeSchema.Enum.asset:
|
|
2549
|
-
return await this.assetService.read({
|
|
2550
|
-
projectId: props.projectId,
|
|
2551
|
-
id: props.valueContentReference.id,
|
|
2552
|
-
language: props.valueContentReference.language
|
|
2553
|
-
});
|
|
2554
|
-
case objectTypeSchema.Enum.entry:
|
|
2555
|
-
return await this.read({
|
|
2556
|
-
projectId: props.projectId,
|
|
2557
|
-
collectionId: props.collectionId,
|
|
2558
|
-
id: props.valueContentReference.id
|
|
2559
|
-
});
|
|
2560
|
-
default:
|
|
2561
|
-
throw new Error(
|
|
2562
|
-
// @ts-ignore
|
|
2563
|
-
`Tried to resolve unsupported Value reference "${props.valueContentReference.referenceObjectType}"`
|
|
2564
|
-
);
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
async resolveValueContentReferences(props) {
|
|
2568
|
-
let resolvedContent = {};
|
|
2569
|
-
for (const language in props.valueReference.content) {
|
|
2570
|
-
const referencesOfLanguage = props.valueReference.content[language];
|
|
2571
|
-
if (!referencesOfLanguage) {
|
|
2572
|
-
throw new Error(
|
|
2573
|
-
`Trying to access content references by language "${language}" failed`
|
|
2574
|
-
);
|
|
2575
|
-
}
|
|
2576
|
-
const resolvedReferencesOfLanguage = await Promise.all(
|
|
2577
|
-
referencesOfLanguage.map(async (reference) => {
|
|
2578
|
-
return await this.resolveValueContentReference({
|
|
2579
|
-
projectId: props.projectId,
|
|
2580
|
-
collectionId: props.collectionId,
|
|
2581
|
-
valueContentReference: reference
|
|
2582
|
-
});
|
|
2583
|
-
})
|
|
2584
|
-
);
|
|
2585
|
-
resolvedContent = {
|
|
2586
|
-
...resolvedContent,
|
|
2587
|
-
[language]: resolvedReferencesOfLanguage
|
|
2588
|
-
};
|
|
2562
|
+
async read(path, schema) {
|
|
2563
|
+
if (this.cache.has(path)) {
|
|
2564
|
+
return this.cache.get(path);
|
|
2589
2565
|
}
|
|
2590
|
-
|
|
2566
|
+
const data = await Fs5.readFile(path, {
|
|
2567
|
+
flag: "r",
|
|
2568
|
+
encoding: "utf8"
|
|
2569
|
+
});
|
|
2570
|
+
const json = this.deserialize(data);
|
|
2571
|
+
const parsedData = schema.parse(json);
|
|
2572
|
+
this.cache.set(path, parsedData);
|
|
2573
|
+
return parsedData;
|
|
2591
2574
|
}
|
|
2592
2575
|
/**
|
|
2593
|
-
*
|
|
2576
|
+
* Overwrites an existing file on disk
|
|
2577
|
+
*
|
|
2578
|
+
* @todo Check how to error out if the file does not exist already
|
|
2579
|
+
*
|
|
2580
|
+
* @param data Data to write into the file
|
|
2581
|
+
* @param path Path to the file to overwrite
|
|
2582
|
+
* @param schema Schema of the file to validate against
|
|
2583
|
+
* @returns Validated content of the file from disk
|
|
2594
2584
|
*/
|
|
2595
|
-
async
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
};
|
|
2611
|
-
}
|
|
2612
|
-
return value;
|
|
2613
|
-
})
|
|
2614
|
-
)
|
|
2615
|
-
};
|
|
2585
|
+
async update(data, path, schema) {
|
|
2586
|
+
const parsedData = schema.parse(data);
|
|
2587
|
+
const string = this.serialize(parsedData);
|
|
2588
|
+
await Fs5.writeFile(path, string, {
|
|
2589
|
+
flag: "w",
|
|
2590
|
+
encoding: "utf8"
|
|
2591
|
+
});
|
|
2592
|
+
this.cache.set(path, parsedData);
|
|
2593
|
+
return parsedData;
|
|
2594
|
+
}
|
|
2595
|
+
serialize(data) {
|
|
2596
|
+
return JSON.stringify(data, null, this.options.file.json.indentation);
|
|
2597
|
+
}
|
|
2598
|
+
deserialize(data) {
|
|
2599
|
+
return JSON.parse(data);
|
|
2616
2600
|
}
|
|
2617
2601
|
};
|
|
2618
2602
|
|
|
@@ -2622,47 +2606,14 @@ import Os2 from "os";
|
|
|
2622
2606
|
import Path2 from "path";
|
|
2623
2607
|
import Semver from "semver";
|
|
2624
2608
|
var ProjectService = class extends AbstractCrudService {
|
|
2609
|
+
jsonFileService;
|
|
2610
|
+
userService;
|
|
2611
|
+
gitService;
|
|
2612
|
+
assetService;
|
|
2613
|
+
collectionService;
|
|
2614
|
+
entryService;
|
|
2625
2615
|
constructor(options, jsonFileService, userService, gitService, assetService, collectionService, entryService) {
|
|
2626
2616
|
super(serviceTypeSchema.Enum.Project, options);
|
|
2627
|
-
this.branches = {
|
|
2628
|
-
list: async (props) => {
|
|
2629
|
-
listBranchesProjectSchema.parse(props);
|
|
2630
|
-
const projectPath = pathTo.project(props.id);
|
|
2631
|
-
await this.gitService.fetch(projectPath);
|
|
2632
|
-
return await this.gitService.branches.list(projectPath);
|
|
2633
|
-
},
|
|
2634
|
-
current: async (props) => {
|
|
2635
|
-
currentBranchProjectSchema.parse(props);
|
|
2636
|
-
const projectPath = pathTo.project(props.id);
|
|
2637
|
-
return await this.gitService.branches.current(projectPath);
|
|
2638
|
-
},
|
|
2639
|
-
switch: async (props) => {
|
|
2640
|
-
switchBranchProjectSchema.parse(props);
|
|
2641
|
-
const projectPath = pathTo.project(props.id);
|
|
2642
|
-
return await this.gitService.branches.switch(
|
|
2643
|
-
projectPath,
|
|
2644
|
-
props.branch,
|
|
2645
|
-
props.options
|
|
2646
|
-
);
|
|
2647
|
-
}
|
|
2648
|
-
};
|
|
2649
|
-
this.remotes = {
|
|
2650
|
-
getOriginUrl: async (props) => {
|
|
2651
|
-
getRemoteOriginUrlProjectSchema.parse(props);
|
|
2652
|
-
const projectPath = pathTo.project(props.id);
|
|
2653
|
-
return await this.gitService.remotes.getOriginUrl(projectPath);
|
|
2654
|
-
},
|
|
2655
|
-
setOriginUrl: async (props) => {
|
|
2656
|
-
setRemoteOriginUrlProjectSchema.parse(props);
|
|
2657
|
-
const projectPath = pathTo.project(props.id);
|
|
2658
|
-
const hasOrigin = await this.gitService.remotes.hasOrigin(projectPath);
|
|
2659
|
-
if (!hasOrigin) {
|
|
2660
|
-
await this.gitService.remotes.addOrigin(projectPath, props.url);
|
|
2661
|
-
} else {
|
|
2662
|
-
await this.gitService.remotes.setOriginUrl(projectPath, props.url);
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
};
|
|
2666
2617
|
this.jsonFileService = jsonFileService;
|
|
2667
2618
|
this.userService = userService;
|
|
2668
2619
|
this.gitService = gitService;
|
|
@@ -2776,7 +2727,14 @@ var ProjectService = class extends AbstractCrudService {
|
|
|
2776
2727
|
const prevProjectFile = await this.read(props);
|
|
2777
2728
|
const projectFile = {
|
|
2778
2729
|
...prevProjectFile,
|
|
2779
|
-
|
|
2730
|
+
name: props.name || prevProjectFile.name,
|
|
2731
|
+
description: props.description || prevProjectFile.description,
|
|
2732
|
+
settings: {
|
|
2733
|
+
language: {
|
|
2734
|
+
supported: props.settings?.language.supported || prevProjectFile.settings.language.supported,
|
|
2735
|
+
default: props.settings?.language.default || prevProjectFile.settings.language.default
|
|
2736
|
+
}
|
|
2737
|
+
},
|
|
2780
2738
|
updated: currentTimestamp()
|
|
2781
2739
|
};
|
|
2782
2740
|
await this.jsonFileService.update(projectFile, filePath, projectFileSchema);
|
|
@@ -2822,6 +2780,7 @@ var ProjectService = class extends AbstractCrudService {
|
|
|
2822
2780
|
if (upgrade.to !== "0.0.0") {
|
|
2823
2781
|
return upgrade;
|
|
2824
2782
|
}
|
|
2783
|
+
return;
|
|
2825
2784
|
});
|
|
2826
2785
|
for (let index = 0; index < sortedUpgrades.length; index++) {
|
|
2827
2786
|
const upgrade = sortedUpgrades[index];
|
|
@@ -2852,6 +2811,45 @@ var ProjectService = class extends AbstractCrudService {
|
|
|
2852
2811
|
}
|
|
2853
2812
|
}
|
|
2854
2813
|
}
|
|
2814
|
+
branches = {
|
|
2815
|
+
list: async (props) => {
|
|
2816
|
+
listBranchesProjectSchema.parse(props);
|
|
2817
|
+
const projectPath = pathTo.project(props.id);
|
|
2818
|
+
await this.gitService.fetch(projectPath);
|
|
2819
|
+
return await this.gitService.branches.list(projectPath);
|
|
2820
|
+
},
|
|
2821
|
+
current: async (props) => {
|
|
2822
|
+
currentBranchProjectSchema.parse(props);
|
|
2823
|
+
const projectPath = pathTo.project(props.id);
|
|
2824
|
+
return await this.gitService.branches.current(projectPath);
|
|
2825
|
+
},
|
|
2826
|
+
switch: async (props) => {
|
|
2827
|
+
switchBranchProjectSchema.parse(props);
|
|
2828
|
+
const projectPath = pathTo.project(props.id);
|
|
2829
|
+
return await this.gitService.branches.switch(
|
|
2830
|
+
projectPath,
|
|
2831
|
+
props.branch,
|
|
2832
|
+
props.options
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2835
|
+
};
|
|
2836
|
+
remotes = {
|
|
2837
|
+
getOriginUrl: async (props) => {
|
|
2838
|
+
getRemoteOriginUrlProjectSchema.parse(props);
|
|
2839
|
+
const projectPath = pathTo.project(props.id);
|
|
2840
|
+
return await this.gitService.remotes.getOriginUrl(projectPath);
|
|
2841
|
+
},
|
|
2842
|
+
setOriginUrl: async (props) => {
|
|
2843
|
+
setRemoteOriginUrlProjectSchema.parse(props);
|
|
2844
|
+
const projectPath = pathTo.project(props.id);
|
|
2845
|
+
const hasOrigin = await this.gitService.remotes.hasOrigin(projectPath);
|
|
2846
|
+
if (!hasOrigin) {
|
|
2847
|
+
await this.gitService.remotes.addOrigin(projectPath, props.url);
|
|
2848
|
+
} else {
|
|
2849
|
+
await this.gitService.remotes.setOriginUrl(projectPath, props.url);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
};
|
|
2855
2853
|
/**
|
|
2856
2854
|
* Returns the differences of the given Projects current branch
|
|
2857
2855
|
* between the local and remote `origin` (commits ahead & behind)
|
|
@@ -3003,8 +3001,50 @@ var ProjectService = class extends AbstractCrudService {
|
|
|
3003
3001
|
}
|
|
3004
3002
|
};
|
|
3005
3003
|
|
|
3004
|
+
// src/service/UserService.ts
|
|
3005
|
+
var UserService = class {
|
|
3006
|
+
jsonFileService;
|
|
3007
|
+
constructor(jsonFileService) {
|
|
3008
|
+
this.jsonFileService = jsonFileService;
|
|
3009
|
+
}
|
|
3010
|
+
/**
|
|
3011
|
+
* Returns the User currently working with Core
|
|
3012
|
+
*/
|
|
3013
|
+
async get() {
|
|
3014
|
+
try {
|
|
3015
|
+
return await this.jsonFileService.read(pathTo.userFile, userFileSchema);
|
|
3016
|
+
} catch (error) {
|
|
3017
|
+
return void 0;
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
/**
|
|
3021
|
+
* Sets the User currently working with Core
|
|
3022
|
+
*
|
|
3023
|
+
* By doing so all git operations are done with the signature of this User
|
|
3024
|
+
*/
|
|
3025
|
+
async set(props) {
|
|
3026
|
+
setUserSchema.parse(props);
|
|
3027
|
+
const userFilePath = pathTo.userFile;
|
|
3028
|
+
const userFile = {
|
|
3029
|
+
...props
|
|
3030
|
+
};
|
|
3031
|
+
if (userFile.userType === UserTypeSchema.Enum.cloud) {
|
|
3032
|
+
}
|
|
3033
|
+
await this.jsonFileService.update(userFile, userFilePath, userFileSchema);
|
|
3034
|
+
return userFile;
|
|
3035
|
+
}
|
|
3036
|
+
};
|
|
3037
|
+
|
|
3006
3038
|
// src/index.node.ts
|
|
3007
3039
|
var ElekIoCore = class {
|
|
3040
|
+
options;
|
|
3041
|
+
userService;
|
|
3042
|
+
gitService;
|
|
3043
|
+
jsonFileService;
|
|
3044
|
+
assetService;
|
|
3045
|
+
projectService;
|
|
3046
|
+
collectionService;
|
|
3047
|
+
entryService;
|
|
3008
3048
|
// private readonly sharedValueService: SharedValueService;
|
|
3009
3049
|
constructor(props) {
|
|
3010
3050
|
const parsedProps = constructorElekIoCoreSchema.parse(props);
|
|
@@ -3020,7 +3060,7 @@ var ElekIoCore = class {
|
|
|
3020
3060
|
this.options = Object.assign({}, defaults, parsedProps);
|
|
3021
3061
|
this.jsonFileService = new JsonFileService(this.options);
|
|
3022
3062
|
this.userService = new UserService(this.jsonFileService);
|
|
3023
|
-
this.gitService = new
|
|
3063
|
+
this.gitService = new GitService(this.options, this.userService);
|
|
3024
3064
|
this.assetService = new AssetService(
|
|
3025
3065
|
this.options,
|
|
3026
3066
|
this.jsonFileService,
|