@suss/extractor 0.34.1 → 0.35.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.cjs +786 -178
- package/dist/index.d.cts +97 -15
- package/dist/index.d.ts +97 -15
- package/dist/index.js +779 -174
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { createHash as
|
|
2
|
+
import { createHash as createHash7 } from "crypto";
|
|
3
3
|
import {
|
|
4
4
|
effectKey,
|
|
5
5
|
exchangesHttpResponses as exchangesHttpResponses2,
|
|
@@ -571,7 +571,7 @@ function splitAtHandOffs(branch, sites, from = 0) {
|
|
|
571
571
|
continue;
|
|
572
572
|
}
|
|
573
573
|
return throughHelper(branch, site.at, site.helper).flatMap(
|
|
574
|
-
(
|
|
574
|
+
(path10) => path10.terminal === branch.terminal ? splitAtHandOffs(path10, sites, index + 1) : [path10]
|
|
575
575
|
);
|
|
576
576
|
}
|
|
577
577
|
return [branch];
|
|
@@ -619,12 +619,12 @@ function rootName(ref) {
|
|
|
619
619
|
}
|
|
620
620
|
|
|
621
621
|
// src/moduleImports.ts
|
|
622
|
-
function stampModuleImports(summaries,
|
|
622
|
+
function stampModuleImports(summaries, importsOf2) {
|
|
623
623
|
const byFile = /* @__PURE__ */ new Map();
|
|
624
624
|
for (const summary of summaries) {
|
|
625
625
|
const file = summary.location.file;
|
|
626
626
|
if (!byFile.has(file)) {
|
|
627
|
-
const found =
|
|
627
|
+
const found = importsOf2(file);
|
|
628
628
|
byFile.set(
|
|
629
629
|
file,
|
|
630
630
|
found === void 0 ? void 0 : [...new Set(found)].sort()
|
|
@@ -919,8 +919,8 @@ var catchEntryCond = () => fixedCond(
|
|
|
919
919
|
"positive",
|
|
920
920
|
"catchBlock"
|
|
921
921
|
);
|
|
922
|
-
function classify(
|
|
923
|
-
return
|
|
922
|
+
function classify(path10, home, isAncestorOrSelf) {
|
|
923
|
+
return path10.map((cond) => {
|
|
924
924
|
if (cond.branchStmt === null) {
|
|
925
925
|
return cond.info;
|
|
926
926
|
}
|
|
@@ -992,9 +992,9 @@ function limitOpenPaths(paths) {
|
|
|
992
992
|
);
|
|
993
993
|
}
|
|
994
994
|
}
|
|
995
|
-
function recordTerminal(ctx, terminal, home,
|
|
995
|
+
function recordTerminal(ctx, terminal, home, path10) {
|
|
996
996
|
chargeBudget(ctx.state);
|
|
997
|
-
const info = classify(
|
|
997
|
+
const info = classify(path10, home, ctx.isAncestorOrSelf);
|
|
998
998
|
const existing = ctx.state.byTerminal.get(terminal) ?? [];
|
|
999
999
|
existing.push(info);
|
|
1000
1000
|
ctx.state.byTerminal.set(terminal, existing);
|
|
@@ -1005,15 +1005,15 @@ function containsTerminal(ctx, stmt) {
|
|
|
1005
1005
|
}
|
|
1006
1006
|
return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
|
|
1007
1007
|
}
|
|
1008
|
-
function stepIf(stmt,
|
|
1008
|
+
function stepIf(stmt, path10, ctx) {
|
|
1009
1009
|
const thenExit = exitKindOfList(stmt.thenBody);
|
|
1010
1010
|
const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
|
|
1011
1011
|
const thenPath = [
|
|
1012
|
-
...
|
|
1012
|
+
...path10,
|
|
1013
1013
|
branchCond(stmt, stmt.condition, "positive", elseExit)
|
|
1014
1014
|
];
|
|
1015
1015
|
const elsePath = [
|
|
1016
|
-
...
|
|
1016
|
+
...path10,
|
|
1017
1017
|
branchCond(
|
|
1018
1018
|
stmt,
|
|
1019
1019
|
stmt.condition,
|
|
@@ -1030,7 +1030,7 @@ function stepIf(stmt, path7, ctx) {
|
|
|
1030
1030
|
}
|
|
1031
1031
|
return out;
|
|
1032
1032
|
}
|
|
1033
|
-
function stepSwitch(stmt,
|
|
1033
|
+
function stepSwitch(stmt, path10, ctx) {
|
|
1034
1034
|
const out = [];
|
|
1035
1035
|
const negations = [];
|
|
1036
1036
|
let defaultRanBody = false;
|
|
@@ -1040,7 +1040,7 @@ function stepSwitch(stmt, path7, ctx) {
|
|
|
1040
1040
|
if (hasStrayBreak(group.body)) {
|
|
1041
1041
|
throw new UnmodeledFlow("non-trailing break in switch clause");
|
|
1042
1042
|
}
|
|
1043
|
-
const groupPath = group.condition === null ? [...
|
|
1043
|
+
const groupPath = group.condition === null ? [...path10, ...negations] : [...path10, fixedCond(group.condition, "positive", "explicit")];
|
|
1044
1044
|
const conts = enumerate(ctx, group.body, groupPath);
|
|
1045
1045
|
if (conts.length > 0) {
|
|
1046
1046
|
if (!group.hasTrailingBreak && !fallthroughSafe) {
|
|
@@ -1057,24 +1057,24 @@ function stepSwitch(stmt, path7, ctx) {
|
|
|
1057
1057
|
}
|
|
1058
1058
|
}
|
|
1059
1059
|
if (!defaultRanBody) {
|
|
1060
|
-
out.push([...
|
|
1060
|
+
out.push([...path10, ...negations]);
|
|
1061
1061
|
}
|
|
1062
1062
|
return out;
|
|
1063
1063
|
}
|
|
1064
|
-
function stepLoop(stmt,
|
|
1064
|
+
function stepLoop(stmt, path10, ctx) {
|
|
1065
1065
|
const bodyExit = exitKindOfList(stmt.body);
|
|
1066
1066
|
if (containsTerminal(ctx, stmt)) {
|
|
1067
1067
|
enumerate(ctx, stmt.body, [
|
|
1068
|
-
...
|
|
1068
|
+
...path10,
|
|
1069
1069
|
loopIterationCond(stmt.condition.sourceText)
|
|
1070
1070
|
]);
|
|
1071
1071
|
}
|
|
1072
1072
|
if (bodyExit !== null) {
|
|
1073
|
-
return [[...
|
|
1073
|
+
return [[...path10, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
|
|
1074
1074
|
}
|
|
1075
|
-
return [
|
|
1075
|
+
return [path10];
|
|
1076
1076
|
}
|
|
1077
|
-
function stepTry(stmt,
|
|
1077
|
+
function stepTry(stmt, path10, ctx) {
|
|
1078
1078
|
if (stmt.finallyBody !== null) {
|
|
1079
1079
|
const finallyHasTerminal = stmt.finallyBody.some(
|
|
1080
1080
|
(s) => containsTerminal(ctx, s)
|
|
@@ -1084,22 +1084,22 @@ function stepTry(stmt, path7, ctx) {
|
|
|
1084
1084
|
}
|
|
1085
1085
|
}
|
|
1086
1086
|
const out = [];
|
|
1087
|
-
out.push(...enumerate(ctx, stmt.tryBody,
|
|
1087
|
+
out.push(...enumerate(ctx, stmt.tryBody, path10));
|
|
1088
1088
|
if (stmt.catchBody !== null) {
|
|
1089
|
-
const catchPath = [...
|
|
1089
|
+
const catchPath = [...path10, catchEntryCond()];
|
|
1090
1090
|
out.push(...enumerate(ctx, stmt.catchBody, catchPath));
|
|
1091
1091
|
}
|
|
1092
1092
|
return out;
|
|
1093
1093
|
}
|
|
1094
|
-
function stepExit(stmt,
|
|
1094
|
+
function stepExit(stmt, path10, ctx) {
|
|
1095
1095
|
const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
|
|
1096
1096
|
if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
|
|
1097
|
-
collector.push(
|
|
1097
|
+
collector.push(path10);
|
|
1098
1098
|
}
|
|
1099
1099
|
return [];
|
|
1100
1100
|
}
|
|
1101
|
-
function stepOpaque(_stmt,
|
|
1102
|
-
return [
|
|
1101
|
+
function stepOpaque(_stmt, path10, _ctx) {
|
|
1102
|
+
return [path10];
|
|
1103
1103
|
}
|
|
1104
1104
|
var stepHandlers = {
|
|
1105
1105
|
if: stepIf,
|
|
@@ -1109,20 +1109,20 @@ var stepHandlers = {
|
|
|
1109
1109
|
exit: stepExit,
|
|
1110
1110
|
opaque: stepOpaque
|
|
1111
1111
|
};
|
|
1112
|
-
function stepCallback(ctx, body,
|
|
1112
|
+
function stepCallback(ctx, body, path10) {
|
|
1113
1113
|
const exits = [];
|
|
1114
1114
|
ctx.state.callbackExits.push(exits);
|
|
1115
1115
|
let fellThrough;
|
|
1116
1116
|
try {
|
|
1117
|
-
fellThrough = enumerate(ctx, body,
|
|
1117
|
+
fellThrough = enumerate(ctx, body, path10);
|
|
1118
1118
|
} finally {
|
|
1119
1119
|
ctx.state.callbackExits.pop();
|
|
1120
1120
|
}
|
|
1121
1121
|
const out = [...fellThrough, ...exits];
|
|
1122
|
-
return out.length === 0 ? [
|
|
1122
|
+
return out.length === 0 ? [path10] : out;
|
|
1123
1123
|
}
|
|
1124
|
-
function stepStatement(ctx, stmt,
|
|
1125
|
-
let paths = [
|
|
1124
|
+
function stepStatement(ctx, stmt, path10) {
|
|
1125
|
+
let paths = [path10];
|
|
1126
1126
|
for (const body of stmt.callbacks ?? []) {
|
|
1127
1127
|
paths = paths.flatMap((each) => stepCallback(ctx, body, each));
|
|
1128
1128
|
limitOpenPaths(paths);
|
|
@@ -1209,8 +1209,8 @@ function enumerate(ctx, stmts, prefix) {
|
|
|
1209
1209
|
let frontiers = [[...prefix]];
|
|
1210
1210
|
for (const stmt of stmts) {
|
|
1211
1211
|
const nextFrontiers = [];
|
|
1212
|
-
for (const
|
|
1213
|
-
nextFrontiers.push(...stepStatement(ctx, stmt,
|
|
1212
|
+
for (const path10 of mergeRejoined(frontiers, ctx.keepsArms)) {
|
|
1213
|
+
nextFrontiers.push(...stepStatement(ctx, stmt, path10));
|
|
1214
1214
|
}
|
|
1215
1215
|
frontiers = nextFrontiers;
|
|
1216
1216
|
limitOpenPaths(frontiers);
|
|
@@ -1259,9 +1259,9 @@ function enumerateStructuredPaths(input) {
|
|
|
1259
1259
|
isAncestorOrSelf
|
|
1260
1260
|
};
|
|
1261
1261
|
const continuations = withRejoined(enumerate(ctx, input.statements, []));
|
|
1262
|
-
for (const
|
|
1262
|
+
for (const path10 of continuations) {
|
|
1263
1263
|
chargeBudget(state);
|
|
1264
|
-
state.fallthrough.push(classify(
|
|
1264
|
+
state.fallthrough.push(classify(path10, null, isAncestorOrSelf));
|
|
1265
1265
|
}
|
|
1266
1266
|
return { byTerminal: state.byTerminal, fallthrough: state.fallthrough };
|
|
1267
1267
|
}
|
|
@@ -1304,8 +1304,8 @@ function sharedGatingConditions(paths, readPredicate) {
|
|
|
1304
1304
|
return [];
|
|
1305
1305
|
}
|
|
1306
1306
|
const shared = new Set(first.map(keyOf2));
|
|
1307
|
-
for (const
|
|
1308
|
-
const here = new Set(
|
|
1307
|
+
for (const path10 of rest) {
|
|
1308
|
+
const here = new Set(path10.map(keyOf2));
|
|
1309
1309
|
for (const value of shared) {
|
|
1310
1310
|
if (!here.has(value)) {
|
|
1311
1311
|
shared.delete(value);
|
|
@@ -1571,17 +1571,179 @@ function quoted(text, key) {
|
|
|
1571
1571
|
}
|
|
1572
1572
|
|
|
1573
1573
|
// src/adapterStamp.ts
|
|
1574
|
+
import { createHash as createHash2 } from "crypto";
|
|
1575
|
+
import fs3 from "fs";
|
|
1576
|
+
import path5 from "path";
|
|
1577
|
+
import { fileURLToPath } from "url";
|
|
1578
|
+
|
|
1579
|
+
// src/codeHash.ts
|
|
1574
1580
|
import { createHash } from "crypto";
|
|
1575
1581
|
import fs2 from "fs";
|
|
1576
1582
|
import { createRequire } from "module";
|
|
1577
1583
|
import path4 from "path";
|
|
1578
|
-
|
|
1579
|
-
var
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1584
|
+
var SUSS_SCOPE = "@suss/";
|
|
1585
|
+
var IMPORT_FORMS = /\b(?:from|import)\s*\(?\s*["']([^"'\s]+)["']|require\s*\(\s*["']([^"'\s]+)["']/g;
|
|
1586
|
+
var CONDITIONS = {
|
|
1587
|
+
import: /* @__PURE__ */ new Set(["import", "node", "default"]),
|
|
1588
|
+
require: /* @__PURE__ */ new Set(["require", "node", "default"])
|
|
1589
|
+
};
|
|
1590
|
+
function createCodeHasher() {
|
|
1591
|
+
const read = /* @__PURE__ */ new Map();
|
|
1592
|
+
function readOnce(file) {
|
|
1593
|
+
const known = read.get(file);
|
|
1594
|
+
if (known !== void 0) {
|
|
1595
|
+
return known;
|
|
1596
|
+
}
|
|
1597
|
+
const found = readCodeFile(file);
|
|
1598
|
+
read.set(file, found);
|
|
1599
|
+
return found;
|
|
1600
|
+
}
|
|
1601
|
+
function codeFiles(entryFile) {
|
|
1602
|
+
const entry = realFile(entryFile);
|
|
1603
|
+
if (entry === null || readOnce(entry) === null) {
|
|
1604
|
+
return [];
|
|
1605
|
+
}
|
|
1606
|
+
const found = [entry];
|
|
1607
|
+
const seen = new Set(found);
|
|
1608
|
+
for (let at = 0; at < found.length; at++) {
|
|
1609
|
+
for (const next of readOnce(found[at])?.imports ?? []) {
|
|
1610
|
+
if (seen.has(next)) {
|
|
1611
|
+
continue;
|
|
1612
|
+
}
|
|
1613
|
+
seen.add(next);
|
|
1614
|
+
if (readOnce(next) !== null) {
|
|
1615
|
+
found.push(next);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
return found;
|
|
1620
|
+
}
|
|
1621
|
+
function codeHash(entryFile) {
|
|
1622
|
+
const files = codeFiles(entryFile);
|
|
1623
|
+
if (files.length === 0) {
|
|
1624
|
+
return "";
|
|
1625
|
+
}
|
|
1626
|
+
const hash = createHash("sha256");
|
|
1627
|
+
for (const file of files) {
|
|
1628
|
+
hash.update(read.get(file)?.digest ?? "");
|
|
1629
|
+
}
|
|
1630
|
+
return hash.digest("hex").slice(0, 16);
|
|
1631
|
+
}
|
|
1632
|
+
return { codeFiles, codeHash };
|
|
1633
|
+
}
|
|
1634
|
+
var processCodeHasher = createCodeHasher();
|
|
1635
|
+
function readCodeFile(file) {
|
|
1636
|
+
let text;
|
|
1637
|
+
try {
|
|
1638
|
+
text = fs2.readFileSync(file);
|
|
1639
|
+
} catch {
|
|
1640
|
+
return null;
|
|
1641
|
+
}
|
|
1642
|
+
return {
|
|
1643
|
+
digest: createHash("sha256").update(text).digest("hex"),
|
|
1644
|
+
imports: importsOf(file, text.toString("utf8"))
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
function importsOf(file, text) {
|
|
1648
|
+
const asked = /* @__PURE__ */ new Set();
|
|
1649
|
+
const found = [];
|
|
1650
|
+
for (const match of text.matchAll(IMPORT_FORMS)) {
|
|
1651
|
+
const kind = match[1] === void 0 ? "require" : "import";
|
|
1652
|
+
const specifier = match[1] ?? match[2] ?? "";
|
|
1653
|
+
if (asked.has(`${kind} ${specifier}`)) {
|
|
1654
|
+
continue;
|
|
1655
|
+
}
|
|
1656
|
+
asked.add(`${kind} ${specifier}`);
|
|
1657
|
+
const target = resolveImport(specifier, file, kind);
|
|
1658
|
+
if (target !== null) {
|
|
1659
|
+
found.push(target);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
return found;
|
|
1663
|
+
}
|
|
1664
|
+
function resolveImport(specifier, fromFile, kind) {
|
|
1665
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
1666
|
+
return realFile(path4.resolve(path4.dirname(fromFile), specifier));
|
|
1667
|
+
}
|
|
1668
|
+
if (specifier.startsWith(SUSS_SCOPE)) {
|
|
1669
|
+
return resolvePackageImport(specifier, fromFile, kind);
|
|
1670
|
+
}
|
|
1671
|
+
return null;
|
|
1672
|
+
}
|
|
1673
|
+
function resolvePackageImport(specifier, fromFile, kind) {
|
|
1674
|
+
const [scope = "", name = "", ...rest] = specifier.split("/");
|
|
1675
|
+
const packageName = `${scope}/${name}`;
|
|
1676
|
+
const subpath = rest.length === 0 ? "." : `./${rest.join("/")}`;
|
|
1677
|
+
const lookIn = createRequire(fromFile).resolve.paths(packageName) ?? [];
|
|
1678
|
+
for (const dir of lookIn) {
|
|
1679
|
+
const packageDir = path4.join(dir, packageName);
|
|
1680
|
+
const manifest = readManifest(packageDir);
|
|
1681
|
+
if (manifest === null) {
|
|
1682
|
+
continue;
|
|
1683
|
+
}
|
|
1684
|
+
const target = exportTarget(manifest, subpath, CONDITIONS[kind]);
|
|
1685
|
+
return target === null ? null : realFile(path4.join(packageDir, target));
|
|
1686
|
+
}
|
|
1687
|
+
return null;
|
|
1688
|
+
}
|
|
1689
|
+
function readManifest(packageDir) {
|
|
1690
|
+
try {
|
|
1691
|
+
return JSON.parse(
|
|
1692
|
+
fs2.readFileSync(path4.join(packageDir, "package.json"), "utf8")
|
|
1693
|
+
);
|
|
1694
|
+
} catch {
|
|
1695
|
+
return null;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
function exportTarget(manifest, subpath, conditions) {
|
|
1699
|
+
if (manifest.exports === void 0) {
|
|
1700
|
+
return subpath === "." ? manifest.main ?? "index.js" : subpath;
|
|
1701
|
+
}
|
|
1702
|
+
return conditionalTarget(subpathEntry(manifest.exports, subpath), conditions);
|
|
1703
|
+
}
|
|
1704
|
+
function subpathEntry(exportsField, subpath) {
|
|
1705
|
+
const isSubpathMap = typeof exportsField === "object" && exportsField !== null && !Array.isArray(exportsField) && Object.keys(exportsField).some((key) => key.startsWith("."));
|
|
1706
|
+
if (isSubpathMap) {
|
|
1707
|
+
return exportsField[subpath];
|
|
1708
|
+
}
|
|
1709
|
+
return subpath === "." ? exportsField : void 0;
|
|
1710
|
+
}
|
|
1711
|
+
function conditionalTarget(value, conditions) {
|
|
1712
|
+
if (typeof value === "string") {
|
|
1713
|
+
return value;
|
|
1714
|
+
}
|
|
1715
|
+
if (Array.isArray(value)) {
|
|
1716
|
+
for (const each of value) {
|
|
1717
|
+
const found = conditionalTarget(each, conditions);
|
|
1718
|
+
if (found !== null) {
|
|
1719
|
+
return found;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
return null;
|
|
1723
|
+
}
|
|
1724
|
+
if (value === null || typeof value !== "object") {
|
|
1725
|
+
return null;
|
|
1726
|
+
}
|
|
1727
|
+
for (const [condition, target] of Object.entries(value)) {
|
|
1728
|
+
if (!conditions.has(condition)) {
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1731
|
+
const found = conditionalTarget(target, conditions);
|
|
1732
|
+
if (found !== null) {
|
|
1733
|
+
return found;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return null;
|
|
1737
|
+
}
|
|
1738
|
+
function realFile(file) {
|
|
1739
|
+
try {
|
|
1740
|
+
return fs2.realpathSync(file);
|
|
1741
|
+
} catch {
|
|
1742
|
+
return null;
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
// src/adapterStamp.ts
|
|
1585
1747
|
var SOURCE_STAMP = { kind: "source" };
|
|
1586
1748
|
function createAdapterStamp(config) {
|
|
1587
1749
|
let cachedCodeStamp = null;
|
|
@@ -1616,19 +1778,19 @@ function createAdapterStamp(config) {
|
|
|
1616
1778
|
function readAdapterCodeStamp(moduleUrl) {
|
|
1617
1779
|
try {
|
|
1618
1780
|
const selfPath = fileURLToPath(moduleUrl);
|
|
1619
|
-
const hash = computeDistHashFrom(
|
|
1781
|
+
const hash = computeDistHashFrom(path5.dirname(selfPath), processCodeHasher);
|
|
1620
1782
|
return hash.length > 0 ? { kind: "bundle", hash } : SOURCE_STAMP;
|
|
1621
1783
|
} catch {
|
|
1622
1784
|
return SOURCE_STAMP;
|
|
1623
1785
|
}
|
|
1624
1786
|
}
|
|
1625
|
-
function computeDistHashFrom(dir) {
|
|
1626
|
-
const candidates = [
|
|
1787
|
+
function computeDistHashFrom(dir, hasher = createCodeHasher()) {
|
|
1788
|
+
const candidates = [path5.join(dir, "index.js"), path5.join(dir, "index.cjs")];
|
|
1627
1789
|
for (const candidate of candidates) {
|
|
1628
|
-
if (!
|
|
1790
|
+
if (!fs3.existsSync(candidate)) {
|
|
1629
1791
|
continue;
|
|
1630
1792
|
}
|
|
1631
|
-
return
|
|
1793
|
+
return hasher.codeHash(candidate);
|
|
1632
1794
|
}
|
|
1633
1795
|
return "";
|
|
1634
1796
|
}
|
|
@@ -1636,10 +1798,10 @@ function computeContentHash(paths) {
|
|
|
1636
1798
|
if (paths.length === 0) {
|
|
1637
1799
|
return "";
|
|
1638
1800
|
}
|
|
1639
|
-
const hash =
|
|
1801
|
+
const hash = createHash2("sha256");
|
|
1640
1802
|
for (const file of paths) {
|
|
1641
1803
|
try {
|
|
1642
|
-
hash.update(
|
|
1804
|
+
hash.update(fs3.readFileSync(file));
|
|
1643
1805
|
} catch {
|
|
1644
1806
|
return "";
|
|
1645
1807
|
}
|
|
@@ -1650,12 +1812,12 @@ function projectFileStamp(paths) {
|
|
|
1650
1812
|
if (paths.length === 0) {
|
|
1651
1813
|
return "none";
|
|
1652
1814
|
}
|
|
1653
|
-
const hash =
|
|
1815
|
+
const hash = createHash2("sha256");
|
|
1654
1816
|
for (const file of [...paths].sort()) {
|
|
1655
1817
|
hash.update(file);
|
|
1656
1818
|
hash.update("\0");
|
|
1657
1819
|
try {
|
|
1658
|
-
hash.update(
|
|
1820
|
+
hash.update(fs3.readFileSync(file));
|
|
1659
1821
|
} catch {
|
|
1660
1822
|
hash.update("absent");
|
|
1661
1823
|
}
|
|
@@ -1668,7 +1830,7 @@ function extractionConfigStamp(config) {
|
|
|
1668
1830
|
["includeReachable", optionalText(config.includeReachable)],
|
|
1669
1831
|
["workspaceRoot", config.workspaceRoot],
|
|
1670
1832
|
["projectRoot", config.projectRoot],
|
|
1671
|
-
["importRoots", config.importRoots?.join(
|
|
1833
|
+
["importRoots", config.importRoots?.join(path5.delimiter)],
|
|
1672
1834
|
["modules", modulesStamp(config.modules)],
|
|
1673
1835
|
["walkedDirectory", config.walkedDirectory]
|
|
1674
1836
|
];
|
|
@@ -1683,27 +1845,288 @@ function runDigest(packsDigest, packs, files) {
|
|
|
1683
1845
|
const inputs = packs.flatMap((pack) => pack.discoveryInputs?.(files) ?? []);
|
|
1684
1846
|
return `${packsDigest}|reads:${projectFileStamp(inputs)}`;
|
|
1685
1847
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1848
|
+
|
|
1849
|
+
// src/cache.ts
|
|
1850
|
+
import { createHash as createHash5 } from "crypto";
|
|
1851
|
+
import fs7 from "fs/promises";
|
|
1852
|
+
import path8 from "path";
|
|
1853
|
+
import { readJsonFile as readJsonFile3, writeDocumentFile as writeDocumentFile2 } from "@suss/behavioral-ir/files";
|
|
1854
|
+
|
|
1855
|
+
// src/cacheIndex.ts
|
|
1856
|
+
import { BOUNDARY_ROLE, displayLabel } from "@suss/behavioral-ir";
|
|
1857
|
+
import { readJsonFile, writeDocumentFile } from "@suss/behavioral-ir/files";
|
|
1858
|
+
function entriesOf(units) {
|
|
1859
|
+
const boundaries = [];
|
|
1860
|
+
const callees = [];
|
|
1861
|
+
units.forEach((summary, unit) => {
|
|
1862
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1863
|
+
const add = (key, role) => {
|
|
1864
|
+
if (key !== null && !seen.has(`${role} ${key}`)) {
|
|
1865
|
+
seen.add(`${role} ${key}`);
|
|
1866
|
+
boundaries.push([key, unit, role]);
|
|
1867
|
+
}
|
|
1868
|
+
};
|
|
1869
|
+
const own = summary.identity?.boundaryBinding ?? null;
|
|
1870
|
+
if (own !== null) {
|
|
1871
|
+
add(
|
|
1872
|
+
keyOf3(own),
|
|
1873
|
+
BOUNDARY_ROLE[summary.kind] === "provider" ? "serves" : "calls"
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1876
|
+
const spellings = /* @__PURE__ */ new Set();
|
|
1877
|
+
for (const transition of summary.transitions ?? []) {
|
|
1878
|
+
for (const effect of transition.effects ?? []) {
|
|
1879
|
+
if (effect.type === "interaction") {
|
|
1880
|
+
add(keyOf3(effect.binding), "calls");
|
|
1881
|
+
}
|
|
1882
|
+
if (effect.type === "invocation") {
|
|
1883
|
+
spellings.add(effect.callee);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
for (const spelling of spellings) {
|
|
1888
|
+
callees.push([spelling, unit]);
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1891
|
+
return { boundaries, callees };
|
|
1892
|
+
}
|
|
1893
|
+
function indexOf(shards) {
|
|
1894
|
+
const boundaries = {};
|
|
1895
|
+
const callees = {};
|
|
1896
|
+
shards.forEach(({ entries }, file) => {
|
|
1897
|
+
for (const [key, unit, role] of entries.boundaries) {
|
|
1898
|
+
listAt(boundaries, key).push([file, unit, role]);
|
|
1899
|
+
}
|
|
1900
|
+
for (const [spelling, unit] of entries.callees) {
|
|
1901
|
+
listAt(callees, spelling).push([file, unit]);
|
|
1902
|
+
}
|
|
1903
|
+
});
|
|
1904
|
+
return {
|
|
1905
|
+
files: shards.map(({ file, id }) => [file, id]),
|
|
1906
|
+
boundaries,
|
|
1907
|
+
callees
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
function listAt(record, key) {
|
|
1911
|
+
const existing = Object.hasOwn(record, key) ? record[key] : void 0;
|
|
1912
|
+
if (existing !== void 0) {
|
|
1913
|
+
return existing;
|
|
1914
|
+
}
|
|
1915
|
+
const created = [];
|
|
1916
|
+
record[key] = created;
|
|
1917
|
+
return created;
|
|
1918
|
+
}
|
|
1919
|
+
function entriesByShard(index) {
|
|
1920
|
+
const byShard = /* @__PURE__ */ new Map();
|
|
1921
|
+
const at = index.files.map(([, id]) => {
|
|
1922
|
+
const entries = { boundaries: [], callees: [] };
|
|
1923
|
+
byShard.set(id, entries);
|
|
1924
|
+
return entries;
|
|
1925
|
+
});
|
|
1926
|
+
for (const [key, units] of Object.entries(index.boundaries)) {
|
|
1927
|
+
for (const [file, unit, role] of units) {
|
|
1928
|
+
at[file]?.boundaries.push([key, unit, role]);
|
|
1693
1929
|
}
|
|
1694
1930
|
}
|
|
1695
|
-
|
|
1931
|
+
for (const [spelling, units] of Object.entries(index.callees)) {
|
|
1932
|
+
for (const [file, unit] of units) {
|
|
1933
|
+
at[file]?.callees.push([spelling, unit]);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
return byShard;
|
|
1937
|
+
}
|
|
1938
|
+
function readStoreIndex(file) {
|
|
1939
|
+
try {
|
|
1940
|
+
const index = readJsonFile(file);
|
|
1941
|
+
return Array.isArray(index.files) ? index : null;
|
|
1942
|
+
} catch {
|
|
1943
|
+
return null;
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
function writeStoreIndex(file, index) {
|
|
1947
|
+
writeDocumentFile(file, index);
|
|
1948
|
+
}
|
|
1949
|
+
function keyOf3(binding) {
|
|
1950
|
+
try {
|
|
1951
|
+
return displayLabel(binding);
|
|
1952
|
+
} catch {
|
|
1953
|
+
return null;
|
|
1954
|
+
}
|
|
1696
1955
|
}
|
|
1697
1956
|
|
|
1698
|
-
// src/
|
|
1957
|
+
// src/cacheShards.ts
|
|
1699
1958
|
import { createHash as createHash3 } from "crypto";
|
|
1700
|
-
import
|
|
1959
|
+
import fs4 from "fs";
|
|
1701
1960
|
import path6 from "path";
|
|
1702
|
-
import {
|
|
1961
|
+
import {
|
|
1962
|
+
documentPieces,
|
|
1963
|
+
readJsonFile as readJsonFile2,
|
|
1964
|
+
writeFileAtomically
|
|
1965
|
+
} from "@suss/behavioral-ir/files";
|
|
1966
|
+
var SHARDS_DIR = "shards";
|
|
1967
|
+
var RECORDS_DIR = "records";
|
|
1968
|
+
var STORED_ID = /^[0-9a-f]{32}\.json$/;
|
|
1969
|
+
function writeShard(entryDir, content) {
|
|
1970
|
+
return writeOnce(path6.join(entryDir, SHARDS_DIR), interned(content));
|
|
1971
|
+
}
|
|
1972
|
+
function readShard(entryDir, id, file) {
|
|
1973
|
+
const stored = readStored(path6.join(entryDir, SHARDS_DIR), id);
|
|
1974
|
+
if (stored?.file !== file || !Array.isArray(stored.units)) {
|
|
1975
|
+
return null;
|
|
1976
|
+
}
|
|
1977
|
+
const take = takerFor(stored.intern ?? []);
|
|
1978
|
+
return {
|
|
1979
|
+
file: stored.file,
|
|
1980
|
+
units: stored.units.map((unit) => expanded(unit, take))
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
function writeRecord(entryDir, meta) {
|
|
1984
|
+
return writeOnce(path6.join(entryDir, RECORDS_DIR), { meta });
|
|
1985
|
+
}
|
|
1986
|
+
function readRecord(entryDir, id) {
|
|
1987
|
+
const stored = readStored(path6.join(entryDir, RECORDS_DIR), id);
|
|
1988
|
+
return typeof stored === "object" && stored !== null ? stored : null;
|
|
1989
|
+
}
|
|
1990
|
+
function recordReader(entryDir) {
|
|
1991
|
+
const opened = /* @__PURE__ */ new Map();
|
|
1992
|
+
return (id) => {
|
|
1993
|
+
if (!opened.has(id)) {
|
|
1994
|
+
const record2 = readRecord(entryDir, id);
|
|
1995
|
+
opened.set(id, record2);
|
|
1996
|
+
return record2;
|
|
1997
|
+
}
|
|
1998
|
+
const record = opened.get(id) ?? null;
|
|
1999
|
+
return record === null ? null : copyOfJson(record);
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
function removeStoredOutside(entryDir, keep) {
|
|
2003
|
+
for (const kind of [SHARDS_DIR, RECORDS_DIR]) {
|
|
2004
|
+
const root = path6.join(entryDir, kind);
|
|
2005
|
+
for (const prefix of namesIn(root)) {
|
|
2006
|
+
const dir = path6.join(root, prefix);
|
|
2007
|
+
for (const name of namesIn(dir)) {
|
|
2008
|
+
if (STORED_ID.test(name) && !keep.has(name.slice(0, -".json".length))) {
|
|
2009
|
+
fs4.rmSync(path6.join(dir, name), { force: true });
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
function namesIn(dir) {
|
|
2016
|
+
try {
|
|
2017
|
+
return fs4.readdirSync(dir);
|
|
2018
|
+
} catch {
|
|
2019
|
+
return [];
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
function writeOnce(root, value) {
|
|
2023
|
+
const pieces = [...documentPieces(value)];
|
|
2024
|
+
const hash = createHash3("sha256");
|
|
2025
|
+
for (const piece of pieces) {
|
|
2026
|
+
hash.update(piece);
|
|
2027
|
+
}
|
|
2028
|
+
const id = hash.digest("hex").slice(0, 32);
|
|
2029
|
+
const file = storedPath(root, id);
|
|
2030
|
+
if (!fs4.existsSync(file)) {
|
|
2031
|
+
writeFileAtomically(file, pieces);
|
|
2032
|
+
}
|
|
2033
|
+
return id;
|
|
2034
|
+
}
|
|
2035
|
+
function readStored(root, id) {
|
|
2036
|
+
try {
|
|
2037
|
+
return readJsonFile2(storedPath(root, id));
|
|
2038
|
+
} catch {
|
|
2039
|
+
return void 0;
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
function storedPath(root, id) {
|
|
2043
|
+
return path6.join(root, id.slice(0, 2), `${id}.json`);
|
|
2044
|
+
}
|
|
2045
|
+
function interned(content) {
|
|
2046
|
+
const intern = [];
|
|
2047
|
+
const byText = /* @__PURE__ */ new Map();
|
|
2048
|
+
const byObject = /* @__PURE__ */ new Map();
|
|
2049
|
+
const positionOf = (value) => {
|
|
2050
|
+
const known = byObject.get(value);
|
|
2051
|
+
if (known !== void 0) {
|
|
2052
|
+
return known;
|
|
2053
|
+
}
|
|
2054
|
+
const text = JSON.stringify(value) ?? "null";
|
|
2055
|
+
let position = byText.get(text);
|
|
2056
|
+
if (position === void 0) {
|
|
2057
|
+
position = intern.length;
|
|
2058
|
+
intern.push(value);
|
|
2059
|
+
byText.set(text, position);
|
|
2060
|
+
}
|
|
2061
|
+
if (typeof value === "object" && value !== null) {
|
|
2062
|
+
byObject.set(value, position);
|
|
2063
|
+
}
|
|
2064
|
+
return position;
|
|
2065
|
+
};
|
|
2066
|
+
const positions = (values) => Array.isArray(values) ? values.map(positionOf) : values;
|
|
2067
|
+
const units = content.units.map((summary) => ({
|
|
2068
|
+
...summary,
|
|
2069
|
+
transitions: summary.transitions.map((transition) => ({
|
|
2070
|
+
...transition,
|
|
2071
|
+
conditions: positions(transition.conditions),
|
|
2072
|
+
effects: positions(transition.effects)
|
|
2073
|
+
})),
|
|
2074
|
+
gaps: summary.gaps.map((gap) => ({
|
|
2075
|
+
...gap,
|
|
2076
|
+
conditions: positions(gap.conditions)
|
|
2077
|
+
}))
|
|
2078
|
+
}));
|
|
2079
|
+
return {
|
|
2080
|
+
file: content.file,
|
|
2081
|
+
intern,
|
|
2082
|
+
units
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
function expanded(unit, take) {
|
|
2086
|
+
const values = (positions) => Array.isArray(positions) ? positions.map((at) => take(at)) : positions;
|
|
2087
|
+
const transitions = Array.isArray(unit.transitions) ? unit.transitions : [];
|
|
2088
|
+
const gaps = Array.isArray(unit.gaps) ? unit.gaps : [];
|
|
2089
|
+
return {
|
|
2090
|
+
...unit,
|
|
2091
|
+
transitions: transitions.map((transition) => ({
|
|
2092
|
+
...transition,
|
|
2093
|
+
conditions: values(transition.conditions),
|
|
2094
|
+
effects: values(transition.effects)
|
|
2095
|
+
})),
|
|
2096
|
+
gaps: gaps.map((gap) => ({
|
|
2097
|
+
...gap,
|
|
2098
|
+
conditions: values(gap.conditions)
|
|
2099
|
+
}))
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2102
|
+
function takerFor(intern) {
|
|
2103
|
+
const handedOut = /* @__PURE__ */ new Set();
|
|
2104
|
+
return (position) => {
|
|
2105
|
+
const value = intern[position];
|
|
2106
|
+
if (!handedOut.has(position)) {
|
|
2107
|
+
handedOut.add(position);
|
|
2108
|
+
return value;
|
|
2109
|
+
}
|
|
2110
|
+
return copyOfJson(value);
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
function copyOfJson(value) {
|
|
2114
|
+
if (Array.isArray(value)) {
|
|
2115
|
+
return value.map(copyOfJson);
|
|
2116
|
+
}
|
|
2117
|
+
if (typeof value === "object" && value !== null) {
|
|
2118
|
+
const copy = {};
|
|
2119
|
+
for (const key of Object.keys(value)) {
|
|
2120
|
+
copy[key] = copyOfJson(value[key]);
|
|
2121
|
+
}
|
|
2122
|
+
return copy;
|
|
2123
|
+
}
|
|
2124
|
+
return value;
|
|
2125
|
+
}
|
|
1703
2126
|
|
|
1704
2127
|
// src/cacheStamps.ts
|
|
1705
|
-
import { createHash as
|
|
1706
|
-
import
|
|
2128
|
+
import { createHash as createHash4 } from "crypto";
|
|
2129
|
+
import fs5 from "fs/promises";
|
|
1707
2130
|
var RECENT_CHANGE_MS = 2e3;
|
|
1708
2131
|
function stampMayMissAWrite(stat, statAt) {
|
|
1709
2132
|
return Math.max(stat.mtimeMs, stat.ctimeMs) > statAt - RECENT_CHANGE_MS;
|
|
@@ -1724,7 +2147,7 @@ async function startRun(files, configPath) {
|
|
|
1724
2147
|
}
|
|
1725
2148
|
async function statAtStart(filePath) {
|
|
1726
2149
|
try {
|
|
1727
|
-
const stat = await
|
|
2150
|
+
const stat = await fs5.stat(filePath);
|
|
1728
2151
|
return {
|
|
1729
2152
|
stamp: { path: filePath, mtimeMs: stat.mtimeMs, size: stat.size },
|
|
1730
2153
|
ctimeMs: stat.ctimeMs
|
|
@@ -1774,7 +2197,7 @@ async function recordedStamp(start, run, prior) {
|
|
|
1774
2197
|
return start.stamp;
|
|
1775
2198
|
}
|
|
1776
2199
|
const filePath = start.stamp.path;
|
|
1777
|
-
const now = await
|
|
2200
|
+
const now = await fs5.stat(filePath).catch(() => null);
|
|
1778
2201
|
if (now === null || now.mtimeMs !== start.stamp.mtimeMs || now.size !== start.stamp.size || now.ctimeMs !== start.ctimeMs) {
|
|
1779
2202
|
return null;
|
|
1780
2203
|
}
|
|
@@ -1791,8 +2214,8 @@ function reusableHash(prior, stamp) {
|
|
|
1791
2214
|
}
|
|
1792
2215
|
async function hashFile(filePath) {
|
|
1793
2216
|
try {
|
|
1794
|
-
const content = await
|
|
1795
|
-
return
|
|
2217
|
+
const content = await fs5.readFile(filePath);
|
|
2218
|
+
return createHash4("sha256").update(content).digest("hex").slice(0, 16);
|
|
1796
2219
|
} catch {
|
|
1797
2220
|
return null;
|
|
1798
2221
|
}
|
|
@@ -1808,21 +2231,29 @@ function fileStampEquals(a, b) {
|
|
|
1808
2231
|
}
|
|
1809
2232
|
|
|
1810
2233
|
// src/ignoredDirectory.ts
|
|
1811
|
-
import
|
|
1812
|
-
import
|
|
2234
|
+
import fs6 from "fs";
|
|
2235
|
+
import path7 from "path";
|
|
1813
2236
|
function makeIgnoredDirectory(dir) {
|
|
1814
|
-
|
|
1815
|
-
const ignore =
|
|
1816
|
-
if (!
|
|
1817
|
-
|
|
2237
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
2238
|
+
const ignore = path7.join(dir, ".gitignore");
|
|
2239
|
+
if (!fs6.existsSync(ignore)) {
|
|
2240
|
+
fs6.writeFileSync(ignore, "*\n");
|
|
1818
2241
|
}
|
|
1819
2242
|
}
|
|
1820
2243
|
|
|
1821
2244
|
// src/cache.ts
|
|
1822
|
-
var SCHEMA_VERSION = "
|
|
2245
|
+
var SCHEMA_VERSION = "10";
|
|
2246
|
+
var MANIFEST = "manifest.json";
|
|
2247
|
+
var INDEX = "index.json";
|
|
1823
2248
|
var MAX_ENTRIES = 2;
|
|
1824
2249
|
var ENTRY_PREFIX = "key-";
|
|
1825
2250
|
var ENTRY_DIR_NAME = new RegExp(`^${ENTRY_PREFIX}[0-9a-f]{16}$`);
|
|
2251
|
+
function ownersWhereWritten(summaries, walkedFileOf) {
|
|
2252
|
+
return summaries.map((summary) => {
|
|
2253
|
+
const walked = walkedFileOf(summary.location.file);
|
|
2254
|
+
return walked === void 0 ? [] : [walked];
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
1826
2257
|
function createCacheLayer(cacheDir) {
|
|
1827
2258
|
if (cacheDir === null) {
|
|
1828
2259
|
return {
|
|
@@ -1842,7 +2273,7 @@ function createCacheLayer(cacheDir) {
|
|
|
1842
2273
|
const lookupWith = async (input, run) => {
|
|
1843
2274
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1844
2275
|
const manifest = await manifests.readAtRunStart(
|
|
1845
|
-
|
|
2276
|
+
path8.join(entryDir, MANIFEST)
|
|
1846
2277
|
);
|
|
1847
2278
|
if (manifest === null) {
|
|
1848
2279
|
return missDiag(await describeAbsentEntry(cacheDir));
|
|
@@ -1857,11 +2288,15 @@ function createCacheLayer(cacheDir) {
|
|
|
1857
2288
|
if (!await filesStillMatch(manifest.files, run)) {
|
|
1858
2289
|
return missDiag("files-changed");
|
|
1859
2290
|
}
|
|
2291
|
+
const summaries = storedSummaries(entryDir, manifest);
|
|
2292
|
+
if (summaries === null) {
|
|
2293
|
+
return missDiag("no-manifest");
|
|
2294
|
+
}
|
|
1860
2295
|
await markUsed(entryDir);
|
|
1861
2296
|
manifests.forget();
|
|
1862
2297
|
return {
|
|
1863
2298
|
kind: "hit",
|
|
1864
|
-
summaries
|
|
2299
|
+
summaries,
|
|
1865
2300
|
diagnostic: { kind: "hit" }
|
|
1866
2301
|
};
|
|
1867
2302
|
};
|
|
@@ -1881,10 +2316,8 @@ function createCacheLayer(cacheDir) {
|
|
|
1881
2316
|
},
|
|
1882
2317
|
async plan(input) {
|
|
1883
2318
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1884
|
-
const manifest = await manifests.readAgain(
|
|
1885
|
-
|
|
1886
|
-
);
|
|
1887
|
-
if (manifest === null || manifest.roots === void 0 || manifest.rootMeta === void 0 || manifest.owners === void 0) {
|
|
2319
|
+
const manifest = await manifests.readAgain(path8.join(entryDir, MANIFEST));
|
|
2320
|
+
if (manifest === null || manifest.roots === void 0 || manifest.rootMeta === void 0) {
|
|
1888
2321
|
return null;
|
|
1889
2322
|
}
|
|
1890
2323
|
const run = await runFor(input);
|
|
@@ -1895,14 +2328,17 @@ function createCacheLayer(cacheDir) {
|
|
|
1895
2328
|
)) {
|
|
1896
2329
|
return null;
|
|
1897
2330
|
}
|
|
2331
|
+
const summaries = storedSummaries(entryDir, manifest);
|
|
2332
|
+
const records = storedRecords(entryDir, manifest);
|
|
2333
|
+
if (summaries === null || records === null) {
|
|
2334
|
+
return null;
|
|
2335
|
+
}
|
|
1898
2336
|
await markUsed(entryDir);
|
|
1899
|
-
return buildPlan(manifest, run);
|
|
2337
|
+
return buildPlan(manifest, records, summaries, run);
|
|
1900
2338
|
},
|
|
1901
2339
|
async write(input, summaries, attribution) {
|
|
1902
2340
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1903
|
-
const previous = await manifests.readAgain(
|
|
1904
|
-
path6.join(entryDir, "manifest.json")
|
|
1905
|
-
);
|
|
2341
|
+
const previous = await manifests.readAgain(path8.join(entryDir, MANIFEST));
|
|
1906
2342
|
manifests.forget();
|
|
1907
2343
|
const known = runs.get(input);
|
|
1908
2344
|
const run = known ?? await runFor(input);
|
|
@@ -1918,55 +2354,119 @@ function createCacheLayer(cacheDir) {
|
|
|
1918
2354
|
)
|
|
1919
2355
|
);
|
|
1920
2356
|
const files = recorded.filter((stamp) => stamp !== null);
|
|
2357
|
+
const encoded = attribution === void 0 ? null : encodeAttribution(
|
|
2358
|
+
attribution,
|
|
2359
|
+
(meta) => writeRecord(entryDir, meta)
|
|
2360
|
+
);
|
|
2361
|
+
makeIgnoredDirectory(cacheDir);
|
|
2362
|
+
const shards = writeShards(entryDir, summaries, encoded);
|
|
1921
2363
|
const manifest = {
|
|
1922
2364
|
schemaVersion: SCHEMA_VERSION,
|
|
1923
2365
|
adapterPacksDigest: input.adapterPacksDigest,
|
|
1924
2366
|
configStamp,
|
|
1925
2367
|
files,
|
|
1926
|
-
summaries,
|
|
1927
|
-
|
|
2368
|
+
summaryCount: summaries.length,
|
|
2369
|
+
shards,
|
|
2370
|
+
...encoded === null ? {} : encoded.stored
|
|
1928
2371
|
};
|
|
1929
|
-
|
|
1930
|
-
|
|
2372
|
+
writeDocumentFile2(path8.join(entryDir, MANIFEST), manifest);
|
|
2373
|
+
removeStoredOutside(
|
|
2374
|
+
entryDir,
|
|
2375
|
+
/* @__PURE__ */ new Set([...storedIds(manifest), ...storedIds(previous)])
|
|
2376
|
+
);
|
|
1931
2377
|
await evictOldEntries(cacheDir, entryDir);
|
|
1932
2378
|
}
|
|
1933
2379
|
};
|
|
1934
2380
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2381
|
+
function storedIds(manifest) {
|
|
2382
|
+
return [
|
|
2383
|
+
...(manifest?.shards ?? []).map((shard) => shard.id),
|
|
2384
|
+
...(manifest?.rootMeta ?? []).flatMap(
|
|
2385
|
+
(root) => root.record === void 0 ? [] : [root.record]
|
|
2386
|
+
)
|
|
2387
|
+
];
|
|
2388
|
+
}
|
|
2389
|
+
function writeShards(entryDir, summaries, encoded) {
|
|
2390
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
2391
|
+
summaries.forEach((summary, position) => {
|
|
2392
|
+
const file = summary.location?.file ?? "";
|
|
2393
|
+
const shard = byFile.get(file) ?? {
|
|
2394
|
+
content: { file, units: [] },
|
|
2395
|
+
order: [],
|
|
2396
|
+
owners: []
|
|
2397
|
+
};
|
|
2398
|
+
byFile.set(file, shard);
|
|
2399
|
+
shard.content.units.push(summary);
|
|
2400
|
+
shard.order.push(position);
|
|
2401
|
+
shard.owners.push(encoded?.owners[position] ?? []);
|
|
2402
|
+
});
|
|
2403
|
+
const indexFile = path8.join(entryDir, INDEX);
|
|
2404
|
+
const before = readStoreIndex(indexFile);
|
|
2405
|
+
const known = before === null ? /* @__PURE__ */ new Map() : entriesByShard(before);
|
|
2406
|
+
const sorted = [...byFile].sort(([a], [b]) => a < b ? -1 : 1);
|
|
2407
|
+
const written = sorted.map(([file, { content, order, owners }]) => {
|
|
2408
|
+
const id = writeShard(entryDir, content);
|
|
2409
|
+
return {
|
|
2410
|
+
shard: {
|
|
2411
|
+
file,
|
|
2412
|
+
id,
|
|
2413
|
+
order,
|
|
2414
|
+
...encoded === null ? {} : { owners }
|
|
2415
|
+
},
|
|
2416
|
+
entries: known.get(id) ?? entriesOf(content.units)
|
|
2417
|
+
};
|
|
2418
|
+
});
|
|
2419
|
+
writeStoreIndex(
|
|
2420
|
+
indexFile,
|
|
2421
|
+
indexOf(
|
|
2422
|
+
written.map(({ shard, entries }) => ({
|
|
2423
|
+
file: shard.file,
|
|
2424
|
+
id: shard.id,
|
|
2425
|
+
entries
|
|
2426
|
+
}))
|
|
2427
|
+
)
|
|
2428
|
+
);
|
|
2429
|
+
return written.map(({ shard }) => shard);
|
|
2430
|
+
}
|
|
2431
|
+
function storedSummaries(entryDir, manifest) {
|
|
2432
|
+
const summaries = new Array(
|
|
2433
|
+
manifest.summaryCount
|
|
2434
|
+
);
|
|
2435
|
+
for (const shard of manifest.shards) {
|
|
2436
|
+
const content = readShard(entryDir, shard.id, shard.file);
|
|
2437
|
+
if (content === null || content.units.length !== shard.order.length) {
|
|
2438
|
+
return null;
|
|
1944
2439
|
}
|
|
2440
|
+
shard.order.forEach((position, i) => {
|
|
2441
|
+
summaries[position] = content.units[i];
|
|
2442
|
+
});
|
|
1945
2443
|
}
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
if (before === void 0) {
|
|
1950
|
-
changed.add(p);
|
|
1951
|
-
added.add(p);
|
|
1952
|
-
} else if (!fileStampEquals(before, stamp)) {
|
|
1953
|
-
if (before.contentHash === void 0) {
|
|
1954
|
-
changed.add(p);
|
|
1955
|
-
} else {
|
|
1956
|
-
toVerify.push(p);
|
|
1957
|
-
}
|
|
1958
|
-
} else if (before.verifyHash === true) {
|
|
1959
|
-
toVerify.push(p);
|
|
2444
|
+
for (let position = 0; position < summaries.length; position++) {
|
|
2445
|
+
if (summaries[position] === void 0) {
|
|
2446
|
+
return null;
|
|
1960
2447
|
}
|
|
1961
2448
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2449
|
+
return summaries;
|
|
2450
|
+
}
|
|
2451
|
+
function storedRecords(entryDir, manifest) {
|
|
2452
|
+
const records = /* @__PURE__ */ new Map();
|
|
2453
|
+
const roots = manifest.roots ?? [];
|
|
2454
|
+
const readRecord2 = recordReader(entryDir);
|
|
2455
|
+
for (const [i, root] of (manifest.rootMeta ?? []).entries()) {
|
|
2456
|
+
const rootPath = roots[i];
|
|
2457
|
+
if (rootPath === void 0 || root.record === void 0) {
|
|
2458
|
+
continue;
|
|
2459
|
+
}
|
|
2460
|
+
const record = readRecord2(root.record);
|
|
2461
|
+
if (record === null) {
|
|
2462
|
+
return null;
|
|
2463
|
+
}
|
|
2464
|
+
records.set(rootPath, record.meta);
|
|
2465
|
+
}
|
|
2466
|
+
return records;
|
|
2467
|
+
}
|
|
2468
|
+
async function buildPlan(manifest, records, stored, run) {
|
|
2469
|
+
const { changed, added, removed } = await changedSince(manifest, run);
|
|
1970
2470
|
const roots = /* @__PURE__ */ new Map();
|
|
1971
2471
|
const rootNames = manifest.roots ?? [];
|
|
1972
2472
|
const depPaths = manifest.depPaths ?? [];
|
|
@@ -1976,23 +2476,24 @@ async function buildPlan(manifest, run) {
|
|
|
1976
2476
|
});
|
|
1977
2477
|
let rootsDeclined = 0;
|
|
1978
2478
|
rootNames.forEach((rootPath, i) => {
|
|
1979
|
-
const
|
|
1980
|
-
if (
|
|
2479
|
+
const record = manifest.rootMeta?.[i];
|
|
2480
|
+
if (record === void 0) {
|
|
1981
2481
|
return;
|
|
1982
2482
|
}
|
|
1983
|
-
if (!
|
|
2483
|
+
if (!record.cacheable) {
|
|
1984
2484
|
rootsDeclined += 1;
|
|
1985
2485
|
}
|
|
1986
2486
|
roots.set(rootPath, {
|
|
1987
2487
|
path: rootPath,
|
|
1988
|
-
cacheable:
|
|
1989
|
-
deps: pathsOf(
|
|
1990
|
-
claims:
|
|
1991
|
-
meta:
|
|
1992
|
-
packs:
|
|
1993
|
-
...
|
|
2488
|
+
cacheable: record.cacheable,
|
|
2489
|
+
deps: pathsOf(record.deps),
|
|
2490
|
+
claims: record.claims,
|
|
2491
|
+
meta: records.get(rootPath),
|
|
2492
|
+
packs: record.packs,
|
|
2493
|
+
...record.imports === void 0 ? {} : { imports: pathsOf(record.imports) }
|
|
1994
2494
|
});
|
|
1995
2495
|
});
|
|
2496
|
+
const current = new Set(run.files.map((f) => f.stamp.path));
|
|
1996
2497
|
const unchanged = (filePath, deps) => current.has(filePath) && !changed.has(filePath) && !deps.some((d) => changed.has(d) || removed.has(d));
|
|
1997
2498
|
const validRoots = /* @__PURE__ */ new Set();
|
|
1998
2499
|
for (const [rootPath, record] of roots) {
|
|
@@ -2000,14 +2501,14 @@ async function buildPlan(manifest, run) {
|
|
|
2000
2501
|
validRoots.add(rootPath);
|
|
2001
2502
|
}
|
|
2002
2503
|
}
|
|
2003
|
-
const units = (manifest.units ?? []).flatMap((
|
|
2004
|
-
const file = depPaths[
|
|
2504
|
+
const units = (manifest.units ?? []).flatMap((unit) => {
|
|
2505
|
+
const file = depPaths[unit.file];
|
|
2005
2506
|
return file === void 0 ? [] : [
|
|
2006
2507
|
{
|
|
2007
|
-
key:
|
|
2508
|
+
key: unit.key,
|
|
2008
2509
|
file,
|
|
2009
|
-
deps: pathsOf(
|
|
2010
|
-
data:
|
|
2510
|
+
deps: pathsOf(unit.deps),
|
|
2511
|
+
data: unit.data
|
|
2011
2512
|
}
|
|
2012
2513
|
];
|
|
2013
2514
|
});
|
|
@@ -2025,7 +2526,7 @@ async function buildPlan(manifest, run) {
|
|
|
2025
2526
|
}
|
|
2026
2527
|
}
|
|
2027
2528
|
}
|
|
2028
|
-
const
|
|
2529
|
+
const ownerPaths = ownersInRunOrder(manifest);
|
|
2029
2530
|
return {
|
|
2030
2531
|
changed,
|
|
2031
2532
|
removed,
|
|
@@ -2037,36 +2538,81 @@ async function buildPlan(manifest, run) {
|
|
|
2037
2538
|
reuse(valid) {
|
|
2038
2539
|
const summaries = [];
|
|
2039
2540
|
const reusedOwners = [];
|
|
2040
|
-
|
|
2041
|
-
const
|
|
2042
|
-
|
|
2043
|
-
return p === void 0 ? [] : [p];
|
|
2044
|
-
});
|
|
2045
|
-
if (ownerPaths.some((p) => valid.has(p))) {
|
|
2541
|
+
stored.forEach((summary, i) => {
|
|
2542
|
+
const owners = ownerPaths[i] ?? [];
|
|
2543
|
+
if (owners.some((p) => valid.has(p))) {
|
|
2046
2544
|
summaries.push(summary);
|
|
2047
|
-
reusedOwners.push(
|
|
2545
|
+
reusedOwners.push(owners.filter((p) => valid.has(p)));
|
|
2048
2546
|
}
|
|
2049
2547
|
});
|
|
2050
2548
|
return { summaries, owners: reusedOwners };
|
|
2051
2549
|
},
|
|
2052
2550
|
allSummaries() {
|
|
2053
|
-
return
|
|
2551
|
+
return stored;
|
|
2054
2552
|
},
|
|
2055
2553
|
attribution() {
|
|
2056
2554
|
return {
|
|
2057
2555
|
roots: [...roots.values()],
|
|
2058
|
-
owners:
|
|
2059
|
-
(ownerIds) => ownerIds.flatMap((o) => {
|
|
2060
|
-
const p = rootNames[o];
|
|
2061
|
-
return p === void 0 ? [] : [p];
|
|
2062
|
-
})
|
|
2063
|
-
),
|
|
2556
|
+
owners: ownerPaths,
|
|
2064
2557
|
units
|
|
2065
2558
|
};
|
|
2066
2559
|
}
|
|
2067
2560
|
};
|
|
2068
2561
|
}
|
|
2069
|
-
function
|
|
2562
|
+
function ownersInRunOrder(manifest) {
|
|
2563
|
+
const rootNames = manifest.roots ?? [];
|
|
2564
|
+
const owners = Array.from(
|
|
2565
|
+
{ length: manifest.summaryCount },
|
|
2566
|
+
() => []
|
|
2567
|
+
);
|
|
2568
|
+
for (const shard of manifest.shards ?? []) {
|
|
2569
|
+
shard.order.forEach((position, i) => {
|
|
2570
|
+
owners[position] = (shard.owners?.[i] ?? []).flatMap((o) => {
|
|
2571
|
+
const p = rootNames[o];
|
|
2572
|
+
return p === void 0 ? [] : [p];
|
|
2573
|
+
});
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
return owners;
|
|
2577
|
+
}
|
|
2578
|
+
async function changedSince(manifest, run) {
|
|
2579
|
+
const stored = new Map(manifest.files.map((f) => [f.path, f]));
|
|
2580
|
+
const current = new Map(run.files.map((f) => [f.stamp.path, f.stamp]));
|
|
2581
|
+
const changed = /* @__PURE__ */ new Set();
|
|
2582
|
+
const added = /* @__PURE__ */ new Set();
|
|
2583
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2584
|
+
for (const p of stored.keys()) {
|
|
2585
|
+
if (!current.has(p)) {
|
|
2586
|
+
removed.add(p);
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
const toVerify = [];
|
|
2590
|
+
for (const [p, stamp] of current) {
|
|
2591
|
+
const before = stored.get(p);
|
|
2592
|
+
if (before === void 0) {
|
|
2593
|
+
changed.add(p);
|
|
2594
|
+
added.add(p);
|
|
2595
|
+
} else if (!fileStampEquals(before, stamp)) {
|
|
2596
|
+
if (before.contentHash === void 0) {
|
|
2597
|
+
changed.add(p);
|
|
2598
|
+
} else {
|
|
2599
|
+
toVerify.push(p);
|
|
2600
|
+
}
|
|
2601
|
+
} else if (before.verifyHash === true) {
|
|
2602
|
+
toVerify.push(p);
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
await Promise.all(
|
|
2606
|
+
toVerify.map(async (p) => {
|
|
2607
|
+
const hash = await hashOf(run, p);
|
|
2608
|
+
if (hash === null || hash !== stored.get(p)?.contentHash) {
|
|
2609
|
+
changed.add(p);
|
|
2610
|
+
}
|
|
2611
|
+
})
|
|
2612
|
+
);
|
|
2613
|
+
return { changed, added, removed };
|
|
2614
|
+
}
|
|
2615
|
+
function encodeAttribution(attribution, storeRecord) {
|
|
2070
2616
|
const roots = attribution.roots.map((r) => r.path);
|
|
2071
2617
|
const rootIndex = new Map(roots.map((p, i) => [p, i]));
|
|
2072
2618
|
const depIndex = /* @__PURE__ */ new Map();
|
|
@@ -2082,10 +2628,10 @@ function encodeAttribution(attribution) {
|
|
|
2082
2628
|
return id;
|
|
2083
2629
|
};
|
|
2084
2630
|
const rootMeta = attribution.roots.map((r) => ({
|
|
2631
|
+
...r.meta === void 0 ? {} : { record: storeRecord(r.meta) },
|
|
2085
2632
|
cacheable: r.cacheable,
|
|
2086
2633
|
deps: r.deps.map(depIdOf),
|
|
2087
2634
|
claims: r.claims,
|
|
2088
|
-
meta: r.meta,
|
|
2089
2635
|
packs: r.packs,
|
|
2090
2636
|
...r.imports === void 0 ? {} : { imports: r.imports.map(depIdOf) }
|
|
2091
2637
|
}));
|
|
@@ -2102,16 +2648,18 @@ function encodeAttribution(attribution) {
|
|
|
2102
2648
|
data: unit.data
|
|
2103
2649
|
}));
|
|
2104
2650
|
return {
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2651
|
+
stored: {
|
|
2652
|
+
roots,
|
|
2653
|
+
rootMeta,
|
|
2654
|
+
depPaths,
|
|
2655
|
+
...units === void 0 ? {} : { units }
|
|
2656
|
+
},
|
|
2657
|
+
owners
|
|
2110
2658
|
};
|
|
2111
2659
|
}
|
|
2112
2660
|
async function describeAbsentEntry(cacheDir) {
|
|
2113
2661
|
try {
|
|
2114
|
-
const entries = await
|
|
2662
|
+
const entries = await fs7.readdir(cacheDir, { withFileTypes: true });
|
|
2115
2663
|
return entries.some((e) => e.isDirectory() && isEntryDir(e.name)) ? "key-changed" : "no-manifest";
|
|
2116
2664
|
} catch {
|
|
2117
2665
|
return "no-manifest";
|
|
@@ -2123,8 +2671,8 @@ function entryDirFor(cacheDir, input) {
|
|
|
2123
2671
|
input.adapterPacksDigest,
|
|
2124
2672
|
input.configPath ?? ""
|
|
2125
2673
|
].join(" ");
|
|
2126
|
-
const name =
|
|
2127
|
-
return
|
|
2674
|
+
const name = createHash5("sha256").update(key).digest("hex").slice(0, 16);
|
|
2675
|
+
return path8.join(cacheDir, `${ENTRY_PREFIX}${name}`);
|
|
2128
2676
|
}
|
|
2129
2677
|
function isEntryDir(name) {
|
|
2130
2678
|
return ENTRY_DIR_NAME.test(name);
|
|
@@ -2132,24 +2680,24 @@ function isEntryDir(name) {
|
|
|
2132
2680
|
async function markUsed(entryDir) {
|
|
2133
2681
|
const now = /* @__PURE__ */ new Date();
|
|
2134
2682
|
try {
|
|
2135
|
-
await
|
|
2683
|
+
await fs7.utimes(entryDir, now, now);
|
|
2136
2684
|
} catch {
|
|
2137
2685
|
}
|
|
2138
2686
|
}
|
|
2139
2687
|
async function evictOldEntries(cacheDir, keepDir) {
|
|
2140
2688
|
try {
|
|
2141
|
-
await
|
|
2142
|
-
const entries = await
|
|
2689
|
+
await fs7.rm(path8.join(cacheDir, "manifest.json"), { force: true });
|
|
2690
|
+
const entries = await fs7.readdir(cacheDir, { withFileTypes: true });
|
|
2143
2691
|
const dirs = await Promise.all(
|
|
2144
2692
|
entries.filter((e) => e.isDirectory() && isEntryDir(e.name)).map(async (e) => {
|
|
2145
|
-
const dir =
|
|
2146
|
-
const stat = await
|
|
2693
|
+
const dir = path8.join(cacheDir, e.name);
|
|
2694
|
+
const stat = await fs7.stat(dir);
|
|
2147
2695
|
return { dir, mtimeMs: stat.mtimeMs };
|
|
2148
2696
|
})
|
|
2149
2697
|
);
|
|
2150
2698
|
const doomed = dirs.filter((d) => d.dir !== keepDir).sort((a, b) => b.mtimeMs - a.mtimeMs).slice(MAX_ENTRIES - 1);
|
|
2151
2699
|
await Promise.all(
|
|
2152
|
-
doomed.map((d) =>
|
|
2700
|
+
doomed.map((d) => fs7.rm(d.dir, { recursive: true, force: true }))
|
|
2153
2701
|
);
|
|
2154
2702
|
} catch {
|
|
2155
2703
|
}
|
|
@@ -2164,7 +2712,7 @@ var ManifestReads = class {
|
|
|
2164
2712
|
last = null;
|
|
2165
2713
|
async readAtRunStart(manifestPath) {
|
|
2166
2714
|
const stamp = await manifestStamp(manifestPath);
|
|
2167
|
-
const manifest = await
|
|
2715
|
+
const manifest = await readManifest2(manifestPath);
|
|
2168
2716
|
this.last = { path: manifestPath, stamp, manifest };
|
|
2169
2717
|
return manifest;
|
|
2170
2718
|
}
|
|
@@ -2181,22 +2729,60 @@ var ManifestReads = class {
|
|
|
2181
2729
|
};
|
|
2182
2730
|
async function manifestStamp(manifestPath) {
|
|
2183
2731
|
try {
|
|
2184
|
-
const stat = await
|
|
2732
|
+
const stat = await fs7.stat(manifestPath);
|
|
2185
2733
|
return `${stat.ino}:${stat.mtimeMs}:${stat.size}`;
|
|
2186
2734
|
} catch {
|
|
2187
2735
|
return null;
|
|
2188
2736
|
}
|
|
2189
2737
|
}
|
|
2190
|
-
async function
|
|
2738
|
+
async function readManifest2(manifestPath) {
|
|
2191
2739
|
try {
|
|
2192
|
-
|
|
2740
|
+
const manifest = readJsonFile3(manifestPath);
|
|
2741
|
+
return Array.isArray(manifest.shards) ? manifest : null;
|
|
2193
2742
|
} catch {
|
|
2194
2743
|
return null;
|
|
2195
2744
|
}
|
|
2196
2745
|
}
|
|
2197
2746
|
|
|
2747
|
+
// src/cacheLocation.ts
|
|
2748
|
+
import { createHash as createHash6 } from "crypto";
|
|
2749
|
+
import fs8 from "fs";
|
|
2750
|
+
import path9 from "path";
|
|
2751
|
+
var CACHE_DIR_ENV = "SUSS_CACHE_DIR";
|
|
2752
|
+
function chosenCacheRoot() {
|
|
2753
|
+
const chosen = process.env[CACHE_DIR_ENV];
|
|
2754
|
+
if (chosen === void 0 || chosen === "") {
|
|
2755
|
+
return null;
|
|
2756
|
+
}
|
|
2757
|
+
return path9.resolve(chosen);
|
|
2758
|
+
}
|
|
2759
|
+
function realPathOrSelf(dir) {
|
|
2760
|
+
try {
|
|
2761
|
+
return fs8.realpathSync(dir);
|
|
2762
|
+
} catch {
|
|
2763
|
+
return dir;
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
function projectKey(projectDir) {
|
|
2767
|
+
return createHash6("sha256").update(realPathOrSelf(path9.resolve(projectDir))).digest("hex").slice(0, 16);
|
|
2768
|
+
}
|
|
2769
|
+
function extractionCacheDirFor(projectDir) {
|
|
2770
|
+
const root = chosenCacheRoot();
|
|
2771
|
+
if (root === null) {
|
|
2772
|
+
return path9.join(projectDir, ".suss", "cache");
|
|
2773
|
+
}
|
|
2774
|
+
return path9.join(root, "cache", projectKey(projectDir));
|
|
2775
|
+
}
|
|
2776
|
+
function liveRecordFor(projectDir) {
|
|
2777
|
+
const root = chosenCacheRoot();
|
|
2778
|
+
if (root === null) {
|
|
2779
|
+
return path9.join(projectDir, ".suss", "live", "server.json");
|
|
2780
|
+
}
|
|
2781
|
+
return path9.join(root, "live", `${projectKey(projectDir)}.json`);
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2198
2784
|
// src/extractionReport.ts
|
|
2199
|
-
import { BOUNDARY_ROLE } from "@suss/behavioral-ir";
|
|
2785
|
+
import { BOUNDARY_ROLE as BOUNDARY_ROLE2 } from "@suss/behavioral-ir";
|
|
2200
2786
|
var emptyTally = () => ({
|
|
2201
2787
|
candidateFiles: 0,
|
|
2202
2788
|
unitsDiscovered: 0,
|
|
@@ -2246,7 +2832,7 @@ function summaryCountsByPack(summaries) {
|
|
|
2246
2832
|
}
|
|
2247
2833
|
const entry = counts.get(recognition) ?? emptyCounts();
|
|
2248
2834
|
entry.bound += 1;
|
|
2249
|
-
if (
|
|
2835
|
+
if (BOUNDARY_ROLE2[summary.kind] === "provider") {
|
|
2250
2836
|
entry.providers += 1;
|
|
2251
2837
|
}
|
|
2252
2838
|
if (summary.transitions.length > 0) {
|
|
@@ -2471,6 +3057,17 @@ function undocumentedDeclarations(gradients) {
|
|
|
2471
3057
|
detail: gradient.withoutExample.join(", ")
|
|
2472
3058
|
}));
|
|
2473
3059
|
}
|
|
3060
|
+
function packConfigCheck(needs) {
|
|
3061
|
+
return {
|
|
3062
|
+
name: "every pack that needs an option was given it",
|
|
3063
|
+
code: "no-config",
|
|
3064
|
+
audience: "run",
|
|
3065
|
+
violations: needs.map((need) => ({
|
|
3066
|
+
label: need.pack,
|
|
3067
|
+
detail: `reads nothing until ${need.option} is set, for example ${need.example}. Write that to a JSON file and pass -f ${need.pack}=<config.json>.`
|
|
3068
|
+
}))
|
|
3069
|
+
};
|
|
3070
|
+
}
|
|
2474
3071
|
function evaluatePackHealth(report) {
|
|
2475
3072
|
const gradients = packGradients(report);
|
|
2476
3073
|
return [
|
|
@@ -2623,7 +3220,7 @@ function makeTransitionId(functionName, branch) {
|
|
|
2623
3220
|
const { terminal } = branch;
|
|
2624
3221
|
const statusKey = terminal.statusCode === null ? "none" : terminal.statusCode.type === "literal" ? String(terminal.statusCode.value) : `dyn:${terminal.statusCode.sourceText}`;
|
|
2625
3222
|
const conditionSig = branch.conditions.map((c) => `${c.polarity}:${c.sourceText}`).join(";");
|
|
2626
|
-
const conditionHash =
|
|
3223
|
+
const conditionHash = createHash7("sha1").update(conditionSig).digest("hex").slice(0, 7);
|
|
2627
3224
|
return `${functionName}:${terminal.kind}:${statusKey}:${conditionHash}`;
|
|
2628
3225
|
}
|
|
2629
3226
|
function collapseReading(table, reading) {
|
|
@@ -3077,6 +3674,7 @@ function paramToInput(param) {
|
|
|
3077
3674
|
};
|
|
3078
3675
|
}
|
|
3079
3676
|
export {
|
|
3677
|
+
CACHE_DIR_ENV,
|
|
3080
3678
|
EnclosingNodes,
|
|
3081
3679
|
IdMap,
|
|
3082
3680
|
IdSet,
|
|
@@ -3094,6 +3692,7 @@ export {
|
|
|
3094
3692
|
assembleSummary,
|
|
3095
3693
|
assessConfidence,
|
|
3096
3694
|
buildUngatedExtractionReport,
|
|
3695
|
+
chosenCacheRoot,
|
|
3097
3696
|
commonDirectoryOf,
|
|
3098
3697
|
composeWrappers,
|
|
3099
3698
|
computeContentHash,
|
|
@@ -3101,6 +3700,7 @@ export {
|
|
|
3101
3700
|
configuredCallOption,
|
|
3102
3701
|
createAdapterStamp,
|
|
3103
3702
|
createCacheLayer,
|
|
3703
|
+
createCodeHasher,
|
|
3104
3704
|
createPackTallies,
|
|
3105
3705
|
createTimer,
|
|
3106
3706
|
detectGaps,
|
|
@@ -3109,6 +3709,7 @@ export {
|
|
|
3109
3709
|
enumerateOrDegrade,
|
|
3110
3710
|
enumerateStructuredPaths,
|
|
3111
3711
|
evaluatePackHealth,
|
|
3712
|
+
extractionCacheDirFor,
|
|
3112
3713
|
extractionConfigStamp,
|
|
3113
3714
|
firstWrittenReading,
|
|
3114
3715
|
formatPackHealth,
|
|
@@ -3116,6 +3717,7 @@ export {
|
|
|
3116
3717
|
helperPathsOnVariables,
|
|
3117
3718
|
httpRouteDiscovery,
|
|
3118
3719
|
isListedTestFile,
|
|
3720
|
+
liveRecordFor,
|
|
3119
3721
|
makeIgnoredDirectory,
|
|
3120
3722
|
makeTransitionId,
|
|
3121
3723
|
mapReading,
|
|
@@ -3125,8 +3727,11 @@ export {
|
|
|
3125
3727
|
moduleInitStructure,
|
|
3126
3728
|
moduleOfFile,
|
|
3127
3729
|
noopTimer,
|
|
3730
|
+
ownersWhereWritten,
|
|
3731
|
+
packConfigCheck,
|
|
3128
3732
|
packGradients,
|
|
3129
3733
|
paramToInput,
|
|
3734
|
+
processCodeHasher,
|
|
3130
3735
|
projectFileStamp,
|
|
3131
3736
|
rawConditionToPredicate,
|
|
3132
3737
|
recordPackFailure,
|