@suss/extractor 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +335 -91
- package/dist/index.d.cts +277 -29
- package/dist/index.d.ts +277 -29
- package/dist/index.js +294 -60
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { createHash as
|
|
2
|
+
import { createHash as createHash8 } from "crypto";
|
|
3
3
|
import {
|
|
4
|
-
effectKey,
|
|
4
|
+
effectKey as effectKey2,
|
|
5
5
|
exchangesHttpResponses as exchangesHttpResponses2,
|
|
6
6
|
foldRepeatedEffects,
|
|
7
|
-
normalizeCalleeText,
|
|
7
|
+
normalizeCalleeText as normalizeCalleeText2,
|
|
8
8
|
withGraphqlMetadata,
|
|
9
9
|
withHttpMetadata,
|
|
10
10
|
withMountMetadata,
|
|
@@ -165,6 +165,45 @@ function mergeInputReads(derived, syntactic) {
|
|
|
165
165
|
return [...found.values()];
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
// src/callSiteGroup.ts
|
|
169
|
+
import { createHash } from "crypto";
|
|
170
|
+
import { effectKey, normalizeCalleeText } from "@suss/behavioral-ir";
|
|
171
|
+
function callSiteKey(effect) {
|
|
172
|
+
const callee = calleeOf(effect);
|
|
173
|
+
const written = callee === void 0 ? effect : { ...effect, callee: normalizeCalleeText(callee) };
|
|
174
|
+
const hash = createHash("sha1").update(effectKey(written)).digest("hex").slice(0, 7);
|
|
175
|
+
return callee === void 0 ? hash : `${normalizeCalleeText(callee)}:${hash}`;
|
|
176
|
+
}
|
|
177
|
+
function calleeOf(effect) {
|
|
178
|
+
return effect.type === "interaction" || effect.type === "invocation" ? effect.callee : void 0;
|
|
179
|
+
}
|
|
180
|
+
function numberRepeatedCallSites(sites) {
|
|
181
|
+
const taken = /* @__PURE__ */ new Map();
|
|
182
|
+
return sites.map((entries) => {
|
|
183
|
+
const ids = /* @__PURE__ */ new Map();
|
|
184
|
+
for (const key of new Set(
|
|
185
|
+
entries.flatMap((entry) => groupIdOf(entry.effect))
|
|
186
|
+
)) {
|
|
187
|
+
const count = (taken.get(key) ?? 0) + 1;
|
|
188
|
+
taken.set(key, count);
|
|
189
|
+
ids.set(key, count === 1 ? key : `${key}#${count}`);
|
|
190
|
+
}
|
|
191
|
+
return entries.map((entry) => ({
|
|
192
|
+
...entry,
|
|
193
|
+
effect: withGroupId(entry.effect, ids)
|
|
194
|
+
}));
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function groupIdOf(effect) {
|
|
198
|
+
return effect.type === "interaction" && effect.groupId !== void 0 ? [effect.groupId] : [];
|
|
199
|
+
}
|
|
200
|
+
function withGroupId(effect, ids) {
|
|
201
|
+
if (effect.type !== "interaction" || effect.groupId === void 0) {
|
|
202
|
+
return effect;
|
|
203
|
+
}
|
|
204
|
+
return { ...effect, groupId: ids.get(effect.groupId) ?? effect.groupId };
|
|
205
|
+
}
|
|
206
|
+
|
|
168
207
|
// src/composeWrappers.ts
|
|
169
208
|
import {
|
|
170
209
|
exchangesHttpResponses,
|
|
@@ -472,6 +511,22 @@ function modulesStamp(modules) {
|
|
|
472
511
|
// src/effectGuards.ts
|
|
473
512
|
var keyOf = (condition) => `${condition.polarity}:${condition.sourceText}`;
|
|
474
513
|
var opposite = (condition) => `${condition.polarity === "positive" ? "negative" : "positive"}:${condition.sourceText}`;
|
|
514
|
+
function firesOn(site, branch) {
|
|
515
|
+
const loop = branch.loopAround;
|
|
516
|
+
if (loop !== void 0 && site.line >= loop.start && site.line <= loop.end) {
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
if (!guardsHoldOn(site.preconditions, branch.conditions)) {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
return runsBefore(
|
|
523
|
+
site.cleansUpFrom ?? site.line,
|
|
524
|
+
branch.terminal.location.end
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
function effectsFiringOn(placed, branch) {
|
|
528
|
+
return placed.filter((one) => firesOn(one.site, branch)).map((one) => one.effect);
|
|
529
|
+
}
|
|
475
530
|
function guardsHoldOn(preconditions, conditions) {
|
|
476
531
|
if (preconditions === void 0 || preconditions.length === 0) {
|
|
477
532
|
return true;
|
|
@@ -539,16 +594,21 @@ function throughHelper(branch, at, helperBranches) {
|
|
|
539
594
|
isDefault: branch.isDefault && helper.isDefault
|
|
540
595
|
};
|
|
541
596
|
}
|
|
597
|
+
const { loopAround, ...rest } = branch;
|
|
542
598
|
return {
|
|
543
|
-
...
|
|
599
|
+
...rest,
|
|
544
600
|
...reads,
|
|
545
601
|
conditions,
|
|
546
602
|
terminal: { ...helper.terminal, location: at },
|
|
547
603
|
location: at,
|
|
604
|
+
...loopAround !== void 0 && within(at, loopAround) ? { loopAround } : {},
|
|
548
605
|
isDefault: false
|
|
549
606
|
};
|
|
550
607
|
});
|
|
551
608
|
}
|
|
609
|
+
function within(inner, outer) {
|
|
610
|
+
return inner.start >= outer.start && inner.end <= outer.end;
|
|
611
|
+
}
|
|
552
612
|
function mergeReadShapes(a, b) {
|
|
553
613
|
if (a === null || b === null) {
|
|
554
614
|
return a ?? b;
|
|
@@ -566,12 +626,11 @@ function mergeReadShapes(a, b) {
|
|
|
566
626
|
function splitAtHandOffs(branch, sites, from = 0) {
|
|
567
627
|
for (let index = from; index < sites.length; index++) {
|
|
568
628
|
const site = sites[index];
|
|
569
|
-
|
|
570
|
-
if (!reached || !guardsHoldOn(site.preconditions, branch.conditions)) {
|
|
629
|
+
if (!firesOn(site, branch)) {
|
|
571
630
|
continue;
|
|
572
631
|
}
|
|
573
632
|
return throughHelper(branch, site.at, site.helper).flatMap(
|
|
574
|
-
(
|
|
633
|
+
(path11) => path11.terminal === branch.terminal ? splitAtHandOffs(path11, sites, index + 1) : [path11]
|
|
575
634
|
);
|
|
576
635
|
}
|
|
577
636
|
return [branch];
|
|
@@ -618,6 +677,34 @@ function rootName(ref) {
|
|
|
618
677
|
return ref.type === "dependency" ? ref.name : null;
|
|
619
678
|
}
|
|
620
679
|
|
|
680
|
+
// src/libraryEnvReads.ts
|
|
681
|
+
import { functionCallBinding } from "@suss/behavioral-ir";
|
|
682
|
+
function libraryEnvReadMarker(recognition, declared, importer) {
|
|
683
|
+
return {
|
|
684
|
+
kind: "library",
|
|
685
|
+
location: { file: importer, range: { start: 0, end: 0 }, exportName: null },
|
|
686
|
+
identity: {
|
|
687
|
+
name: `${declared.module} env reads`,
|
|
688
|
+
exportPath: null,
|
|
689
|
+
boundaryBinding: functionCallBinding({
|
|
690
|
+
transport: "in-process",
|
|
691
|
+
recognition
|
|
692
|
+
})
|
|
693
|
+
},
|
|
694
|
+
inputs: [],
|
|
695
|
+
transitions: [],
|
|
696
|
+
gaps: [],
|
|
697
|
+
confidence: { source: "declared", level: "high" },
|
|
698
|
+
metadata: {
|
|
699
|
+
libraryEnvReads: {
|
|
700
|
+
module: declared.module,
|
|
701
|
+
...declared.prefixes !== void 0 ? { prefixes: declared.prefixes } : {},
|
|
702
|
+
...declared.names !== void 0 ? { names: declared.names } : {}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
621
708
|
// src/moduleImports.ts
|
|
622
709
|
function stampModuleImports(summaries, importsOf2) {
|
|
623
710
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -919,8 +1006,8 @@ var catchEntryCond = () => fixedCond(
|
|
|
919
1006
|
"positive",
|
|
920
1007
|
"catchBlock"
|
|
921
1008
|
);
|
|
922
|
-
function classify(
|
|
923
|
-
return
|
|
1009
|
+
function classify(path11, home, isAncestorOrSelf) {
|
|
1010
|
+
return path11.map((cond) => {
|
|
924
1011
|
if (cond.branchStmt === null) {
|
|
925
1012
|
return cond.info;
|
|
926
1013
|
}
|
|
@@ -992,9 +1079,9 @@ function limitOpenPaths(paths) {
|
|
|
992
1079
|
);
|
|
993
1080
|
}
|
|
994
1081
|
}
|
|
995
|
-
function recordTerminal(ctx, terminal, home,
|
|
1082
|
+
function recordTerminal(ctx, terminal, home, path11) {
|
|
996
1083
|
chargeBudget(ctx.state);
|
|
997
|
-
const info = classify(
|
|
1084
|
+
const info = classify(path11, home, ctx.isAncestorOrSelf);
|
|
998
1085
|
const existing = ctx.state.byTerminal.get(terminal) ?? [];
|
|
999
1086
|
existing.push(info);
|
|
1000
1087
|
ctx.state.byTerminal.set(terminal, existing);
|
|
@@ -1005,15 +1092,15 @@ function containsTerminal(ctx, stmt) {
|
|
|
1005
1092
|
}
|
|
1006
1093
|
return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
|
|
1007
1094
|
}
|
|
1008
|
-
function stepIf(stmt,
|
|
1095
|
+
function stepIf(stmt, path11, ctx) {
|
|
1009
1096
|
const thenExit = exitKindOfList(stmt.thenBody);
|
|
1010
1097
|
const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
|
|
1011
1098
|
const thenPath = [
|
|
1012
|
-
...
|
|
1099
|
+
...path11,
|
|
1013
1100
|
branchCond(stmt, stmt.condition, "positive", elseExit)
|
|
1014
1101
|
];
|
|
1015
1102
|
const elsePath = [
|
|
1016
|
-
...
|
|
1103
|
+
...path11,
|
|
1017
1104
|
branchCond(
|
|
1018
1105
|
stmt,
|
|
1019
1106
|
stmt.condition,
|
|
@@ -1030,7 +1117,7 @@ function stepIf(stmt, path10, ctx) {
|
|
|
1030
1117
|
}
|
|
1031
1118
|
return out;
|
|
1032
1119
|
}
|
|
1033
|
-
function stepSwitch(stmt,
|
|
1120
|
+
function stepSwitch(stmt, path11, ctx) {
|
|
1034
1121
|
const out = [];
|
|
1035
1122
|
const negations = [];
|
|
1036
1123
|
let defaultRanBody = false;
|
|
@@ -1040,7 +1127,7 @@ function stepSwitch(stmt, path10, ctx) {
|
|
|
1040
1127
|
if (hasStrayBreak(group.body)) {
|
|
1041
1128
|
throw new UnmodeledFlow("non-trailing break in switch clause");
|
|
1042
1129
|
}
|
|
1043
|
-
const groupPath = group.condition === null ? [...
|
|
1130
|
+
const groupPath = group.condition === null ? [...path11, ...negations] : [...path11, fixedCond(group.condition, "positive", "explicit")];
|
|
1044
1131
|
const conts = enumerate(ctx, group.body, groupPath);
|
|
1045
1132
|
if (conts.length > 0) {
|
|
1046
1133
|
if (!group.hasTrailingBreak && !fallthroughSafe) {
|
|
@@ -1057,24 +1144,24 @@ function stepSwitch(stmt, path10, ctx) {
|
|
|
1057
1144
|
}
|
|
1058
1145
|
}
|
|
1059
1146
|
if (!defaultRanBody) {
|
|
1060
|
-
out.push([...
|
|
1147
|
+
out.push([...path11, ...negations]);
|
|
1061
1148
|
}
|
|
1062
1149
|
return out;
|
|
1063
1150
|
}
|
|
1064
|
-
function stepLoop(stmt,
|
|
1151
|
+
function stepLoop(stmt, path11, ctx) {
|
|
1065
1152
|
const bodyExit = exitKindOfList(stmt.body);
|
|
1066
1153
|
if (containsTerminal(ctx, stmt)) {
|
|
1067
1154
|
enumerate(ctx, stmt.body, [
|
|
1068
|
-
...
|
|
1155
|
+
...path11,
|
|
1069
1156
|
loopIterationCond(stmt.condition.sourceText)
|
|
1070
1157
|
]);
|
|
1071
1158
|
}
|
|
1072
1159
|
if (bodyExit !== null) {
|
|
1073
|
-
return [[...
|
|
1160
|
+
return [[...path11, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
|
|
1074
1161
|
}
|
|
1075
|
-
return [
|
|
1162
|
+
return [path11];
|
|
1076
1163
|
}
|
|
1077
|
-
function stepTry(stmt,
|
|
1164
|
+
function stepTry(stmt, path11, ctx) {
|
|
1078
1165
|
if (stmt.finallyBody !== null) {
|
|
1079
1166
|
const finallyHasTerminal = stmt.finallyBody.some(
|
|
1080
1167
|
(s) => containsTerminal(ctx, s)
|
|
@@ -1084,22 +1171,22 @@ function stepTry(stmt, path10, ctx) {
|
|
|
1084
1171
|
}
|
|
1085
1172
|
}
|
|
1086
1173
|
const out = [];
|
|
1087
|
-
out.push(...enumerate(ctx, stmt.tryBody,
|
|
1174
|
+
out.push(...enumerate(ctx, stmt.tryBody, path11));
|
|
1088
1175
|
if (stmt.catchBody !== null) {
|
|
1089
|
-
const catchPath = [...
|
|
1176
|
+
const catchPath = [...path11, catchEntryCond()];
|
|
1090
1177
|
out.push(...enumerate(ctx, stmt.catchBody, catchPath));
|
|
1091
1178
|
}
|
|
1092
1179
|
return out;
|
|
1093
1180
|
}
|
|
1094
|
-
function stepExit(stmt,
|
|
1181
|
+
function stepExit(stmt, path11, ctx) {
|
|
1095
1182
|
const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
|
|
1096
1183
|
if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
|
|
1097
|
-
collector.push(
|
|
1184
|
+
collector.push(path11);
|
|
1098
1185
|
}
|
|
1099
1186
|
return [];
|
|
1100
1187
|
}
|
|
1101
|
-
function stepOpaque(_stmt,
|
|
1102
|
-
return [
|
|
1188
|
+
function stepOpaque(_stmt, path11, _ctx) {
|
|
1189
|
+
return [path11];
|
|
1103
1190
|
}
|
|
1104
1191
|
var stepHandlers = {
|
|
1105
1192
|
if: stepIf,
|
|
@@ -1109,20 +1196,20 @@ var stepHandlers = {
|
|
|
1109
1196
|
exit: stepExit,
|
|
1110
1197
|
opaque: stepOpaque
|
|
1111
1198
|
};
|
|
1112
|
-
function stepCallback(ctx, body,
|
|
1199
|
+
function stepCallback(ctx, body, path11) {
|
|
1113
1200
|
const exits = [];
|
|
1114
1201
|
ctx.state.callbackExits.push(exits);
|
|
1115
1202
|
let fellThrough;
|
|
1116
1203
|
try {
|
|
1117
|
-
fellThrough = enumerate(ctx, body,
|
|
1204
|
+
fellThrough = enumerate(ctx, body, path11);
|
|
1118
1205
|
} finally {
|
|
1119
1206
|
ctx.state.callbackExits.pop();
|
|
1120
1207
|
}
|
|
1121
1208
|
const out = [...fellThrough, ...exits];
|
|
1122
|
-
return out.length === 0 ? [
|
|
1209
|
+
return out.length === 0 ? [path11] : out;
|
|
1123
1210
|
}
|
|
1124
|
-
function stepStatement(ctx, stmt,
|
|
1125
|
-
let paths = [
|
|
1211
|
+
function stepStatement(ctx, stmt, path11) {
|
|
1212
|
+
let paths = [path11];
|
|
1126
1213
|
for (const body of stmt.callbacks ?? []) {
|
|
1127
1214
|
paths = paths.flatMap((each) => stepCallback(ctx, body, each));
|
|
1128
1215
|
limitOpenPaths(paths);
|
|
@@ -1209,8 +1296,8 @@ function enumerate(ctx, stmts, prefix) {
|
|
|
1209
1296
|
let frontiers = [[...prefix]];
|
|
1210
1297
|
for (const stmt of stmts) {
|
|
1211
1298
|
const nextFrontiers = [];
|
|
1212
|
-
for (const
|
|
1213
|
-
nextFrontiers.push(...stepStatement(ctx, stmt,
|
|
1299
|
+
for (const path11 of mergeRejoined(frontiers, ctx.keepsArms)) {
|
|
1300
|
+
nextFrontiers.push(...stepStatement(ctx, stmt, path11));
|
|
1214
1301
|
}
|
|
1215
1302
|
frontiers = nextFrontiers;
|
|
1216
1303
|
limitOpenPaths(frontiers);
|
|
@@ -1234,6 +1321,39 @@ function buildParentMap(statements) {
|
|
|
1234
1321
|
}
|
|
1235
1322
|
return parentOf;
|
|
1236
1323
|
}
|
|
1324
|
+
function placeTerminals(input, parentOf = buildParentMap(input.statements)) {
|
|
1325
|
+
const placement = /* @__PURE__ */ new Map();
|
|
1326
|
+
for (const [home, terminals] of input.terminalsByStmt) {
|
|
1327
|
+
const placed = placementOf(home, parentOf);
|
|
1328
|
+
if (placed.loopAround === void 0 && placed.cleansUpFrom === void 0) {
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
for (const terminal of terminals) {
|
|
1332
|
+
placement.set(terminal, placed);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
return placement;
|
|
1336
|
+
}
|
|
1337
|
+
function placementOf(home, parentOf) {
|
|
1338
|
+
let loopAround = home.kind === "loop" ? home.lines : void 0;
|
|
1339
|
+
let cleansUpFrom;
|
|
1340
|
+
let child = home;
|
|
1341
|
+
let parent = parentOf.get(home) ?? null;
|
|
1342
|
+
while (parent !== null) {
|
|
1343
|
+
if (parent.kind === "loop" && parent.lines !== void 0) {
|
|
1344
|
+
loopAround = parent.lines;
|
|
1345
|
+
}
|
|
1346
|
+
if (parent.kind === "try" && parent.lines !== void 0 && (parent.finallyBody ?? []).includes(child)) {
|
|
1347
|
+
cleansUpFrom = parent.lines.start;
|
|
1348
|
+
}
|
|
1349
|
+
child = parent;
|
|
1350
|
+
parent = parentOf.get(parent) ?? null;
|
|
1351
|
+
}
|
|
1352
|
+
return {
|
|
1353
|
+
...loopAround === void 0 ? {} : { loopAround: { start: loopAround.start, end: loopAround.end } },
|
|
1354
|
+
...cleansUpFrom === void 0 ? {} : { cleansUpFrom }
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1237
1357
|
function enumerateStructuredPaths(input) {
|
|
1238
1358
|
const parentOf = buildParentMap(input.statements);
|
|
1239
1359
|
const isAncestorOrSelf = (a, b) => {
|
|
@@ -1259,11 +1379,15 @@ function enumerateStructuredPaths(input) {
|
|
|
1259
1379
|
isAncestorOrSelf
|
|
1260
1380
|
};
|
|
1261
1381
|
const continuations = withRejoined(enumerate(ctx, input.statements, []));
|
|
1262
|
-
for (const
|
|
1382
|
+
for (const path11 of continuations) {
|
|
1263
1383
|
chargeBudget(state);
|
|
1264
|
-
state.fallthrough.push(classify(
|
|
1384
|
+
state.fallthrough.push(classify(path11, null, isAncestorOrSelf));
|
|
1265
1385
|
}
|
|
1266
|
-
return {
|
|
1386
|
+
return {
|
|
1387
|
+
byTerminal: state.byTerminal,
|
|
1388
|
+
fallthrough: state.fallthrough,
|
|
1389
|
+
placement: placeTerminals(input, parentOf)
|
|
1390
|
+
};
|
|
1267
1391
|
}
|
|
1268
1392
|
function enumerateOrDegrade(input, terminals) {
|
|
1269
1393
|
try {
|
|
@@ -1283,9 +1407,28 @@ function enumerateOrDegrade(input, terminals) {
|
|
|
1283
1407
|
for (const terminal of terminals) {
|
|
1284
1408
|
byTerminal.set(terminal, [[marker]]);
|
|
1285
1409
|
}
|
|
1286
|
-
return {
|
|
1410
|
+
return {
|
|
1411
|
+
byTerminal,
|
|
1412
|
+
fallthrough: [[marker]],
|
|
1413
|
+
placement: placeTerminals(input),
|
|
1414
|
+
degraded: reason
|
|
1415
|
+
};
|
|
1287
1416
|
}
|
|
1288
1417
|
}
|
|
1418
|
+
function enumerateCallStatements(input, terminals) {
|
|
1419
|
+
const placement = placeTerminals(input);
|
|
1420
|
+
const enumerable = new Map(
|
|
1421
|
+
[...input.terminalsByStmt].filter(
|
|
1422
|
+
([, found]) => found.every(
|
|
1423
|
+
(terminal) => placement.get(terminal)?.cleansUpFrom === void 0
|
|
1424
|
+
)
|
|
1425
|
+
)
|
|
1426
|
+
);
|
|
1427
|
+
return {
|
|
1428
|
+
...enumerateOrDegrade({ ...input, terminalsByStmt: enumerable }, terminals),
|
|
1429
|
+
placement
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1289
1432
|
function reasonToDegrade(error) {
|
|
1290
1433
|
if (error instanceof PathBudgetExceeded) {
|
|
1291
1434
|
return error.message === "" ? "path budget exceeded" : error.message;
|
|
@@ -1304,8 +1447,8 @@ function sharedGatingConditions(paths, readPredicate) {
|
|
|
1304
1447
|
return [];
|
|
1305
1448
|
}
|
|
1306
1449
|
const shared = new Set(first.map(keyOf2));
|
|
1307
|
-
for (const
|
|
1308
|
-
const here = new Set(
|
|
1450
|
+
for (const path11 of rest) {
|
|
1451
|
+
const here = new Set(path11.map(keyOf2));
|
|
1309
1452
|
for (const value of shared) {
|
|
1310
1453
|
if (!here.has(value)) {
|
|
1311
1454
|
shared.delete(value);
|
|
@@ -1423,6 +1566,43 @@ function walkDescendants(root, carried, childrenOf2, visitor) {
|
|
|
1423
1566
|
}
|
|
1424
1567
|
}
|
|
1425
1568
|
|
|
1569
|
+
// src/paths/statementSites.ts
|
|
1570
|
+
function statementSites(nodes, reading) {
|
|
1571
|
+
const statements = new IdMap();
|
|
1572
|
+
const statementOfNode = new IdMap();
|
|
1573
|
+
for (const node of nodes) {
|
|
1574
|
+
const written = reading.statementOf(node);
|
|
1575
|
+
if (written === null) {
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
const statement = statements.get(written) ?? written;
|
|
1579
|
+
statements.set(statement, statement);
|
|
1580
|
+
statementOfNode.set(node, statement);
|
|
1581
|
+
}
|
|
1582
|
+
const terminals = [...statements].map(([statement]) => statement);
|
|
1583
|
+
const enumerated = enumerateCallStatements(
|
|
1584
|
+
reading.lower(terminals),
|
|
1585
|
+
terminals
|
|
1586
|
+
);
|
|
1587
|
+
const pathsTo = (node) => {
|
|
1588
|
+
const statement = statementOfNode.get(node);
|
|
1589
|
+
return statement === void 0 ? void 0 : enumerated.byTerminal.get(statement);
|
|
1590
|
+
};
|
|
1591
|
+
const siteOf = (node, preconditions) => {
|
|
1592
|
+
const statement = statementOfNode.get(node);
|
|
1593
|
+
return {
|
|
1594
|
+
line: reading.firstLine(statement ?? node),
|
|
1595
|
+
preconditions,
|
|
1596
|
+
cleansUpFrom: statement === void 0 ? void 0 : enumerated.placement.get(statement)?.cleansUpFrom
|
|
1597
|
+
};
|
|
1598
|
+
};
|
|
1599
|
+
return {
|
|
1600
|
+
pathsTo,
|
|
1601
|
+
siteOf,
|
|
1602
|
+
plainSiteOf: (node) => siteOf(node, sharedGatingConditions(pathsTo(node)))
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1426
1606
|
// src/projectRoot.ts
|
|
1427
1607
|
import path3 from "path";
|
|
1428
1608
|
function commonDirectoryOf(files) {
|
|
@@ -1571,13 +1751,13 @@ function quoted(text, key) {
|
|
|
1571
1751
|
}
|
|
1572
1752
|
|
|
1573
1753
|
// src/adapterStamp.ts
|
|
1574
|
-
import { createHash as
|
|
1754
|
+
import { createHash as createHash3 } from "crypto";
|
|
1575
1755
|
import fs3 from "fs";
|
|
1576
1756
|
import path5 from "path";
|
|
1577
1757
|
import { fileURLToPath } from "url";
|
|
1578
1758
|
|
|
1579
1759
|
// src/codeHash.ts
|
|
1580
|
-
import { createHash } from "crypto";
|
|
1760
|
+
import { createHash as createHash2 } from "crypto";
|
|
1581
1761
|
import fs2 from "fs";
|
|
1582
1762
|
import { createRequire } from "module";
|
|
1583
1763
|
import path4 from "path";
|
|
@@ -1623,7 +1803,7 @@ function createCodeHasher() {
|
|
|
1623
1803
|
if (files.length === 0) {
|
|
1624
1804
|
return "";
|
|
1625
1805
|
}
|
|
1626
|
-
const hash =
|
|
1806
|
+
const hash = createHash2("sha256");
|
|
1627
1807
|
for (const file of files) {
|
|
1628
1808
|
hash.update(read.get(file)?.digest ?? "");
|
|
1629
1809
|
}
|
|
@@ -1640,7 +1820,7 @@ function readCodeFile(file) {
|
|
|
1640
1820
|
return null;
|
|
1641
1821
|
}
|
|
1642
1822
|
return {
|
|
1643
|
-
digest:
|
|
1823
|
+
digest: createHash2("sha256").update(text).digest("hex"),
|
|
1644
1824
|
imports: importsOf(file, text.toString("utf8"))
|
|
1645
1825
|
};
|
|
1646
1826
|
}
|
|
@@ -1798,7 +1978,7 @@ function computeContentHash(paths) {
|
|
|
1798
1978
|
if (paths.length === 0) {
|
|
1799
1979
|
return "";
|
|
1800
1980
|
}
|
|
1801
|
-
const hash =
|
|
1981
|
+
const hash = createHash3("sha256");
|
|
1802
1982
|
for (const file of paths) {
|
|
1803
1983
|
try {
|
|
1804
1984
|
hash.update(fs3.readFileSync(file));
|
|
@@ -1812,7 +1992,7 @@ function projectFileStamp(paths) {
|
|
|
1812
1992
|
if (paths.length === 0) {
|
|
1813
1993
|
return "none";
|
|
1814
1994
|
}
|
|
1815
|
-
const hash =
|
|
1995
|
+
const hash = createHash3("sha256");
|
|
1816
1996
|
for (const file of [...paths].sort()) {
|
|
1817
1997
|
hash.update(file);
|
|
1818
1998
|
hash.update("\0");
|
|
@@ -1847,7 +2027,7 @@ function runDigest(packsDigest, packs, files) {
|
|
|
1847
2027
|
}
|
|
1848
2028
|
|
|
1849
2029
|
// src/cache.ts
|
|
1850
|
-
import { createHash as
|
|
2030
|
+
import { createHash as createHash6 } from "crypto";
|
|
1851
2031
|
import fs7 from "fs/promises";
|
|
1852
2032
|
import path8 from "path";
|
|
1853
2033
|
import { readJsonFile as readJsonFile3, writeDocumentFile as writeDocumentFile2 } from "@suss/behavioral-ir/files";
|
|
@@ -1955,7 +2135,7 @@ function keyOf3(binding) {
|
|
|
1955
2135
|
}
|
|
1956
2136
|
|
|
1957
2137
|
// src/cacheShards.ts
|
|
1958
|
-
import { createHash as
|
|
2138
|
+
import { createHash as createHash4 } from "crypto";
|
|
1959
2139
|
import fs4 from "fs";
|
|
1960
2140
|
import path6 from "path";
|
|
1961
2141
|
import {
|
|
@@ -2021,7 +2201,7 @@ function namesIn(dir) {
|
|
|
2021
2201
|
}
|
|
2022
2202
|
function writeOnce(root, value) {
|
|
2023
2203
|
const pieces = [...documentPieces(value)];
|
|
2024
|
-
const hash =
|
|
2204
|
+
const hash = createHash4("sha256");
|
|
2025
2205
|
for (const piece of pieces) {
|
|
2026
2206
|
hash.update(piece);
|
|
2027
2207
|
}
|
|
@@ -2125,7 +2305,7 @@ function copyOfJson(value) {
|
|
|
2125
2305
|
}
|
|
2126
2306
|
|
|
2127
2307
|
// src/cacheStamps.ts
|
|
2128
|
-
import { createHash as
|
|
2308
|
+
import { createHash as createHash5 } from "crypto";
|
|
2129
2309
|
import fs5 from "fs/promises";
|
|
2130
2310
|
var RECENT_CHANGE_MS = 2e3;
|
|
2131
2311
|
function stampMayMissAWrite(stat, statAt) {
|
|
@@ -2215,7 +2395,7 @@ function reusableHash(prior, stamp) {
|
|
|
2215
2395
|
async function hashFile(filePath) {
|
|
2216
2396
|
try {
|
|
2217
2397
|
const content = await fs5.readFile(filePath);
|
|
2218
|
-
return
|
|
2398
|
+
return createHash5("sha256").update(content).digest("hex").slice(0, 16);
|
|
2219
2399
|
} catch {
|
|
2220
2400
|
return null;
|
|
2221
2401
|
}
|
|
@@ -2671,7 +2851,7 @@ function entryDirFor(cacheDir, input) {
|
|
|
2671
2851
|
input.adapterPacksDigest,
|
|
2672
2852
|
input.configPath ?? ""
|
|
2673
2853
|
].join(" ");
|
|
2674
|
-
const name =
|
|
2854
|
+
const name = createHash6("sha256").update(key).digest("hex").slice(0, 16);
|
|
2675
2855
|
return path8.join(cacheDir, `${ENTRY_PREFIX}${name}`);
|
|
2676
2856
|
}
|
|
2677
2857
|
function isEntryDir(name) {
|
|
@@ -2745,7 +2925,7 @@ async function readManifest2(manifestPath) {
|
|
|
2745
2925
|
}
|
|
2746
2926
|
|
|
2747
2927
|
// src/cacheLocation.ts
|
|
2748
|
-
import { createHash as
|
|
2928
|
+
import { createHash as createHash7 } from "crypto";
|
|
2749
2929
|
import fs8 from "fs";
|
|
2750
2930
|
import path9 from "path";
|
|
2751
2931
|
var CACHE_DIR_ENV = "SUSS_CACHE_DIR";
|
|
@@ -2764,7 +2944,7 @@ function realPathOrSelf(dir) {
|
|
|
2764
2944
|
}
|
|
2765
2945
|
}
|
|
2766
2946
|
function projectKey(projectDir) {
|
|
2767
|
-
return
|
|
2947
|
+
return createHash7("sha256").update(realPathOrSelf(path9.resolve(projectDir))).digest("hex").slice(0, 16);
|
|
2768
2948
|
}
|
|
2769
2949
|
function extractionCacheDirFor(projectDir) {
|
|
2770
2950
|
const root = chosenCacheRoot();
|
|
@@ -2773,6 +2953,13 @@ function extractionCacheDirFor(projectDir) {
|
|
|
2773
2953
|
}
|
|
2774
2954
|
return path9.join(root, "cache", projectKey(projectDir));
|
|
2775
2955
|
}
|
|
2956
|
+
function mapFolderFor(projectDir) {
|
|
2957
|
+
const root = chosenCacheRoot();
|
|
2958
|
+
if (root === null) {
|
|
2959
|
+
return path9.join(projectDir, ".suss");
|
|
2960
|
+
}
|
|
2961
|
+
return path9.join(root, "map", projectKey(projectDir));
|
|
2962
|
+
}
|
|
2776
2963
|
function liveRecordFor(projectDir) {
|
|
2777
2964
|
const root = chosenCacheRoot();
|
|
2778
2965
|
if (root === null) {
|
|
@@ -2921,6 +3108,7 @@ var KeptParses = class {
|
|
|
2921
3108
|
};
|
|
2922
3109
|
|
|
2923
3110
|
// src/packHealth.ts
|
|
3111
|
+
import path10 from "path";
|
|
2924
3112
|
function stagesOf(funnel) {
|
|
2925
3113
|
const stages = [];
|
|
2926
3114
|
const gateSaysSomething = funnel.gates.length > 0 && funnel.unresolvedGates.length === 0;
|
|
@@ -3068,6 +3256,30 @@ function packConfigCheck(needs) {
|
|
|
3068
3256
|
}))
|
|
3069
3257
|
};
|
|
3070
3258
|
}
|
|
3259
|
+
function describeMissingPath(missing) {
|
|
3260
|
+
const where = `${missing.option} is ${missing.value} in ${missing.configFile}`;
|
|
3261
|
+
if (path10.isAbsolute(missing.value)) {
|
|
3262
|
+
return {
|
|
3263
|
+
problem: `${where}, and nothing exists there.`,
|
|
3264
|
+
fix: `Set ${missing.option} to a path that exists.`
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3267
|
+
return {
|
|
3268
|
+
problem: `${where}, and nothing exists at ${missing.resolved}. A relative path is read against the config file, not the project.`,
|
|
3269
|
+
fix: missing.inProject === void 0 ? `Set ${missing.option} to an absolute path, or move the config file into the project.` : `Set ${missing.option} to ${missing.inProject} in the config file, or move the config file into the project.`
|
|
3270
|
+
};
|
|
3271
|
+
}
|
|
3272
|
+
function packPathCheck(missing) {
|
|
3273
|
+
return {
|
|
3274
|
+
name: "every path a pack config gives exists",
|
|
3275
|
+
code: "no-path",
|
|
3276
|
+
audience: "run",
|
|
3277
|
+
violations: missing.map((one) => {
|
|
3278
|
+
const { problem, fix } = describeMissingPath(one);
|
|
3279
|
+
return { label: one.pack, detail: `${problem} ${fix}` };
|
|
3280
|
+
})
|
|
3281
|
+
};
|
|
3282
|
+
}
|
|
3071
3283
|
function evaluatePackHealth(report) {
|
|
3072
3284
|
const gradients = packGradients(report);
|
|
3073
3285
|
return [
|
|
@@ -3220,7 +3432,7 @@ function makeTransitionId(functionName, branch) {
|
|
|
3220
3432
|
const { terminal } = branch;
|
|
3221
3433
|
const statusKey = terminal.statusCode === null ? "none" : terminal.statusCode.type === "literal" ? String(terminal.statusCode.value) : `dyn:${terminal.statusCode.sourceText}`;
|
|
3222
3434
|
const conditionSig = branch.conditions.map((c) => `${c.polarity}:${c.sourceText}`).join(";");
|
|
3223
|
-
const conditionHash =
|
|
3435
|
+
const conditionHash = createHash8("sha1").update(conditionSig).digest("hex").slice(0, 7);
|
|
3224
3436
|
return `${functionName}:${terminal.kind}:${statusKey}:${conditionHash}`;
|
|
3225
3437
|
}
|
|
3226
3438
|
function collapseReading(table, reading) {
|
|
@@ -3295,11 +3507,11 @@ function provenanceOf(raw, effects) {
|
|
|
3295
3507
|
if (raw.length === 0) {
|
|
3296
3508
|
return [];
|
|
3297
3509
|
}
|
|
3298
|
-
const positionOf = new Map(effects.map((one, at) => [
|
|
3510
|
+
const positionOf = new Map(effects.map((one, at) => [effectKey2(one), at]));
|
|
3299
3511
|
const bySlot = /* @__PURE__ */ new Map();
|
|
3300
3512
|
const said = /* @__PURE__ */ new Map();
|
|
3301
3513
|
for (const one of raw) {
|
|
3302
|
-
const effect = positionOf.get(
|
|
3514
|
+
const effect = positionOf.get(effectKey2(withNormalizedCallee(one.effect)));
|
|
3303
3515
|
if (effect === void 0) {
|
|
3304
3516
|
continue;
|
|
3305
3517
|
}
|
|
@@ -3331,7 +3543,7 @@ function withNormalizedCallee(effect) {
|
|
|
3331
3543
|
if (effect.callee === void 0) {
|
|
3332
3544
|
return effect;
|
|
3333
3545
|
}
|
|
3334
|
-
return { ...effect, callee:
|
|
3546
|
+
return { ...effect, callee: normalizeCalleeText2(effect.callee) };
|
|
3335
3547
|
}
|
|
3336
3548
|
function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
3337
3549
|
const transitions = raw.branches.map((rawBranch) => {
|
|
@@ -3419,6 +3631,9 @@ function buildMetadata(raw) {
|
|
|
3419
3631
|
if (raw.test !== void 0) {
|
|
3420
3632
|
metadata = withTestMetadata(metadata, raw.test);
|
|
3421
3633
|
}
|
|
3634
|
+
if (raw.packMetadata !== void 0) {
|
|
3635
|
+
metadata = { ...metadata, ...raw.packMetadata };
|
|
3636
|
+
}
|
|
3422
3637
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
3423
3638
|
}
|
|
3424
3639
|
function buildHttpMetadataValue(raw) {
|
|
@@ -3470,6 +3685,12 @@ function buildGraphqlMetadataValue(raw) {
|
|
|
3470
3685
|
if (raw.graphqlUnresolvedDocument !== void 0) {
|
|
3471
3686
|
graphql.unresolvedDocument = raw.graphqlUnresolvedDocument;
|
|
3472
3687
|
}
|
|
3688
|
+
if (raw.graphqlClient !== void 0) {
|
|
3689
|
+
graphql.client = raw.graphqlClient;
|
|
3690
|
+
}
|
|
3691
|
+
if (raw.graphqlUnresolvedClient !== void 0) {
|
|
3692
|
+
graphql.unresolvedClient = raw.graphqlUnresolvedClient;
|
|
3693
|
+
}
|
|
3473
3694
|
return Object.keys(graphql).length > 0 ? graphql : null;
|
|
3474
3695
|
}
|
|
3475
3696
|
function answersWithHttpResponses(raw) {
|
|
@@ -3661,7 +3882,10 @@ var effectConverters = {
|
|
|
3661
3882
|
stateChange: (e) => ({ type: "stateChange", variable: e.variable })
|
|
3662
3883
|
};
|
|
3663
3884
|
function effectToIR(effect) {
|
|
3664
|
-
|
|
3885
|
+
const converted = effectConverters[effect.type](
|
|
3886
|
+
effect
|
|
3887
|
+
);
|
|
3888
|
+
return effect.location === void 0 ? converted : { ...converted, location: effect.location };
|
|
3665
3889
|
}
|
|
3666
3890
|
function paramToInput(param) {
|
|
3667
3891
|
return {
|
|
@@ -3692,6 +3916,7 @@ export {
|
|
|
3692
3916
|
assembleSummary,
|
|
3693
3917
|
assessConfidence,
|
|
3694
3918
|
buildUngatedExtractionReport,
|
|
3919
|
+
callSiteKey,
|
|
3695
3920
|
chosenCacheRoot,
|
|
3696
3921
|
commonDirectoryOf,
|
|
3697
3922
|
composeWrappers,
|
|
@@ -3703,23 +3928,28 @@ export {
|
|
|
3703
3928
|
createCodeHasher,
|
|
3704
3929
|
createPackTallies,
|
|
3705
3930
|
createTimer,
|
|
3931
|
+
describeMissingPath,
|
|
3706
3932
|
detectGaps,
|
|
3707
3933
|
effectToIR,
|
|
3934
|
+
effectsFiringOn,
|
|
3708
3935
|
emptyTally,
|
|
3709
3936
|
enumerateOrDegrade,
|
|
3710
3937
|
enumerateStructuredPaths,
|
|
3711
3938
|
evaluatePackHealth,
|
|
3712
3939
|
extractionCacheDirFor,
|
|
3713
3940
|
extractionConfigStamp,
|
|
3941
|
+
firesOn,
|
|
3714
3942
|
firstWrittenReading,
|
|
3715
3943
|
formatPackHealth,
|
|
3716
3944
|
guardsHoldOn,
|
|
3717
3945
|
helperPathsOnVariables,
|
|
3718
3946
|
httpRouteDiscovery,
|
|
3719
3947
|
isListedTestFile,
|
|
3948
|
+
libraryEnvReadMarker,
|
|
3720
3949
|
liveRecordFor,
|
|
3721
3950
|
makeIgnoredDirectory,
|
|
3722
3951
|
makeTransitionId,
|
|
3952
|
+
mapFolderFor,
|
|
3723
3953
|
mapReading,
|
|
3724
3954
|
markReturnsAsExitCode,
|
|
3725
3955
|
matchesTestFileName,
|
|
@@ -3727,10 +3957,13 @@ export {
|
|
|
3727
3957
|
moduleInitStructure,
|
|
3728
3958
|
moduleOfFile,
|
|
3729
3959
|
noopTimer,
|
|
3960
|
+
numberRepeatedCallSites,
|
|
3730
3961
|
ownersWhereWritten,
|
|
3731
3962
|
packConfigCheck,
|
|
3732
3963
|
packGradients,
|
|
3964
|
+
packPathCheck,
|
|
3733
3965
|
paramToInput,
|
|
3966
|
+
placeTerminals,
|
|
3734
3967
|
processCodeHasher,
|
|
3735
3968
|
projectFileStamp,
|
|
3736
3969
|
rawConditionToPredicate,
|
|
@@ -3748,6 +3981,7 @@ export {
|
|
|
3748
3981
|
stampMayMissAWrite,
|
|
3749
3982
|
stampModuleImports,
|
|
3750
3983
|
stampModules,
|
|
3984
|
+
statementSites,
|
|
3751
3985
|
storageSystemOption,
|
|
3752
3986
|
summaryCountsByPack,
|
|
3753
3987
|
tallyUnit,
|