saasaloy 0.4.0 → 0.5.1
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/index.js
CHANGED
|
@@ -367,6 +367,34 @@ var MANIFEST_FILE = join3(".saasaloy", "manifest.json");
|
|
|
367
367
|
function samePatchEntry(a, b) {
|
|
368
368
|
return a.module === b.module && a.file === b.file && JSON.stringify(a.patch) === JSON.stringify(b.patch);
|
|
369
369
|
}
|
|
370
|
+
function recordManagedFile(manifest, record) {
|
|
371
|
+
manifest.managed[record.target] = {
|
|
372
|
+
hash: record.hash,
|
|
373
|
+
module: record.module,
|
|
374
|
+
...record.adopted ? { adopted: true } : {},
|
|
375
|
+
...record.from === void 0 ? {} : { from: record.from }
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function untrackManagedFile(manifest, target) {
|
|
379
|
+
delete manifest.managed[target];
|
|
380
|
+
}
|
|
381
|
+
function recordPatch(manifest, entry) {
|
|
382
|
+
if (manifest.patches.some((existing) => samePatchEntry(existing, entry))) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
manifest.patches.push(entry);
|
|
386
|
+
}
|
|
387
|
+
function untrackPatch(manifest, entry) {
|
|
388
|
+
manifest.patches = manifest.patches.filter(
|
|
389
|
+
(patch) => !samePatchEntry(patch, entry)
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
function recordLink(manifest, target, path) {
|
|
393
|
+
manifest.links[target] = path;
|
|
394
|
+
}
|
|
395
|
+
function untrackLink(manifest, target) {
|
|
396
|
+
delete manifest.links[target];
|
|
397
|
+
}
|
|
370
398
|
function emptyManifest() {
|
|
371
399
|
return { links: {}, managed: {}, patches: [], removeWarnings: {} };
|
|
372
400
|
}
|
|
@@ -707,40 +735,45 @@ function buildRouteLink(receiver, path, call) {
|
|
|
707
735
|
|
|
708
736
|
// src/lib/patch/const-array.ts
|
|
709
737
|
import { parseModule as parseModule2 } from "magicast";
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
738
|
+
|
|
739
|
+
// src/lib/patch/ts-array.ts
|
|
740
|
+
function findConstArray(program, constName) {
|
|
741
|
+
for (const statement of program.body) {
|
|
742
|
+
const declaration = statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
|
|
743
|
+
if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") {
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
for (const declarator of declaration.declarations) {
|
|
747
|
+
if (declarator.id.type !== "Identifier" || declarator.id.name !== constName || !declarator.init) {
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
return asArray(declarator.init);
|
|
751
|
+
}
|
|
716
752
|
}
|
|
717
|
-
return
|
|
753
|
+
return void 0;
|
|
718
754
|
}
|
|
719
|
-
function
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
755
|
+
function asArray(node) {
|
|
756
|
+
const value = unwrapTypeExpression(node);
|
|
757
|
+
return value.type === "ArrayExpression" ? value : void 0;
|
|
758
|
+
}
|
|
759
|
+
function findElement(array, key, wanted) {
|
|
760
|
+
for (const element of array.elements) {
|
|
761
|
+
if (element?.type === "ObjectExpression" && entryValue(element, key) === wanted) {
|
|
762
|
+
return element;
|
|
763
|
+
}
|
|
727
764
|
}
|
|
728
765
|
return void 0;
|
|
729
766
|
}
|
|
730
|
-
function
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
(element) => entryValue(element, patch.key) === wanted
|
|
739
|
-
);
|
|
740
|
-
if (index === -1) {
|
|
741
|
-
return source;
|
|
767
|
+
function propertyValue(object, key) {
|
|
768
|
+
for (const property of object.properties) {
|
|
769
|
+
if (property.type !== "ObjectProperty" || property.computed) {
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if (propertyName(property.key) === key) {
|
|
773
|
+
return property.value;
|
|
774
|
+
}
|
|
742
775
|
}
|
|
743
|
-
return
|
|
776
|
+
return void 0;
|
|
744
777
|
}
|
|
745
778
|
function appendEntry(source, array, entry) {
|
|
746
779
|
const close = array.end - 1;
|
|
@@ -797,6 +830,32 @@ function entryValue(element, key) {
|
|
|
797
830
|
}
|
|
798
831
|
return void 0;
|
|
799
832
|
}
|
|
833
|
+
function renderObject(entry) {
|
|
834
|
+
return `{ ${renderProperties(entry).join(", ")} }`;
|
|
835
|
+
}
|
|
836
|
+
function renderProperties(entry) {
|
|
837
|
+
return Object.entries(entry).map(
|
|
838
|
+
([key, value]) => `${renderKey(key)}: ${renderValue(value)}`
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
function renderKey(key) {
|
|
842
|
+
return /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
|
|
843
|
+
}
|
|
844
|
+
function renderValue(value) {
|
|
845
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
846
|
+
return JSON.stringify(value);
|
|
847
|
+
}
|
|
848
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
849
|
+
return String(value);
|
|
850
|
+
}
|
|
851
|
+
if (Array.isArray(value)) {
|
|
852
|
+
return `[${value.map(renderValue).join(", ")}]`;
|
|
853
|
+
}
|
|
854
|
+
if (typeof value === "object") {
|
|
855
|
+
return renderObject(value);
|
|
856
|
+
}
|
|
857
|
+
throw new TypeError("patch entries must contain JSON values");
|
|
858
|
+
}
|
|
800
859
|
function propertyName(node) {
|
|
801
860
|
if (node.type === "Identifier") {
|
|
802
861
|
return node.name;
|
|
@@ -809,22 +868,6 @@ function literalValue(node) {
|
|
|
809
868
|
}
|
|
810
869
|
return node.type === "NullLiteral" ? null : node.value;
|
|
811
870
|
}
|
|
812
|
-
function findConstArray(program, constName) {
|
|
813
|
-
for (const statement of program.body) {
|
|
814
|
-
const declaration = statement.type === "ExportNamedDeclaration" ? statement.declaration : statement;
|
|
815
|
-
if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") {
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
for (const declarator of declaration.declarations) {
|
|
819
|
-
if (declarator.id.type !== "Identifier" || declarator.id.name !== constName || !declarator.init) {
|
|
820
|
-
continue;
|
|
821
|
-
}
|
|
822
|
-
const value = unwrapTypeExpression(declarator.init);
|
|
823
|
-
return value.type === "ArrayExpression" ? value : void 0;
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
return void 0;
|
|
827
|
-
}
|
|
828
871
|
function unwrapTypeExpression(node) {
|
|
829
872
|
let value = node;
|
|
830
873
|
while (value.type === "TSAsExpression" || value.type === "TSSatisfiesExpression" || value.type === "TypeCastExpression") {
|
|
@@ -832,26 +875,42 @@ function unwrapTypeExpression(node) {
|
|
|
832
875
|
}
|
|
833
876
|
return value;
|
|
834
877
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
878
|
+
|
|
879
|
+
// src/lib/patch/const-array.ts
|
|
880
|
+
function insertIntoConstArray(source, patch) {
|
|
881
|
+
const mod = parseModule2(source);
|
|
882
|
+
const array = findConstArray(mod.$ast, patch.constName);
|
|
883
|
+
const wanted = patch.entry[patch.key];
|
|
884
|
+
if (!array || wanted === void 0 || hasEntry(array, patch.key, wanted)) {
|
|
885
|
+
return source;
|
|
886
|
+
}
|
|
887
|
+
return appendEntry(source, array, renderObject(patch.entry));
|
|
840
888
|
}
|
|
841
|
-
function
|
|
842
|
-
|
|
843
|
-
|
|
889
|
+
function constArrayInsertRefusal(source, patch) {
|
|
890
|
+
const mod = parseModule2(source);
|
|
891
|
+
const array = findConstArray(mod.$ast, patch.constName);
|
|
892
|
+
if (!array) {
|
|
893
|
+
return `const-array could not find a module-scope const array named ${patch.constName}`;
|
|
844
894
|
}
|
|
845
|
-
if (
|
|
846
|
-
return
|
|
895
|
+
if (patch.entry[patch.key] === void 0) {
|
|
896
|
+
return `const-array entry has no identity property named ${patch.key}`;
|
|
847
897
|
}
|
|
848
|
-
|
|
849
|
-
|
|
898
|
+
return void 0;
|
|
899
|
+
}
|
|
900
|
+
function removeFromConstArray(source, patch) {
|
|
901
|
+
const mod = parseModule2(source);
|
|
902
|
+
const array = findConstArray(mod.$ast, patch.constName);
|
|
903
|
+
const wanted = patch.entry[patch.key];
|
|
904
|
+
if (!array || wanted === void 0) {
|
|
905
|
+
return source;
|
|
850
906
|
}
|
|
851
|
-
|
|
852
|
-
|
|
907
|
+
const index = array.elements.findIndex(
|
|
908
|
+
(element) => entryValue(element, patch.key) === wanted
|
|
909
|
+
);
|
|
910
|
+
if (index === -1) {
|
|
911
|
+
return source;
|
|
853
912
|
}
|
|
854
|
-
|
|
913
|
+
return removeEntry(source, array, index);
|
|
855
914
|
}
|
|
856
915
|
|
|
857
916
|
// src/lib/patch/diff.ts
|
|
@@ -1211,6 +1270,233 @@ function inferFormatting(source) {
|
|
|
1211
1270
|
};
|
|
1212
1271
|
}
|
|
1213
1272
|
|
|
1273
|
+
// src/lib/patch/nav-entry.ts
|
|
1274
|
+
import { parseModule as parseModule5 } from "magicast";
|
|
1275
|
+
|
|
1276
|
+
// src/lib/patch/named-import.ts
|
|
1277
|
+
import { parseModule as parseModule4 } from "magicast";
|
|
1278
|
+
var PRINT_WIDTH = 80;
|
|
1279
|
+
function ensureNamedImport(source, want) {
|
|
1280
|
+
const program = parseModule4(source).$ast;
|
|
1281
|
+
const declaration = findImport(program, want.from);
|
|
1282
|
+
if (!declaration) {
|
|
1283
|
+
return insertDeclaration(source, program, want);
|
|
1284
|
+
}
|
|
1285
|
+
const named = namedSpecifiers(declaration).map(
|
|
1286
|
+
(specifier) => source.slice(specifier.start, specifier.end)
|
|
1287
|
+
);
|
|
1288
|
+
if (named.includes(want.name)) {
|
|
1289
|
+
return source;
|
|
1290
|
+
}
|
|
1291
|
+
const at = named.findIndex((text4) => localOf(text4) > want.name);
|
|
1292
|
+
const next = at === -1 ? [...named, want.name] : named.toSpliced(at, 0, want.name);
|
|
1293
|
+
return replaceDeclaration(source, declaration, next, want.from);
|
|
1294
|
+
}
|
|
1295
|
+
function removeNamedImport(source, want) {
|
|
1296
|
+
const program = parseModule4(source).$ast;
|
|
1297
|
+
const declaration = findImport(program, want.from);
|
|
1298
|
+
if (!declaration || isReferenced(program, want.name)) {
|
|
1299
|
+
return source;
|
|
1300
|
+
}
|
|
1301
|
+
const specifiers = namedSpecifiers(declaration);
|
|
1302
|
+
const texts = specifiers.map(
|
|
1303
|
+
(specifier) => source.slice(specifier.start, specifier.end)
|
|
1304
|
+
);
|
|
1305
|
+
const at = texts.indexOf(want.name);
|
|
1306
|
+
if (at === -1) {
|
|
1307
|
+
return source;
|
|
1308
|
+
}
|
|
1309
|
+
if (declaration.specifiers.length === 1) {
|
|
1310
|
+
const lineEnd = source.indexOf("\n", declaration.end);
|
|
1311
|
+
return lineEnd === -1 ? source.slice(0, declaration.start) : `${source.slice(0, declaration.start)}${source.slice(lineEnd + 1)}`;
|
|
1312
|
+
}
|
|
1313
|
+
return replaceDeclaration(
|
|
1314
|
+
source,
|
|
1315
|
+
declaration,
|
|
1316
|
+
texts.toSpliced(at, 1),
|
|
1317
|
+
want.from
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
function importedElsewhere(source, want) {
|
|
1321
|
+
const program = parseModule4(source).$ast;
|
|
1322
|
+
for (const statement of program.body) {
|
|
1323
|
+
if (statement.type !== "ImportDeclaration") {
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
const declaration = statement;
|
|
1327
|
+
for (const specifier of declaration.specifiers) {
|
|
1328
|
+
if (localName(specifier) !== want.name) {
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
const ours = specifier.type === "ImportSpecifier" && importedName(specifier) === want.name && sourceValue(declaration) === want.from;
|
|
1332
|
+
if (!ours) {
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
function replaceDeclaration(source, declaration, named, from) {
|
|
1340
|
+
const leading = declaration.specifiers.filter((specifier) => specifier.type !== "ImportSpecifier").map((specifier) => source.slice(specifier.start, specifier.end));
|
|
1341
|
+
const text4 = source.slice(declaration.start, declaration.end);
|
|
1342
|
+
const tail = `from ${JSON.stringify(from)}${text4.trimEnd().endsWith(";") ? ";" : ""}`;
|
|
1343
|
+
const keyword = declaration.importKind === "type" ? "import type" : "import";
|
|
1344
|
+
const inline = [...leading, `{ ${named.join(", ")} }`].join(", ");
|
|
1345
|
+
const oneLine = `${keyword} ${inline} ${tail}`;
|
|
1346
|
+
const printed2 = oneLine.length <= PRINT_WIDTH ? oneLine : `${[keyword, ...leading.map((part) => `${part},`)].join(" ")} {
|
|
1347
|
+
${named.map((specifier) => ` ${specifier},
|
|
1348
|
+
`).join("")}} ${tail}`;
|
|
1349
|
+
return `${source.slice(0, declaration.start)}${printed2}${source.slice(declaration.end)}`;
|
|
1350
|
+
}
|
|
1351
|
+
function insertDeclaration(source, program, want) {
|
|
1352
|
+
const statement = `import { ${want.name} } from ${JSON.stringify(want.from)};`;
|
|
1353
|
+
const last = program.body.findLast(
|
|
1354
|
+
(node) => node.type === "ImportDeclaration"
|
|
1355
|
+
);
|
|
1356
|
+
if (!last) {
|
|
1357
|
+
return `${statement}
|
|
1358
|
+
|
|
1359
|
+
${source}`;
|
|
1360
|
+
}
|
|
1361
|
+
return `${source.slice(0, last.end)}
|
|
1362
|
+
${statement}${source.slice(last.end)}`;
|
|
1363
|
+
}
|
|
1364
|
+
function findImport(program, from) {
|
|
1365
|
+
for (const statement of program.body) {
|
|
1366
|
+
if (statement.type !== "ImportDeclaration") {
|
|
1367
|
+
continue;
|
|
1368
|
+
}
|
|
1369
|
+
const declaration = statement;
|
|
1370
|
+
if (declaration.importKind === "type") {
|
|
1371
|
+
continue;
|
|
1372
|
+
}
|
|
1373
|
+
if (sourceValue(declaration) === from) {
|
|
1374
|
+
return declaration;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return void 0;
|
|
1378
|
+
}
|
|
1379
|
+
function namedSpecifiers(declaration) {
|
|
1380
|
+
return declaration.specifiers.filter(
|
|
1381
|
+
(specifier) => specifier.type === "ImportSpecifier" && specifier.importKind !== "type"
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1384
|
+
function localOf(text4) {
|
|
1385
|
+
const [, local] = text4.split(/\s+as\s+/);
|
|
1386
|
+
return (local ?? text4).trim();
|
|
1387
|
+
}
|
|
1388
|
+
function sourceValue(declaration) {
|
|
1389
|
+
const value = declaration.source.value;
|
|
1390
|
+
return typeof value === "string" ? value : void 0;
|
|
1391
|
+
}
|
|
1392
|
+
function importedName(specifier) {
|
|
1393
|
+
return identifierName(specifier.imported);
|
|
1394
|
+
}
|
|
1395
|
+
function localName(specifier) {
|
|
1396
|
+
return identifierName(specifier.local);
|
|
1397
|
+
}
|
|
1398
|
+
function identifierName(node) {
|
|
1399
|
+
if (node?.type === "Identifier") {
|
|
1400
|
+
return node.name;
|
|
1401
|
+
}
|
|
1402
|
+
if (node?.type === "StringLiteral" || node?.type === "Literal") {
|
|
1403
|
+
const value = node.value;
|
|
1404
|
+
return typeof value === "string" ? value : void 0;
|
|
1405
|
+
}
|
|
1406
|
+
return void 0;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// src/lib/patch/nav-entry.ts
|
|
1410
|
+
var IDENTITY = "to";
|
|
1411
|
+
function insertNavEntry(source, patch) {
|
|
1412
|
+
const items = findItems(source, patch);
|
|
1413
|
+
const wanted = patch.entry[IDENTITY];
|
|
1414
|
+
if (!items || wanted === void 0 || hasEntry(items, IDENTITY, wanted)) {
|
|
1415
|
+
return source;
|
|
1416
|
+
}
|
|
1417
|
+
if (importedElsewhere(source, patch.icon)) {
|
|
1418
|
+
return source;
|
|
1419
|
+
}
|
|
1420
|
+
const withEntry = appendEntry(source, items, renderItem(patch));
|
|
1421
|
+
return ensureNamedImport(withEntry, patch.icon);
|
|
1422
|
+
}
|
|
1423
|
+
function navEntryInsertRefusal(source, patch) {
|
|
1424
|
+
const program = parseModule5(source).$ast;
|
|
1425
|
+
const areas = findConstArray(program, patch.constName);
|
|
1426
|
+
if (!areas) {
|
|
1427
|
+
return `nav-entry could not find a module-scope const array named ${patch.constName}`;
|
|
1428
|
+
}
|
|
1429
|
+
const area = findElement(areas, IDENTITY, patch.area);
|
|
1430
|
+
if (!area) {
|
|
1431
|
+
return `nav-entry could not find an area with ${IDENTITY} ${JSON.stringify(patch.area)} in ${patch.constName}`;
|
|
1432
|
+
}
|
|
1433
|
+
const groups = arrayProperty(area, "groups");
|
|
1434
|
+
if (!groups) {
|
|
1435
|
+
return `nav-entry found the ${JSON.stringify(patch.area)} area but it has no groups array`;
|
|
1436
|
+
}
|
|
1437
|
+
const group = findElement(groups, "label", patch.group);
|
|
1438
|
+
if (!group) {
|
|
1439
|
+
return `nav-entry could not find a group labelled ${JSON.stringify(patch.group)} in the ${JSON.stringify(patch.area)} area`;
|
|
1440
|
+
}
|
|
1441
|
+
if (!arrayProperty(group, "items")) {
|
|
1442
|
+
return `nav-entry found the ${JSON.stringify(patch.group)} group but it has no items array`;
|
|
1443
|
+
}
|
|
1444
|
+
if (patch.entry[IDENTITY] === void 0) {
|
|
1445
|
+
return `nav-entry entry has no identity property named ${IDENTITY}`;
|
|
1446
|
+
}
|
|
1447
|
+
if (importedElsewhere(source, patch.icon)) {
|
|
1448
|
+
return `${JSON.stringify(patch.icon.name)} is already bound to something other than the named import from ${JSON.stringify(patch.icon.from)}, so the icon would render the wrong component`;
|
|
1449
|
+
}
|
|
1450
|
+
return void 0;
|
|
1451
|
+
}
|
|
1452
|
+
function removeNavEntry(source, patch) {
|
|
1453
|
+
const items = findItems(source, patch);
|
|
1454
|
+
const wanted = patch.entry[IDENTITY];
|
|
1455
|
+
if (!items || wanted === void 0) {
|
|
1456
|
+
return source;
|
|
1457
|
+
}
|
|
1458
|
+
const index = items.elements.findIndex(
|
|
1459
|
+
(element) => entryValue(element, IDENTITY) === wanted
|
|
1460
|
+
);
|
|
1461
|
+
if (index === -1) {
|
|
1462
|
+
return source;
|
|
1463
|
+
}
|
|
1464
|
+
const withoutEntry = removeEntry(source, items, index);
|
|
1465
|
+
return removeNamedImport(withoutEntry, patch.icon);
|
|
1466
|
+
}
|
|
1467
|
+
function navEntryRemoveRefusal(source, patch) {
|
|
1468
|
+
const items = findItems(source, patch);
|
|
1469
|
+
if (!items) {
|
|
1470
|
+
return `nav-entry could not find the ${JSON.stringify(patch.group)} group of the ${JSON.stringify(patch.area)} area in ${patch.constName}`;
|
|
1471
|
+
}
|
|
1472
|
+
return void 0;
|
|
1473
|
+
}
|
|
1474
|
+
function findItems(source, patch) {
|
|
1475
|
+
const program = parseModule5(source).$ast;
|
|
1476
|
+
const areas = findConstArray(program, patch.constName);
|
|
1477
|
+
if (!areas) {
|
|
1478
|
+
return void 0;
|
|
1479
|
+
}
|
|
1480
|
+
const area = findElement(areas, IDENTITY, patch.area);
|
|
1481
|
+
const groups = area && arrayProperty(area, "groups");
|
|
1482
|
+
if (!groups) {
|
|
1483
|
+
return void 0;
|
|
1484
|
+
}
|
|
1485
|
+
const group = findElement(groups, "label", patch.group);
|
|
1486
|
+
return group ? arrayProperty(group, "items") : void 0;
|
|
1487
|
+
}
|
|
1488
|
+
function arrayProperty(object, key) {
|
|
1489
|
+
const value = propertyValue(object, key);
|
|
1490
|
+
return value ? asArray(value) : void 0;
|
|
1491
|
+
}
|
|
1492
|
+
function renderItem(patch) {
|
|
1493
|
+
const properties = [
|
|
1494
|
+
...renderProperties(patch.entry),
|
|
1495
|
+
`${renderKey("icon")}: ${patch.icon.name}`
|
|
1496
|
+
];
|
|
1497
|
+
return `{ ${properties.join(", ")} }`;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1214
1500
|
// src/lib/patch/pkg-json.ts
|
|
1215
1501
|
import {
|
|
1216
1502
|
applyEdits as applyEdits2,
|
|
@@ -1325,9 +1611,9 @@ function upsertPackageJsonScript(source, patch) {
|
|
|
1325
1611
|
}
|
|
1326
1612
|
|
|
1327
1613
|
// src/lib/patch/ts-module.ts
|
|
1328
|
-
import { builders as builders2, generateCode as generateCode3, parseModule as
|
|
1614
|
+
import { builders as builders2, generateCode as generateCode3, parseModule as parseModule6 } from "magicast";
|
|
1329
1615
|
function insertIntoPluginArray(source, patch) {
|
|
1330
|
-
const mod =
|
|
1616
|
+
const mod = parseModule6(source);
|
|
1331
1617
|
const exported = mod.exports[patch.exportName];
|
|
1332
1618
|
const callArg = exported?.$args?.[0];
|
|
1333
1619
|
if (!callArg) {
|
|
@@ -1353,7 +1639,7 @@ function insertIntoPluginArray(source, patch) {
|
|
|
1353
1639
|
return print2(source, mod);
|
|
1354
1640
|
}
|
|
1355
1641
|
function removeFromPluginArray(source, patch) {
|
|
1356
|
-
const mod =
|
|
1642
|
+
const mod = parseModule6(source);
|
|
1357
1643
|
const exported = mod.exports[patch.exportName];
|
|
1358
1644
|
const callArg = exported?.$args?.[0];
|
|
1359
1645
|
if (!callArg) {
|
|
@@ -1381,7 +1667,7 @@ function removeFromPluginArray(source, patch) {
|
|
|
1381
1667
|
return print2(source, mod);
|
|
1382
1668
|
}
|
|
1383
1669
|
function pluginArrayRemoveRefusal(source, patch) {
|
|
1384
|
-
const mod =
|
|
1670
|
+
const mod = parseModule6(source);
|
|
1385
1671
|
const callArg = mod.exports[patch.exportName]?.$args?.[0];
|
|
1386
1672
|
if (!callArg) {
|
|
1387
1673
|
return void 0;
|
|
@@ -1433,6 +1719,7 @@ var PATCH_KIND_KEYS = {
|
|
|
1433
1719
|
"chained-route": true,
|
|
1434
1720
|
"const-array": true,
|
|
1435
1721
|
"drizzle-column": true,
|
|
1722
|
+
"nav-entry": true,
|
|
1436
1723
|
"package-json-dependency": true,
|
|
1437
1724
|
"package-json-script": true,
|
|
1438
1725
|
"plugin-array": true,
|
|
@@ -1469,6 +1756,9 @@ function applyCodemod(source, patch) {
|
|
|
1469
1756
|
case "const-array": {
|
|
1470
1757
|
return insertIntoConstArray(source, patch);
|
|
1471
1758
|
}
|
|
1759
|
+
case "nav-entry": {
|
|
1760
|
+
return insertNavEntry(source, patch);
|
|
1761
|
+
}
|
|
1472
1762
|
case "drizzle-column": {
|
|
1473
1763
|
return insertDrizzleColumn(source, patch);
|
|
1474
1764
|
}
|
|
@@ -1497,6 +1787,7 @@ var INVERSES = {
|
|
|
1497
1787
|
"chained-route": removeChainedRoute,
|
|
1498
1788
|
"const-array": removeFromConstArray,
|
|
1499
1789
|
"drizzle-column": removeDrizzleColumn,
|
|
1790
|
+
"nav-entry": removeNavEntry,
|
|
1500
1791
|
"plugin-array": removeFromPluginArray,
|
|
1501
1792
|
"wrangler-binding": removeWranglerBinding
|
|
1502
1793
|
};
|
|
@@ -1521,11 +1812,13 @@ var REFUSALS = {
|
|
|
1521
1812
|
"chained-route": chainedRouteInsertRefusal,
|
|
1522
1813
|
"const-array": constArrayInsertRefusal,
|
|
1523
1814
|
"drizzle-column": drizzleColumnInsertRefusal,
|
|
1815
|
+
"nav-entry": navEntryInsertRefusal,
|
|
1524
1816
|
"package-json-script": packageJsonScriptRefusal
|
|
1525
1817
|
};
|
|
1526
1818
|
var REVERSAL_REFUSALS = {
|
|
1527
1819
|
"chained-route": chainedRouteRemoveRefusal,
|
|
1528
1820
|
"drizzle-column": drizzleColumnRemoveRefusal,
|
|
1821
|
+
"nav-entry": navEntryRemoveRefusal,
|
|
1529
1822
|
"plugin-array": pluginArrayRemoveRefusal,
|
|
1530
1823
|
"wrangler-binding": wranglerBindingRemoveRefusal
|
|
1531
1824
|
};
|
|
@@ -1957,11 +2250,12 @@ async function executePlan(plan, root, config, manifest) {
|
|
|
1957
2250
|
} else {
|
|
1958
2251
|
refreshed.push(file);
|
|
1959
2252
|
}
|
|
1960
|
-
manifest
|
|
1961
|
-
|
|
2253
|
+
recordManagedFile(manifest, {
|
|
2254
|
+
from: file.from,
|
|
1962
2255
|
hash: file.newHash,
|
|
1963
|
-
|
|
1964
|
-
|
|
2256
|
+
module: file.module,
|
|
2257
|
+
target: file.target
|
|
2258
|
+
});
|
|
1965
2259
|
}
|
|
1966
2260
|
for (const p of plan.patches) {
|
|
1967
2261
|
if (!await pathExists(p.fileAbs)) {
|
|
@@ -1974,14 +2268,11 @@ async function executePlan(plan, root, config, manifest) {
|
|
|
1974
2268
|
if (changed) {
|
|
1975
2269
|
await writeFile3(p.fileAbs, content, "utf-8");
|
|
1976
2270
|
patched.push(p);
|
|
1977
|
-
|
|
1978
|
-
module: p.module,
|
|
2271
|
+
recordPatch(manifest, {
|
|
1979
2272
|
file: p.file,
|
|
2273
|
+
module: p.module,
|
|
1980
2274
|
patch: p.patch
|
|
1981
|
-
};
|
|
1982
|
-
if (!manifest.patches.some((existing) => samePatchEntry(existing, entry))) {
|
|
1983
|
-
manifest.patches.push(entry);
|
|
1984
|
-
}
|
|
2275
|
+
});
|
|
1985
2276
|
} else if (reason !== void 0) {
|
|
1986
2277
|
patchRefusals.push({ patch: p, reason });
|
|
1987
2278
|
}
|
|
@@ -1995,7 +2286,7 @@ async function executePlan(plan, root, config, manifest) {
|
|
|
1995
2286
|
await assertNoSymlinkPath(root, link.pathAbs);
|
|
1996
2287
|
await createDirLink(link.pathAbs, link.targetAbs);
|
|
1997
2288
|
}
|
|
1998
|
-
manifest
|
|
2289
|
+
recordLink(manifest, link.target, link.path);
|
|
1999
2290
|
links.push(link);
|
|
2000
2291
|
}
|
|
2001
2292
|
for (const [alias, prefix] of Object.entries(plan.aliases)) {
|
|
@@ -2633,6 +2924,24 @@ function upsertLock(lock, provenance, installed, graph) {
|
|
|
2633
2924
|
}
|
|
2634
2925
|
}
|
|
2635
2926
|
|
|
2927
|
+
// src/lib/ledger.ts
|
|
2928
|
+
async function persistLedger(input) {
|
|
2929
|
+
const saves = [
|
|
2930
|
+
[MANIFEST_FILE, () => saveManifest(input.root, input.manifest)],
|
|
2931
|
+
[CONFIG_FILE, () => saveConfig(input.root, input.config)],
|
|
2932
|
+
[LOCK_FILE, () => saveLock(input.root, input.lock)]
|
|
2933
|
+
];
|
|
2934
|
+
const failures = [];
|
|
2935
|
+
for (const [file, save] of saves) {
|
|
2936
|
+
try {
|
|
2937
|
+
await save();
|
|
2938
|
+
} catch (error) {
|
|
2939
|
+
failures.push({ error, file });
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
return failures;
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2636
2945
|
// src/lib/pkg-json.ts
|
|
2637
2946
|
import { readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
|
|
2638
2947
|
import { join as join6 } from "path";
|
|
@@ -3478,18 +3787,11 @@ async function persistState(input) {
|
|
|
3478
3787
|
failures.push(error);
|
|
3479
3788
|
log.warn(`Couldn't pin ${LOCK_FILE} \u2014 ${formatFailure(error)}.`);
|
|
3480
3789
|
}
|
|
3481
|
-
const
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
for (const [file, save] of saves) {
|
|
3487
|
-
try {
|
|
3488
|
-
await save();
|
|
3489
|
-
} catch (error) {
|
|
3490
|
-
failures.push(error);
|
|
3491
|
-
log.warn(`Couldn't write ${file} \u2014 ${formatFailure(error)}.`);
|
|
3492
|
-
}
|
|
3790
|
+
for (const failure of await persistLedger(input)) {
|
|
3791
|
+
failures.push(failure.error);
|
|
3792
|
+
log.warn(
|
|
3793
|
+
`Couldn't write ${failure.file} \u2014 ${formatFailure(failure.error)}.`
|
|
3794
|
+
);
|
|
3493
3795
|
}
|
|
3494
3796
|
return failures;
|
|
3495
3797
|
}
|
|
@@ -3881,7 +4183,7 @@ import { fileURLToPath as fileURLToPath3 } from "url";
|
|
|
3881
4183
|
// package.json
|
|
3882
4184
|
var package_default = {
|
|
3883
4185
|
name: "saasaloy",
|
|
3884
|
-
version: "0.
|
|
4186
|
+
version: "0.5.1",
|
|
3885
4187
|
description: "Composable SaaS accelerator kit.",
|
|
3886
4188
|
keywords: [
|
|
3887
4189
|
"saas",
|
|
@@ -4107,16 +4409,17 @@ function baseEntries(manifest) {
|
|
|
4107
4409
|
function recordBaseFiles(manifest, files) {
|
|
4108
4410
|
for (const [target, entry] of Object.entries(manifest.managed)) {
|
|
4109
4411
|
if (entry.module === BASE_MODULE) {
|
|
4110
|
-
|
|
4412
|
+
untrackManagedFile(manifest, target);
|
|
4111
4413
|
}
|
|
4112
4414
|
}
|
|
4113
4415
|
for (const file of files) {
|
|
4114
|
-
manifest
|
|
4115
|
-
|
|
4416
|
+
recordManagedFile(manifest, {
|
|
4417
|
+
adopted: file.adopted,
|
|
4418
|
+
from: file.from,
|
|
4116
4419
|
hash: file.hash,
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
};
|
|
4420
|
+
module: BASE_MODULE,
|
|
4421
|
+
target: file.target
|
|
4422
|
+
});
|
|
4120
4423
|
}
|
|
4121
4424
|
}
|
|
4122
4425
|
function isBaseTracked(lock, manifest) {
|
|
@@ -4250,7 +4553,7 @@ async function baseUpdateInput(args) {
|
|
|
4250
4553
|
|
|
4251
4554
|
// src/lib/doctor.ts
|
|
4252
4555
|
import { findNodeAtLocation as findNodeAtLocation4, getNodeValue as getNodeValue4, parseTree as parseTree4 } from "jsonc-parser";
|
|
4253
|
-
import { parseModule as
|
|
4556
|
+
import { parseModule as parseModule7 } from "magicast";
|
|
4254
4557
|
import { readFile as readFile13 } from "fs/promises";
|
|
4255
4558
|
import { basename, dirname as dirname6, join as join11, posix as posix7, resolve as resolve3 } from "path";
|
|
4256
4559
|
var SKILL_PREFIX = "saasaloy-";
|
|
@@ -4258,7 +4561,7 @@ var PINNED_DEP = /^(@[^/@]+\/)?[^/@]+@\d+\.\d+\.\d+(-[\w.-]+)?(\+[\w.-]+)?$/;
|
|
|
4258
4561
|
function finding(module, where, message) {
|
|
4259
4562
|
return { message, module, where };
|
|
4260
4563
|
}
|
|
4261
|
-
function
|
|
4564
|
+
function asArray2(value) {
|
|
4262
4565
|
return Array.isArray(value) ? value : [];
|
|
4263
4566
|
}
|
|
4264
4567
|
function asRecord(value) {
|
|
@@ -4282,7 +4585,7 @@ async function collectAliases(registryDir, names) {
|
|
|
4282
4585
|
const fromScaffolds = {};
|
|
4283
4586
|
for (const name of names) {
|
|
4284
4587
|
const item = asRecord(await readDescriptor(join11(registryDir, name)));
|
|
4285
|
-
for (const scaffold of
|
|
4588
|
+
for (const scaffold of asArray2(item.scaffolds)) {
|
|
4286
4589
|
const aliases = asRecord(asRecord(scaffold).aliases);
|
|
4287
4590
|
for (const [alias, prefix] of Object.entries(aliases)) {
|
|
4288
4591
|
if (typeof prefix === "string") {
|
|
@@ -4346,7 +4649,7 @@ async function checkModule(input) {
|
|
|
4346
4649
|
}
|
|
4347
4650
|
const known = { ...aliases.base, ...aliases.fromScaffolds };
|
|
4348
4651
|
const knownList = Object.keys(known).toSorted().join(", ") || "(none)";
|
|
4349
|
-
for (const [index, entry] of
|
|
4652
|
+
for (const [index, entry] of asArray2(item.files).entries()) {
|
|
4350
4653
|
await checkSourcePath(findings, module, dir, `/files/${index}/path`, entry);
|
|
4351
4654
|
const target = asRecord(entry).target;
|
|
4352
4655
|
const alias = typeof target === "string" ? target.split("/")[0] : void 0;
|
|
@@ -4360,8 +4663,8 @@ async function checkModule(input) {
|
|
|
4360
4663
|
);
|
|
4361
4664
|
}
|
|
4362
4665
|
}
|
|
4363
|
-
for (const [index, scaffold] of
|
|
4364
|
-
for (const [fileIndex, entry] of
|
|
4666
|
+
for (const [index, scaffold] of asArray2(item.scaffolds).entries()) {
|
|
4667
|
+
for (const [fileIndex, entry] of asArray2(
|
|
4365
4668
|
asRecord(scaffold).files
|
|
4366
4669
|
).entries()) {
|
|
4367
4670
|
await checkSourcePath(
|
|
@@ -4379,7 +4682,7 @@ async function checkModule(input) {
|
|
|
4379
4682
|
["requiresOneOf", item.requiresOneOf],
|
|
4380
4683
|
["conflictsWith", item.conflictsWith]
|
|
4381
4684
|
]) {
|
|
4382
|
-
for (const [index, name] of
|
|
4685
|
+
for (const [index, name] of asArray2(names).entries()) {
|
|
4383
4686
|
if (typeof name === "string" && !siblingSet.has(name)) {
|
|
4384
4687
|
findings.push(
|
|
4385
4688
|
finding(
|
|
@@ -4395,7 +4698,7 @@ async function checkModule(input) {
|
|
|
4395
4698
|
["dependencies", item.dependencies],
|
|
4396
4699
|
["devDependencies", item.devDependencies]
|
|
4397
4700
|
]) {
|
|
4398
|
-
for (const [index, dep] of
|
|
4701
|
+
for (const [index, dep] of asArray2(deps).entries()) {
|
|
4399
4702
|
if (typeof dep === "string" && !PINNED_DEP.test(dep)) {
|
|
4400
4703
|
findings.push(
|
|
4401
4704
|
finding(
|
|
@@ -4438,7 +4741,7 @@ async function checkModule(input) {
|
|
|
4438
4741
|
);
|
|
4439
4742
|
}
|
|
4440
4743
|
}
|
|
4441
|
-
for (const [index, skill] of
|
|
4744
|
+
for (const [index, skill] of asArray2(asRecord(item.agent).skills).entries()) {
|
|
4442
4745
|
if (typeof skill !== "string") {
|
|
4443
4746
|
continue;
|
|
4444
4747
|
}
|
|
@@ -4561,7 +4864,7 @@ function rateLimitBindingNames(wrangler) {
|
|
|
4561
4864
|
function registeredPolicies(args) {
|
|
4562
4865
|
let mod;
|
|
4563
4866
|
try {
|
|
4564
|
-
mod =
|
|
4867
|
+
mod = parseModule7(args.index);
|
|
4565
4868
|
} catch {
|
|
4566
4869
|
return [];
|
|
4567
4870
|
}
|
|
@@ -4609,7 +4912,7 @@ function calleeName(element) {
|
|
|
4609
4912
|
function policyNameIn(source, callee) {
|
|
4610
4913
|
let program;
|
|
4611
4914
|
try {
|
|
4612
|
-
program =
|
|
4915
|
+
program = parseModule7(source).$ast;
|
|
4613
4916
|
} catch {
|
|
4614
4917
|
return void 0;
|
|
4615
4918
|
}
|
|
@@ -4624,8 +4927,8 @@ function policyNameIn(source, callee) {
|
|
|
4624
4927
|
factory,
|
|
4625
4928
|
(node) => node.type === "CallExpression" && asRecord(node.callee).name === "definePolicy"
|
|
4626
4929
|
);
|
|
4627
|
-
const argument =
|
|
4628
|
-
const property =
|
|
4930
|
+
const argument = asArray2(call?.arguments)[0];
|
|
4931
|
+
const property = asArray2(asRecord(argument).properties).find(
|
|
4629
4932
|
(entry) => asRecord(asRecord(entry).key).name === "name"
|
|
4630
4933
|
);
|
|
4631
4934
|
const value = asRecord(asRecord(property).value).value;
|
|
@@ -4688,7 +4991,7 @@ async function readPolicyState(root, installed) {
|
|
|
4688
4991
|
function relativeImportsIn(index) {
|
|
4689
4992
|
let mod;
|
|
4690
4993
|
try {
|
|
4691
|
-
mod =
|
|
4994
|
+
mod = parseModule7(index);
|
|
4692
4995
|
} catch {
|
|
4693
4996
|
return [];
|
|
4694
4997
|
}
|
|
@@ -6552,7 +6855,7 @@ async function executeRemovePlan(plan, args) {
|
|
|
6552
6855
|
} else {
|
|
6553
6856
|
missingUntracked.push(file);
|
|
6554
6857
|
}
|
|
6555
|
-
|
|
6858
|
+
untrackManagedFile(manifest, file.target);
|
|
6556
6859
|
}
|
|
6557
6860
|
const linksRemoved = [];
|
|
6558
6861
|
const linkConflicts = [];
|
|
@@ -6568,7 +6871,7 @@ async function executeRemovePlan(plan, args) {
|
|
|
6568
6871
|
} else if (link.action === "conflict") {
|
|
6569
6872
|
linkConflicts.push(link);
|
|
6570
6873
|
}
|
|
6571
|
-
|
|
6874
|
+
untrackLink(manifest, link.target);
|
|
6572
6875
|
}
|
|
6573
6876
|
const patchesReversed = [];
|
|
6574
6877
|
const patchesDropped = [];
|
|
@@ -6591,9 +6894,7 @@ async function executeRemovePlan(plan, args) {
|
|
|
6591
6894
|
}
|
|
6592
6895
|
}
|
|
6593
6896
|
(reversed ? patchesReversed : patchesDropped).push(entry);
|
|
6594
|
-
manifest
|
|
6595
|
-
(p) => !samePatchEntry(p, entry)
|
|
6596
|
-
);
|
|
6897
|
+
untrackPatch(manifest, entry);
|
|
6597
6898
|
}
|
|
6598
6899
|
const prunedDirs = await pruneEmptyDirs(root, [
|
|
6599
6900
|
...deleted.map((f) => f.targetAbs),
|
|
@@ -7173,11 +7474,12 @@ async function executeUpdatePlan(plan, args) {
|
|
|
7173
7474
|
await writeFile11(file.targetAbs, file.theirs, "utf-8");
|
|
7174
7475
|
result.written.push(file);
|
|
7175
7476
|
}
|
|
7176
|
-
manifest
|
|
7177
|
-
|
|
7477
|
+
recordManagedFile(manifest, {
|
|
7478
|
+
from: file.from,
|
|
7178
7479
|
hash: file.newHash ?? hashContent(file.theirs),
|
|
7179
|
-
|
|
7180
|
-
|
|
7480
|
+
module: file.module,
|
|
7481
|
+
target: file.target
|
|
7482
|
+
});
|
|
7181
7483
|
}
|
|
7182
7484
|
for (const file of mod.removals) {
|
|
7183
7485
|
if (file.action === "delete") {
|
|
@@ -7193,7 +7495,7 @@ async function executeUpdatePlan(plan, args) {
|
|
|
7193
7495
|
} else {
|
|
7194
7496
|
result.untracked.push(file);
|
|
7195
7497
|
}
|
|
7196
|
-
|
|
7498
|
+
untrackManagedFile(manifest, file.target);
|
|
7197
7499
|
}
|
|
7198
7500
|
for (const p of mod.patches) {
|
|
7199
7501
|
if (!await pathExists(p.fileAbs)) {
|
|
@@ -7208,14 +7510,11 @@ async function executeUpdatePlan(plan, args) {
|
|
|
7208
7510
|
}
|
|
7209
7511
|
await writeFile11(p.fileAbs, content, "utf-8");
|
|
7210
7512
|
result.patched.push(p);
|
|
7211
|
-
|
|
7212
|
-
module: p.module,
|
|
7513
|
+
recordPatch(manifest, {
|
|
7213
7514
|
file: p.file,
|
|
7515
|
+
module: p.module,
|
|
7214
7516
|
patch: p.patch
|
|
7215
|
-
};
|
|
7216
|
-
if (!manifest.patches.some((existing) => samePatchEntry(existing, entry))) {
|
|
7217
|
-
manifest.patches.push(entry);
|
|
7218
|
-
}
|
|
7517
|
+
});
|
|
7219
7518
|
}
|
|
7220
7519
|
for (const link of mod.links) {
|
|
7221
7520
|
if (link.action === "conflict") {
|
|
@@ -7225,7 +7524,7 @@ async function executeUpdatePlan(plan, args) {
|
|
|
7225
7524
|
if (link.action === "create") {
|
|
7226
7525
|
await createDirLink(link.pathAbs, link.targetAbs);
|
|
7227
7526
|
}
|
|
7228
|
-
manifest
|
|
7527
|
+
recordLink(manifest, link.target, link.path);
|
|
7229
7528
|
result.links.push(link);
|
|
7230
7529
|
}
|
|
7231
7530
|
for (const bump of mod.depBumps) {
|
|
@@ -7737,6 +8036,7 @@ async function runRemove(argv) {
|
|
|
7737
8036
|
}
|
|
7738
8037
|
}
|
|
7739
8038
|
let result;
|
|
8039
|
+
let ledgerFailures = [];
|
|
7740
8040
|
try {
|
|
7741
8041
|
result = await executeRemovePlan(plan, {
|
|
7742
8042
|
root,
|
|
@@ -7746,9 +8046,11 @@ async function runRemove(argv) {
|
|
|
7746
8046
|
deleteDrifted
|
|
7747
8047
|
});
|
|
7748
8048
|
} finally {
|
|
7749
|
-
await
|
|
7750
|
-
|
|
7751
|
-
|
|
8049
|
+
ledgerFailures = await persistLedger({ config, lock, manifest, root });
|
|
8050
|
+
}
|
|
8051
|
+
const failedSave = ledgerFailures[0];
|
|
8052
|
+
if (failedSave) {
|
|
8053
|
+
throw failedSave.error;
|
|
7752
8054
|
}
|
|
7753
8055
|
for (const file of result.deleted) {
|
|
7754
8056
|
log6.step(`${pc10.red("delete")} ${file.target}`);
|
|
@@ -8705,7 +9007,11 @@ async function runUpdate(argv) {
|
|
|
8705
9007
|
const skipped = comparisons.filter((c) => c.status !== "outdated");
|
|
8706
9008
|
if (outdated.length === 0) {
|
|
8707
9009
|
if (!preview && recordRefRewrites(lock, comparisons).length > 0) {
|
|
8708
|
-
await
|
|
9010
|
+
const failures2 = await persistLedger({ config, lock, manifest, root });
|
|
9011
|
+
const failedSave2 = failures2[0];
|
|
9012
|
+
if (failedSave2) {
|
|
9013
|
+
throw failedSave2.error;
|
|
9014
|
+
}
|
|
8709
9015
|
}
|
|
8710
9016
|
for (const comparison of skipped) {
|
|
8711
9017
|
log7.info(
|
|
@@ -8932,17 +9238,13 @@ async function runUpdate(argv) {
|
|
|
8932
9238
|
(value) => ({ ok: true, value }),
|
|
8933
9239
|
(error) => ({ ok: false, error })
|
|
8934
9240
|
);
|
|
8935
|
-
const
|
|
8936
|
-
saveManifest(root, manifest),
|
|
8937
|
-
saveConfig(root, config),
|
|
8938
|
-
saveLock(root, lock)
|
|
8939
|
-
]);
|
|
9241
|
+
const failures = await persistLedger({ config, lock, manifest, root });
|
|
8940
9242
|
if (!outcome.ok) {
|
|
8941
9243
|
throw outcome.error;
|
|
8942
9244
|
}
|
|
8943
|
-
const failedSave =
|
|
9245
|
+
const failedSave = failures[0];
|
|
8944
9246
|
if (failedSave) {
|
|
8945
|
-
throw failedSave.
|
|
9247
|
+
throw failedSave.error;
|
|
8946
9248
|
}
|
|
8947
9249
|
const result = outcome.value;
|
|
8948
9250
|
reportResult(result);
|