@suss/extractor 0.34.0 → 0.34.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 +380 -94
- package/dist/index.d.cts +227 -9
- package/dist/index.d.ts +227 -9
- package/dist/index.js +363 -84
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -199,29 +199,82 @@ function composeOne(summary, chain, keepGaps) {
|
|
|
199
199
|
if (wrappers.length === 0) {
|
|
200
200
|
return narrowed;
|
|
201
201
|
}
|
|
202
|
-
const responses = respondedInstead(wrappers);
|
|
203
|
-
const
|
|
204
|
-
const
|
|
202
|
+
const responses = settledUncaught(respondedInstead(wrappers), wrappers);
|
|
203
|
+
const unitOwn = settledUncaught(summary.transitions, wrappers);
|
|
204
|
+
const own = [...responses, ...unitOwn];
|
|
205
|
+
const handled = handledThrows(wrappers, thrownBy(own));
|
|
206
|
+
const transitions = beside(summary, unitOwn, responses, handled);
|
|
205
207
|
if (!keepGaps) {
|
|
206
208
|
return transitions === summary.transitions ? narrowed : { ...narrowed, transitions };
|
|
207
209
|
}
|
|
208
210
|
const gaps = withContractStatusGaps(
|
|
209
211
|
summary,
|
|
210
|
-
|
|
211
|
-
|
|
212
|
+
own,
|
|
213
|
+
everyHandlerOutcome(wrappers)
|
|
212
214
|
);
|
|
213
215
|
if (transitions === summary.transitions && gaps === summary.gaps) {
|
|
214
216
|
return narrowed;
|
|
215
217
|
}
|
|
216
218
|
return { ...narrowed, transitions, gaps };
|
|
217
219
|
}
|
|
218
|
-
function beside(summary, responses, handled) {
|
|
219
|
-
|
|
220
|
-
const onThrow = throws ? handled : [];
|
|
221
|
-
if (responses.length === 0 && onThrow.length === 0) {
|
|
220
|
+
function beside(summary, unitOwn, responses, handled) {
|
|
221
|
+
if (responses.length === 0 && handled.length === 0 && unitOwn === summary.transitions) {
|
|
222
222
|
return summary.transitions;
|
|
223
223
|
}
|
|
224
|
-
return withDistinctIds([...responses, ...
|
|
224
|
+
return withDistinctIds([...responses, ...unitOwn, ...handled]);
|
|
225
|
+
}
|
|
226
|
+
function settledUncaught(transitions, wrappers) {
|
|
227
|
+
const handlers = wrappers.filter(
|
|
228
|
+
(wrapper) => wrapper.reference.onThrow === true
|
|
229
|
+
);
|
|
230
|
+
let changed = false;
|
|
231
|
+
const settled = transitions.flatMap((transition) => {
|
|
232
|
+
const { output } = transition;
|
|
233
|
+
if (output.type !== "throw") {
|
|
234
|
+
return [transition];
|
|
235
|
+
}
|
|
236
|
+
const caught = caughtOnRoute(handlers, output);
|
|
237
|
+
if (caught === "sure") {
|
|
238
|
+
changed = true;
|
|
239
|
+
return [markedCaught(transition)];
|
|
240
|
+
}
|
|
241
|
+
if (output.statusWhenUncaught === void 0) {
|
|
242
|
+
return [transition];
|
|
243
|
+
}
|
|
244
|
+
changed = true;
|
|
245
|
+
const response = {
|
|
246
|
+
...transition,
|
|
247
|
+
output: {
|
|
248
|
+
type: "response",
|
|
249
|
+
statusCode: { type: "literal", value: output.statusWhenUncaught },
|
|
250
|
+
body: null,
|
|
251
|
+
headers: {}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
return caught === "uncertain" ? [transition, response] : [response];
|
|
255
|
+
});
|
|
256
|
+
return changed ? settled : transitions;
|
|
257
|
+
}
|
|
258
|
+
function markedCaught(transition) {
|
|
259
|
+
return {
|
|
260
|
+
...transition,
|
|
261
|
+
metadata: withWrapperMetadata(transition.metadata, {
|
|
262
|
+
...readWrapperMetadata2(transition),
|
|
263
|
+
caught: true
|
|
264
|
+
})
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function caughtOnRoute(handlers, thrown) {
|
|
268
|
+
if (handlers.some((handler) => handler.reference.catches === void 0)) {
|
|
269
|
+
return "sure";
|
|
270
|
+
}
|
|
271
|
+
const matches = handlers.map(
|
|
272
|
+
(handler) => catchMatch(handler.reference, thrown)
|
|
273
|
+
);
|
|
274
|
+
if (matches.includes("yes")) {
|
|
275
|
+
return "sure";
|
|
276
|
+
}
|
|
277
|
+
return matches.includes("maybe") ? "uncertain" : "no";
|
|
225
278
|
}
|
|
226
279
|
function respondedInstead(wrappers) {
|
|
227
280
|
return wrappers.flatMap(
|
|
@@ -233,11 +286,91 @@ function respondedInstead(wrappers) {
|
|
|
233
286
|
)
|
|
234
287
|
);
|
|
235
288
|
}
|
|
236
|
-
function
|
|
289
|
+
function thrownBy(transitions) {
|
|
290
|
+
return transitions.flatMap(
|
|
291
|
+
(t) => t.output.type === "throw" ? [t.output] : []
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
function everyHandlerOutcome(wrappers) {
|
|
237
295
|
return wrappers.flatMap(
|
|
238
296
|
(wrapper) => wrapper.reference.onThrow === true ? attribute(wrapper.summary.transitions, wrapper.reference) : []
|
|
239
297
|
);
|
|
240
298
|
}
|
|
299
|
+
function handledThrows(wrappers, thrown) {
|
|
300
|
+
const caught = catchesAny(wrappers, thrown);
|
|
301
|
+
return [...oncePerHandler(wrappers, caught)].flatMap(
|
|
302
|
+
([wrapper, how]) => attribute(
|
|
303
|
+
wrapper.summary.transitions,
|
|
304
|
+
wrapper.reference,
|
|
305
|
+
how === "uncertain"
|
|
306
|
+
)
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
function oncePerHandler(wrappers, caught) {
|
|
310
|
+
const byHandler = /* @__PURE__ */ new Map();
|
|
311
|
+
for (const wrapper of wrappers) {
|
|
312
|
+
const how = caught.get(wrapper);
|
|
313
|
+
if (how === void 0) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const earlier = byHandler.get(wrapper.summary);
|
|
317
|
+
if (earlier === void 0 || earlier[1] === "uncertain" && how === "sure") {
|
|
318
|
+
byHandler.set(wrapper.summary, [wrapper, how]);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return new Map(byHandler.values());
|
|
322
|
+
}
|
|
323
|
+
function catchesAny(wrappers, thrown) {
|
|
324
|
+
const caught = /* @__PURE__ */ new Map();
|
|
325
|
+
if (thrown.length === 0) {
|
|
326
|
+
return caught;
|
|
327
|
+
}
|
|
328
|
+
const handlers = wrappers.filter(
|
|
329
|
+
(wrapper) => wrapper.reference.onThrow === true
|
|
330
|
+
);
|
|
331
|
+
for (const handler of handlers) {
|
|
332
|
+
if (handler.reference.catches === void 0) {
|
|
333
|
+
caught.set(handler, "sure");
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const listing = handlers.filter(
|
|
337
|
+
(handler) => handler.reference.catches !== void 0
|
|
338
|
+
);
|
|
339
|
+
for (const one of thrown) {
|
|
340
|
+
for (const [handler, how] of catchersOf(listing, one)) {
|
|
341
|
+
if (caught.get(handler) !== "sure") {
|
|
342
|
+
caught.set(handler, how);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return caught;
|
|
347
|
+
}
|
|
348
|
+
function catchersOf(handlers, thrown) {
|
|
349
|
+
const found = [];
|
|
350
|
+
for (const handler of handlers) {
|
|
351
|
+
const match = catchMatch(handler.reference, thrown);
|
|
352
|
+
if (match === "yes") {
|
|
353
|
+
found.push([handler, found.length === 0 ? "sure" : "uncertain"]);
|
|
354
|
+
return found;
|
|
355
|
+
}
|
|
356
|
+
if (match === "maybe") {
|
|
357
|
+
found.push([handler, "uncertain"]);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return found;
|
|
361
|
+
}
|
|
362
|
+
function catchMatch(reference, thrown) {
|
|
363
|
+
const ancestors = thrown.exceptionAncestors;
|
|
364
|
+
if (thrown.exceptionType === null || ancestors === void 0) {
|
|
365
|
+
return "maybe";
|
|
366
|
+
}
|
|
367
|
+
const classes = /* @__PURE__ */ new Set([thrown.exceptionType, ...ancestors]);
|
|
368
|
+
if ((reference.catches ?? []).some((name) => classes.has(name))) {
|
|
369
|
+
return "yes";
|
|
370
|
+
}
|
|
371
|
+
const unread = thrown.ancestryIncomplete === true && reference.mayCatchUnreadClasses === true;
|
|
372
|
+
return unread || reference.mayCatchAny === true ? "maybe" : "no";
|
|
373
|
+
}
|
|
241
374
|
function withContractStatusGaps(summary, composed, handled) {
|
|
242
375
|
const contract = readHttpMetadata(summary)?.declaredContract;
|
|
243
376
|
const binding = summary.identity.boundaryBinding;
|
|
@@ -268,10 +401,13 @@ function coversUnit(reference, summary) {
|
|
|
268
401
|
const binding = summary.identity.boundaryBinding;
|
|
269
402
|
return binding !== null && withinScope(binding, reference.scope);
|
|
270
403
|
}
|
|
271
|
-
function attribute(transitions, reference) {
|
|
404
|
+
function attribute(transitions, reference, catchUncertain = false) {
|
|
272
405
|
return transitions.map((transition) => ({
|
|
273
406
|
...transition,
|
|
274
|
-
metadata: withWrapperMetadata(transition.metadata, {
|
|
407
|
+
metadata: withWrapperMetadata(transition.metadata, {
|
|
408
|
+
from: reference,
|
|
409
|
+
...catchUncertain ? { catchUncertain } : {}
|
|
410
|
+
})
|
|
275
411
|
}));
|
|
276
412
|
}
|
|
277
413
|
function withDistinctIds(transitions) {
|
|
@@ -384,6 +520,104 @@ function markExitCodeFrom(summary, marked) {
|
|
|
384
520
|
summary.metadata = left;
|
|
385
521
|
}
|
|
386
522
|
|
|
523
|
+
// src/helperHandOff.ts
|
|
524
|
+
import { predicateRefs, replacePredicateRefs } from "@suss/behavioral-ir";
|
|
525
|
+
var MAX_HELPER_PATHS = 16;
|
|
526
|
+
function throughHelper(branch, at, helperBranches) {
|
|
527
|
+
return helperBranches.map((helper) => {
|
|
528
|
+
const conditions = [...branch.conditions, ...helper.conditions];
|
|
529
|
+
const expectedInput = mergeReadShapes(
|
|
530
|
+
branch.expectedInput ?? null,
|
|
531
|
+
helper.expectedInput ?? null
|
|
532
|
+
);
|
|
533
|
+
const reads = expectedInput === null ? {} : { expectedInput };
|
|
534
|
+
if (helper.terminal.kind !== "throw" && helper.terminal.kind !== "exit") {
|
|
535
|
+
return {
|
|
536
|
+
...branch,
|
|
537
|
+
...reads,
|
|
538
|
+
conditions,
|
|
539
|
+
isDefault: branch.isDefault && helper.isDefault
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
return {
|
|
543
|
+
...branch,
|
|
544
|
+
...reads,
|
|
545
|
+
conditions,
|
|
546
|
+
terminal: { ...helper.terminal, location: at },
|
|
547
|
+
location: at,
|
|
548
|
+
isDefault: false
|
|
549
|
+
};
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
function mergeReadShapes(a, b) {
|
|
553
|
+
if (a === null || b === null) {
|
|
554
|
+
return a ?? b;
|
|
555
|
+
}
|
|
556
|
+
if (a.type !== "record" || b.type !== "record") {
|
|
557
|
+
return a.type === "record" ? a : b;
|
|
558
|
+
}
|
|
559
|
+
const properties = { ...a.properties };
|
|
560
|
+
for (const [name, shape] of Object.entries(b.properties)) {
|
|
561
|
+
const known = properties[name];
|
|
562
|
+
properties[name] = known === void 0 ? shape : mergeReadShapes(known, shape) ?? shape;
|
|
563
|
+
}
|
|
564
|
+
return { ...a, properties };
|
|
565
|
+
}
|
|
566
|
+
function splitAtHandOffs(branch, sites, from = 0) {
|
|
567
|
+
for (let index = from; index < sites.length; index++) {
|
|
568
|
+
const site = sites[index];
|
|
569
|
+
const reached = site.alwaysRuns === true || runsBefore(site.line, branch.terminal.location.end);
|
|
570
|
+
if (!reached || !guardsHoldOn(site.preconditions, branch.conditions)) {
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
return throughHelper(branch, site.at, site.helper).flatMap(
|
|
574
|
+
(path7) => path7.terminal === branch.terminal ? splitAtHandOffs(path7, sites, index + 1) : [path7]
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
return [branch];
|
|
578
|
+
}
|
|
579
|
+
function helperPathsOnVariables(helperBranches, passed) {
|
|
580
|
+
const renamed = helperBranches.map((branch) => ({
|
|
581
|
+
...branch,
|
|
582
|
+
conditions: branch.conditions.map((condition) => ({
|
|
583
|
+
...condition,
|
|
584
|
+
structured: condition.structured === null ? null : onCallerVariables(condition.structured, passed)
|
|
585
|
+
}))
|
|
586
|
+
}));
|
|
587
|
+
const variables = new Set(passed.values());
|
|
588
|
+
const testsWhatItGot = renamed.some(
|
|
589
|
+
(branch) => branch.conditions.some(
|
|
590
|
+
(condition) => condition.structured !== null && predicateRefs(condition.structured).some(
|
|
591
|
+
(ref) => variables.has(rootName(ref) ?? "")
|
|
592
|
+
)
|
|
593
|
+
)
|
|
594
|
+
);
|
|
595
|
+
return testsWhatItGot && renamed.length <= MAX_HELPER_PATHS ? renamed : null;
|
|
596
|
+
}
|
|
597
|
+
function onCallerVariables(predicate, passed) {
|
|
598
|
+
const rename = (ref) => {
|
|
599
|
+
if (ref.type === "derived") {
|
|
600
|
+
return { ...ref, from: rename(ref.from) };
|
|
601
|
+
}
|
|
602
|
+
if (ref.type === "input") {
|
|
603
|
+
const name = passed.get(ref.inputRef);
|
|
604
|
+
return name === void 0 ? ref : { type: "dependency", name, accessChain: ref.path };
|
|
605
|
+
}
|
|
606
|
+
if (ref.type === "dependency") {
|
|
607
|
+
const name = passed.get(ref.name);
|
|
608
|
+
return name === void 0 ? ref : { ...ref, name };
|
|
609
|
+
}
|
|
610
|
+
return ref;
|
|
611
|
+
};
|
|
612
|
+
return replacePredicateRefs(predicate, rename);
|
|
613
|
+
}
|
|
614
|
+
function rootName(ref) {
|
|
615
|
+
if (ref.type === "derived") {
|
|
616
|
+
return rootName(ref.from);
|
|
617
|
+
}
|
|
618
|
+
return ref.type === "dependency" ? ref.name : null;
|
|
619
|
+
}
|
|
620
|
+
|
|
387
621
|
// src/moduleImports.ts
|
|
388
622
|
function stampModuleImports(summaries, importsOf) {
|
|
389
623
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -685,8 +919,8 @@ var catchEntryCond = () => fixedCond(
|
|
|
685
919
|
"positive",
|
|
686
920
|
"catchBlock"
|
|
687
921
|
);
|
|
688
|
-
function classify(
|
|
689
|
-
return
|
|
922
|
+
function classify(path7, home, isAncestorOrSelf) {
|
|
923
|
+
return path7.map((cond) => {
|
|
690
924
|
if (cond.branchStmt === null) {
|
|
691
925
|
return cond.info;
|
|
692
926
|
}
|
|
@@ -751,9 +985,16 @@ function chargeBudget(state) {
|
|
|
751
985
|
);
|
|
752
986
|
}
|
|
753
987
|
}
|
|
754
|
-
function
|
|
988
|
+
function limitOpenPaths(paths) {
|
|
989
|
+
if (paths.length > MAX_PATHS) {
|
|
990
|
+
throw new PathBudgetExceeded(
|
|
991
|
+
`path budget exceeded, more than ${MAX_PATHS} paths`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
function recordTerminal(ctx, terminal, home, path7) {
|
|
755
996
|
chargeBudget(ctx.state);
|
|
756
|
-
const info = classify(
|
|
997
|
+
const info = classify(path7, home, ctx.isAncestorOrSelf);
|
|
757
998
|
const existing = ctx.state.byTerminal.get(terminal) ?? [];
|
|
758
999
|
existing.push(info);
|
|
759
1000
|
ctx.state.byTerminal.set(terminal, existing);
|
|
@@ -764,15 +1005,15 @@ function containsTerminal(ctx, stmt) {
|
|
|
764
1005
|
}
|
|
765
1006
|
return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
|
|
766
1007
|
}
|
|
767
|
-
function stepIf(stmt,
|
|
1008
|
+
function stepIf(stmt, path7, ctx) {
|
|
768
1009
|
const thenExit = exitKindOfList(stmt.thenBody);
|
|
769
1010
|
const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
|
|
770
1011
|
const thenPath = [
|
|
771
|
-
...
|
|
1012
|
+
...path7,
|
|
772
1013
|
branchCond(stmt, stmt.condition, "positive", elseExit)
|
|
773
1014
|
];
|
|
774
1015
|
const elsePath = [
|
|
775
|
-
...
|
|
1016
|
+
...path7,
|
|
776
1017
|
branchCond(
|
|
777
1018
|
stmt,
|
|
778
1019
|
stmt.condition,
|
|
@@ -789,7 +1030,7 @@ function stepIf(stmt, path6, ctx) {
|
|
|
789
1030
|
}
|
|
790
1031
|
return out;
|
|
791
1032
|
}
|
|
792
|
-
function stepSwitch(stmt,
|
|
1033
|
+
function stepSwitch(stmt, path7, ctx) {
|
|
793
1034
|
const out = [];
|
|
794
1035
|
const negations = [];
|
|
795
1036
|
let defaultRanBody = false;
|
|
@@ -799,7 +1040,7 @@ function stepSwitch(stmt, path6, ctx) {
|
|
|
799
1040
|
if (hasStrayBreak(group.body)) {
|
|
800
1041
|
throw new UnmodeledFlow("non-trailing break in switch clause");
|
|
801
1042
|
}
|
|
802
|
-
const groupPath = group.condition === null ? [...
|
|
1043
|
+
const groupPath = group.condition === null ? [...path7, ...negations] : [...path7, fixedCond(group.condition, "positive", "explicit")];
|
|
803
1044
|
const conts = enumerate(ctx, group.body, groupPath);
|
|
804
1045
|
if (conts.length > 0) {
|
|
805
1046
|
if (!group.hasTrailingBreak && !fallthroughSafe) {
|
|
@@ -816,24 +1057,24 @@ function stepSwitch(stmt, path6, ctx) {
|
|
|
816
1057
|
}
|
|
817
1058
|
}
|
|
818
1059
|
if (!defaultRanBody) {
|
|
819
|
-
out.push([...
|
|
1060
|
+
out.push([...path7, ...negations]);
|
|
820
1061
|
}
|
|
821
1062
|
return out;
|
|
822
1063
|
}
|
|
823
|
-
function stepLoop(stmt,
|
|
1064
|
+
function stepLoop(stmt, path7, ctx) {
|
|
824
1065
|
const bodyExit = exitKindOfList(stmt.body);
|
|
825
1066
|
if (containsTerminal(ctx, stmt)) {
|
|
826
1067
|
enumerate(ctx, stmt.body, [
|
|
827
|
-
...
|
|
1068
|
+
...path7,
|
|
828
1069
|
loopIterationCond(stmt.condition.sourceText)
|
|
829
1070
|
]);
|
|
830
1071
|
}
|
|
831
1072
|
if (bodyExit !== null) {
|
|
832
|
-
return [[...
|
|
1073
|
+
return [[...path7, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
|
|
833
1074
|
}
|
|
834
|
-
return [
|
|
1075
|
+
return [path7];
|
|
835
1076
|
}
|
|
836
|
-
function stepTry(stmt,
|
|
1077
|
+
function stepTry(stmt, path7, ctx) {
|
|
837
1078
|
if (stmt.finallyBody !== null) {
|
|
838
1079
|
const finallyHasTerminal = stmt.finallyBody.some(
|
|
839
1080
|
(s) => containsTerminal(ctx, s)
|
|
@@ -843,22 +1084,22 @@ function stepTry(stmt, path6, ctx) {
|
|
|
843
1084
|
}
|
|
844
1085
|
}
|
|
845
1086
|
const out = [];
|
|
846
|
-
out.push(...enumerate(ctx, stmt.tryBody,
|
|
1087
|
+
out.push(...enumerate(ctx, stmt.tryBody, path7));
|
|
847
1088
|
if (stmt.catchBody !== null) {
|
|
848
|
-
const catchPath = [...
|
|
1089
|
+
const catchPath = [...path7, catchEntryCond()];
|
|
849
1090
|
out.push(...enumerate(ctx, stmt.catchBody, catchPath));
|
|
850
1091
|
}
|
|
851
1092
|
return out;
|
|
852
1093
|
}
|
|
853
|
-
function stepExit(stmt,
|
|
1094
|
+
function stepExit(stmt, path7, ctx) {
|
|
854
1095
|
const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
|
|
855
1096
|
if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
|
|
856
|
-
collector.push(
|
|
1097
|
+
collector.push(path7);
|
|
857
1098
|
}
|
|
858
1099
|
return [];
|
|
859
1100
|
}
|
|
860
|
-
function stepOpaque(_stmt,
|
|
861
|
-
return [
|
|
1101
|
+
function stepOpaque(_stmt, path7, _ctx) {
|
|
1102
|
+
return [path7];
|
|
862
1103
|
}
|
|
863
1104
|
var stepHandlers = {
|
|
864
1105
|
if: stepIf,
|
|
@@ -868,22 +1109,23 @@ var stepHandlers = {
|
|
|
868
1109
|
exit: stepExit,
|
|
869
1110
|
opaque: stepOpaque
|
|
870
1111
|
};
|
|
871
|
-
function stepCallback(ctx, body,
|
|
1112
|
+
function stepCallback(ctx, body, path7) {
|
|
872
1113
|
const exits = [];
|
|
873
1114
|
ctx.state.callbackExits.push(exits);
|
|
874
1115
|
let fellThrough;
|
|
875
1116
|
try {
|
|
876
|
-
fellThrough = enumerate(ctx, body,
|
|
1117
|
+
fellThrough = enumerate(ctx, body, path7);
|
|
877
1118
|
} finally {
|
|
878
1119
|
ctx.state.callbackExits.pop();
|
|
879
1120
|
}
|
|
880
1121
|
const out = [...fellThrough, ...exits];
|
|
881
|
-
return out.length === 0 ? [
|
|
1122
|
+
return out.length === 0 ? [path7] : out;
|
|
882
1123
|
}
|
|
883
|
-
function stepStatement(ctx, stmt,
|
|
884
|
-
let paths = [
|
|
1124
|
+
function stepStatement(ctx, stmt, path7) {
|
|
1125
|
+
let paths = [path7];
|
|
885
1126
|
for (const body of stmt.callbacks ?? []) {
|
|
886
1127
|
paths = paths.flatMap((each) => stepCallback(ctx, body, each));
|
|
1128
|
+
limitOpenPaths(paths);
|
|
887
1129
|
}
|
|
888
1130
|
const ownTerminals = ctx.terminalsByStmt.get(stmt) ?? [];
|
|
889
1131
|
for (const each of withRejoined(paths)) {
|
|
@@ -900,7 +1142,7 @@ function stepStatement(ctx, stmt, path6) {
|
|
|
900
1142
|
)
|
|
901
1143
|
);
|
|
902
1144
|
}
|
|
903
|
-
function soleDisagreement(left, right) {
|
|
1145
|
+
function soleDisagreement(left, right, keepsArms) {
|
|
904
1146
|
if (left.length !== right.length) {
|
|
905
1147
|
return null;
|
|
906
1148
|
}
|
|
@@ -919,9 +1161,10 @@ function soleDisagreement(left, right) {
|
|
|
919
1161
|
}
|
|
920
1162
|
found = at;
|
|
921
1163
|
}
|
|
922
|
-
|
|
1164
|
+
const test = found === null ? null : left[found]?.info.expression ?? null;
|
|
1165
|
+
return test !== null && keepsArms(test) ? null : found;
|
|
923
1166
|
}
|
|
924
|
-
function mergeRejoined(paths) {
|
|
1167
|
+
function mergeRejoined(paths, keepsArms = KEEPS_NO_ARMS) {
|
|
925
1168
|
let current = paths;
|
|
926
1169
|
for (let round = 0; round < current.length; round++) {
|
|
927
1170
|
const out = [];
|
|
@@ -936,7 +1179,11 @@ function mergeRejoined(paths) {
|
|
|
936
1179
|
if (taken.has(j)) {
|
|
937
1180
|
continue;
|
|
938
1181
|
}
|
|
939
|
-
const at = soleDisagreement(
|
|
1182
|
+
const at = soleDisagreement(
|
|
1183
|
+
combined,
|
|
1184
|
+
current[j],
|
|
1185
|
+
keepsArms
|
|
1186
|
+
);
|
|
940
1187
|
if (at === null) {
|
|
941
1188
|
continue;
|
|
942
1189
|
}
|
|
@@ -962,21 +1209,18 @@ function enumerate(ctx, stmts, prefix) {
|
|
|
962
1209
|
let frontiers = [[...prefix]];
|
|
963
1210
|
for (const stmt of stmts) {
|
|
964
1211
|
const nextFrontiers = [];
|
|
965
|
-
for (const
|
|
966
|
-
nextFrontiers.push(...stepStatement(ctx, stmt,
|
|
1212
|
+
for (const path7 of mergeRejoined(frontiers, ctx.keepsArms)) {
|
|
1213
|
+
nextFrontiers.push(...stepStatement(ctx, stmt, path7));
|
|
967
1214
|
}
|
|
968
1215
|
frontiers = nextFrontiers;
|
|
969
|
-
|
|
970
|
-
throw new PathBudgetExceeded(
|
|
971
|
-
`path budget exceeded, more than ${MAX_PATHS} paths`
|
|
972
|
-
);
|
|
973
|
-
}
|
|
1216
|
+
limitOpenPaths(frontiers);
|
|
974
1217
|
if (frontiers.length === 0) {
|
|
975
1218
|
break;
|
|
976
1219
|
}
|
|
977
1220
|
}
|
|
978
1221
|
return frontiers;
|
|
979
1222
|
}
|
|
1223
|
+
var KEEPS_NO_ARMS = () => false;
|
|
980
1224
|
function buildParentMap(statements) {
|
|
981
1225
|
const parentOf = /* @__PURE__ */ new Map();
|
|
982
1226
|
const visit = (stmt, parent) => {
|
|
@@ -1010,13 +1254,14 @@ function enumerateStructuredPaths(input) {
|
|
|
1010
1254
|
};
|
|
1011
1255
|
const ctx = {
|
|
1012
1256
|
terminalsByStmt: input.terminalsByStmt,
|
|
1257
|
+
keepsArms: input.keepsArms ?? KEEPS_NO_ARMS,
|
|
1013
1258
|
state,
|
|
1014
1259
|
isAncestorOrSelf
|
|
1015
1260
|
};
|
|
1016
1261
|
const continuations = withRejoined(enumerate(ctx, input.statements, []));
|
|
1017
|
-
for (const
|
|
1262
|
+
for (const path7 of continuations) {
|
|
1018
1263
|
chargeBudget(state);
|
|
1019
|
-
state.fallthrough.push(classify(
|
|
1264
|
+
state.fallthrough.push(classify(path7, null, isAncestorOrSelf));
|
|
1020
1265
|
}
|
|
1021
1266
|
return { byTerminal: state.byTerminal, fallthrough: state.fallthrough };
|
|
1022
1267
|
}
|
|
@@ -1059,8 +1304,8 @@ function sharedGatingConditions(paths, readPredicate) {
|
|
|
1059
1304
|
return [];
|
|
1060
1305
|
}
|
|
1061
1306
|
const shared = new Set(first.map(keyOf2));
|
|
1062
|
-
for (const
|
|
1063
|
-
const here = new Set(
|
|
1307
|
+
for (const path7 of rest) {
|
|
1308
|
+
const here = new Set(path7.map(keyOf2));
|
|
1064
1309
|
for (const value of shared) {
|
|
1065
1310
|
if (!here.has(value)) {
|
|
1066
1311
|
shared.delete(value);
|
|
@@ -1168,15 +1413,12 @@ var EnclosingNodes = class {
|
|
|
1168
1413
|
|
|
1169
1414
|
// src/paths/nodeWalk.ts
|
|
1170
1415
|
var SKIP_CHILDREN = /* @__PURE__ */ Symbol("skipChildren");
|
|
1171
|
-
function walkDescendants(root, carried, visitor) {
|
|
1172
|
-
for (const child of root
|
|
1173
|
-
if (child === null) {
|
|
1174
|
-
continue;
|
|
1175
|
-
}
|
|
1416
|
+
function walkDescendants(root, carried, childrenOf2, visitor) {
|
|
1417
|
+
for (const child of childrenOf2(root)) {
|
|
1176
1418
|
visitor.at(child, carried);
|
|
1177
1419
|
const inner = visitor.into(child, carried);
|
|
1178
1420
|
if (inner !== SKIP_CHILDREN) {
|
|
1179
|
-
walkDescendants(child, inner, visitor);
|
|
1421
|
+
walkDescendants(child, inner, childrenOf2, visitor);
|
|
1180
1422
|
}
|
|
1181
1423
|
}
|
|
1182
1424
|
}
|
|
@@ -1255,6 +1497,11 @@ function valueToReadFurtherFrom(reading) {
|
|
|
1255
1497
|
return reading.kind === "written" ? reading.value : null;
|
|
1256
1498
|
}
|
|
1257
1499
|
|
|
1500
|
+
// src/redirectOption.ts
|
|
1501
|
+
function redirectDeliveryWhenSet(option, value) {
|
|
1502
|
+
return option.handsBack.includes(value) ? "response" : "followed";
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1258
1505
|
// src/testFiles.ts
|
|
1259
1506
|
function isListedTestFile(file, listed) {
|
|
1260
1507
|
if (listed === void 0) {
|
|
@@ -1422,7 +1669,8 @@ function extractionConfigStamp(config) {
|
|
|
1422
1669
|
["workspaceRoot", config.workspaceRoot],
|
|
1423
1670
|
["projectRoot", config.projectRoot],
|
|
1424
1671
|
["importRoots", config.importRoots?.join(path4.delimiter)],
|
|
1425
|
-
["modules", modulesStamp(config.modules)]
|
|
1672
|
+
["modules", modulesStamp(config.modules)],
|
|
1673
|
+
["walkedDirectory", config.walkedDirectory]
|
|
1426
1674
|
];
|
|
1427
1675
|
return parts.flatMap(
|
|
1428
1676
|
([name, value]) => value === void 0 ? [] : [`${name}=${value}`]
|
|
@@ -1449,8 +1697,9 @@ function analysisBundles() {
|
|
|
1449
1697
|
|
|
1450
1698
|
// src/cache.ts
|
|
1451
1699
|
import { createHash as createHash3 } from "crypto";
|
|
1452
|
-
import
|
|
1453
|
-
import
|
|
1700
|
+
import fs5 from "fs/promises";
|
|
1701
|
+
import path6 from "path";
|
|
1702
|
+
import { readJsonFile, writeDocumentFile } from "@suss/behavioral-ir/files";
|
|
1454
1703
|
|
|
1455
1704
|
// src/cacheStamps.ts
|
|
1456
1705
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -1558,6 +1807,17 @@ function fileStampEquals(a, b) {
|
|
|
1558
1807
|
return a.path === b.path && a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
1559
1808
|
}
|
|
1560
1809
|
|
|
1810
|
+
// src/ignoredDirectory.ts
|
|
1811
|
+
import fs4 from "fs";
|
|
1812
|
+
import path5 from "path";
|
|
1813
|
+
function makeIgnoredDirectory(dir) {
|
|
1814
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
1815
|
+
const ignore = path5.join(dir, ".gitignore");
|
|
1816
|
+
if (!fs4.existsSync(ignore)) {
|
|
1817
|
+
fs4.writeFileSync(ignore, "*\n");
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1561
1821
|
// src/cache.ts
|
|
1562
1822
|
var SCHEMA_VERSION = "9";
|
|
1563
1823
|
var MAX_ENTRIES = 2;
|
|
@@ -1582,7 +1842,7 @@ function createCacheLayer(cacheDir) {
|
|
|
1582
1842
|
const lookupWith = async (input, run) => {
|
|
1583
1843
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1584
1844
|
const manifest = await manifests.readAtRunStart(
|
|
1585
|
-
|
|
1845
|
+
path6.join(entryDir, "manifest.json")
|
|
1586
1846
|
);
|
|
1587
1847
|
if (manifest === null) {
|
|
1588
1848
|
return missDiag(await describeAbsentEntry(cacheDir));
|
|
@@ -1622,7 +1882,7 @@ function createCacheLayer(cacheDir) {
|
|
|
1622
1882
|
async plan(input) {
|
|
1623
1883
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1624
1884
|
const manifest = await manifests.readAgain(
|
|
1625
|
-
|
|
1885
|
+
path6.join(entryDir, "manifest.json")
|
|
1626
1886
|
);
|
|
1627
1887
|
if (manifest === null || manifest.roots === void 0 || manifest.rootMeta === void 0 || manifest.owners === void 0) {
|
|
1628
1888
|
return null;
|
|
@@ -1641,7 +1901,7 @@ function createCacheLayer(cacheDir) {
|
|
|
1641
1901
|
async write(input, summaries, attribution) {
|
|
1642
1902
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1643
1903
|
const previous = await manifests.readAgain(
|
|
1644
|
-
|
|
1904
|
+
path6.join(entryDir, "manifest.json")
|
|
1645
1905
|
);
|
|
1646
1906
|
manifests.forget();
|
|
1647
1907
|
const known = runs.get(input);
|
|
@@ -1666,11 +1926,8 @@ function createCacheLayer(cacheDir) {
|
|
|
1666
1926
|
summaries,
|
|
1667
1927
|
...attribution === void 0 ? {} : encodeAttribution(attribution)
|
|
1668
1928
|
};
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
path5.join(entryDir, "manifest.json"),
|
|
1672
|
-
JSON.stringify(manifest)
|
|
1673
|
-
);
|
|
1929
|
+
makeIgnoredDirectory(cacheDir);
|
|
1930
|
+
writeDocumentFile(path6.join(entryDir, "manifest.json"), manifest);
|
|
1674
1931
|
await evictOldEntries(cacheDir, entryDir);
|
|
1675
1932
|
}
|
|
1676
1933
|
};
|
|
@@ -1854,7 +2111,7 @@ function encodeAttribution(attribution) {
|
|
|
1854
2111
|
}
|
|
1855
2112
|
async function describeAbsentEntry(cacheDir) {
|
|
1856
2113
|
try {
|
|
1857
|
-
const entries = await
|
|
2114
|
+
const entries = await fs5.readdir(cacheDir, { withFileTypes: true });
|
|
1858
2115
|
return entries.some((e) => e.isDirectory() && isEntryDir(e.name)) ? "key-changed" : "no-manifest";
|
|
1859
2116
|
} catch {
|
|
1860
2117
|
return "no-manifest";
|
|
@@ -1867,7 +2124,7 @@ function entryDirFor(cacheDir, input) {
|
|
|
1867
2124
|
input.configPath ?? ""
|
|
1868
2125
|
].join(" ");
|
|
1869
2126
|
const name = createHash3("sha256").update(key).digest("hex").slice(0, 16);
|
|
1870
|
-
return
|
|
2127
|
+
return path6.join(cacheDir, `${ENTRY_PREFIX}${name}`);
|
|
1871
2128
|
}
|
|
1872
2129
|
function isEntryDir(name) {
|
|
1873
2130
|
return ENTRY_DIR_NAME.test(name);
|
|
@@ -1875,24 +2132,24 @@ function isEntryDir(name) {
|
|
|
1875
2132
|
async function markUsed(entryDir) {
|
|
1876
2133
|
const now = /* @__PURE__ */ new Date();
|
|
1877
2134
|
try {
|
|
1878
|
-
await
|
|
2135
|
+
await fs5.utimes(entryDir, now, now);
|
|
1879
2136
|
} catch {
|
|
1880
2137
|
}
|
|
1881
2138
|
}
|
|
1882
2139
|
async function evictOldEntries(cacheDir, keepDir) {
|
|
1883
2140
|
try {
|
|
1884
|
-
await
|
|
1885
|
-
const entries = await
|
|
2141
|
+
await fs5.rm(path6.join(cacheDir, "manifest.json"), { force: true });
|
|
2142
|
+
const entries = await fs5.readdir(cacheDir, { withFileTypes: true });
|
|
1886
2143
|
const dirs = await Promise.all(
|
|
1887
2144
|
entries.filter((e) => e.isDirectory() && isEntryDir(e.name)).map(async (e) => {
|
|
1888
|
-
const dir =
|
|
1889
|
-
const stat = await
|
|
2145
|
+
const dir = path6.join(cacheDir, e.name);
|
|
2146
|
+
const stat = await fs5.stat(dir);
|
|
1890
2147
|
return { dir, mtimeMs: stat.mtimeMs };
|
|
1891
2148
|
})
|
|
1892
2149
|
);
|
|
1893
2150
|
const doomed = dirs.filter((d) => d.dir !== keepDir).sort((a, b) => b.mtimeMs - a.mtimeMs).slice(MAX_ENTRIES - 1);
|
|
1894
2151
|
await Promise.all(
|
|
1895
|
-
doomed.map((d) =>
|
|
2152
|
+
doomed.map((d) => fs5.rm(d.dir, { recursive: true, force: true }))
|
|
1896
2153
|
);
|
|
1897
2154
|
} catch {
|
|
1898
2155
|
}
|
|
@@ -1924,7 +2181,7 @@ var ManifestReads = class {
|
|
|
1924
2181
|
};
|
|
1925
2182
|
async function manifestStamp(manifestPath) {
|
|
1926
2183
|
try {
|
|
1927
|
-
const stat = await
|
|
2184
|
+
const stat = await fs5.stat(manifestPath);
|
|
1928
2185
|
return `${stat.ino}:${stat.mtimeMs}:${stat.size}`;
|
|
1929
2186
|
} catch {
|
|
1930
2187
|
return null;
|
|
@@ -1932,8 +2189,7 @@ async function manifestStamp(manifestPath) {
|
|
|
1932
2189
|
}
|
|
1933
2190
|
async function readManifest(manifestPath) {
|
|
1934
2191
|
try {
|
|
1935
|
-
|
|
1936
|
-
return JSON.parse(raw);
|
|
2192
|
+
return readJsonFile(manifestPath);
|
|
1937
2193
|
} catch {
|
|
1938
2194
|
return null;
|
|
1939
2195
|
}
|
|
@@ -2426,6 +2682,7 @@ function unreadSentences(raw) {
|
|
|
2426
2682
|
...raw.branches.flatMap(readingsOfBranch)
|
|
2427
2683
|
];
|
|
2428
2684
|
return [
|
|
2685
|
+
...raw.readFailure !== void 0 ? [raw.readFailure] : [],
|
|
2429
2686
|
...raw.unreadBinding !== void 0 ? [raw.unreadBinding] : [],
|
|
2430
2687
|
...handedOver.map(unreadReasonOf).filter((reason) => reason !== null)
|
|
2431
2688
|
];
|
|
@@ -2588,6 +2845,12 @@ function buildHttpMetadataValue(raw) {
|
|
|
2588
2845
|
if (raw.failureDelivery !== void 0) {
|
|
2589
2846
|
http.failureDelivery = raw.failureDelivery;
|
|
2590
2847
|
}
|
|
2848
|
+
if (raw.redirectDelivery !== void 0) {
|
|
2849
|
+
http.redirectDelivery = raw.redirectDelivery;
|
|
2850
|
+
}
|
|
2851
|
+
if (raw.declaredStatuses !== void 0 && raw.declaredStatuses.length > 0) {
|
|
2852
|
+
http.declaredStatuses = raw.declaredStatuses;
|
|
2853
|
+
}
|
|
2591
2854
|
return Object.keys(http).length > 0 ? http : null;
|
|
2592
2855
|
}
|
|
2593
2856
|
function buildGraphqlMetadataValue(raw) {
|
|
@@ -2655,13 +2918,16 @@ function detectGaps(raw, transitions, options) {
|
|
|
2655
2918
|
return gaps;
|
|
2656
2919
|
}
|
|
2657
2920
|
function bodyWentUnread(raw) {
|
|
2921
|
+
if (raw.readFailure !== void 0) {
|
|
2922
|
+
return true;
|
|
2923
|
+
}
|
|
2658
2924
|
if (raw.bodyContent === "absent" || raw.bodyContent === "elsewhere") {
|
|
2659
2925
|
return true;
|
|
2660
2926
|
}
|
|
2661
2927
|
return raw.bodyContent === "statements" && raw.branches.length === 0;
|
|
2662
2928
|
}
|
|
2663
2929
|
function describeUnreadBody(raw) {
|
|
2664
|
-
if (!bodyWentUnread(raw)) {
|
|
2930
|
+
if (!bodyWentUnread(raw) || raw.readFailure !== void 0) {
|
|
2665
2931
|
return null;
|
|
2666
2932
|
}
|
|
2667
2933
|
if (raw.bodyContent === "absent") {
|
|
@@ -2733,10 +2999,16 @@ var terminalConverters = {
|
|
|
2733
2999
|
headers: {}
|
|
2734
3000
|
};
|
|
2735
3001
|
}
|
|
3002
|
+
const ancestry = t.exceptionAncestry;
|
|
2736
3003
|
return {
|
|
2737
3004
|
type: "throw",
|
|
2738
3005
|
exceptionType: t.exceptionType,
|
|
2739
|
-
message: t.message
|
|
3006
|
+
message: t.message,
|
|
3007
|
+
...ancestry === void 0 ? {} : {
|
|
3008
|
+
exceptionAncestors: ancestry.ancestors,
|
|
3009
|
+
...ancestry.incomplete ? { ancestryIncomplete: true } : {}
|
|
3010
|
+
},
|
|
3011
|
+
...t.statusWhenUncaught === void 0 ? {} : { statusWhenUncaught: t.statusWhenUncaught }
|
|
2740
3012
|
};
|
|
2741
3013
|
},
|
|
2742
3014
|
render: (t) => ({
|
|
@@ -2810,6 +3082,7 @@ export {
|
|
|
2810
3082
|
IdSet,
|
|
2811
3083
|
KeptParses,
|
|
2812
3084
|
MAX_ENTRIES,
|
|
3085
|
+
MAX_HELPER_PATHS,
|
|
2813
3086
|
MAX_PATHS,
|
|
2814
3087
|
MODULE_SURFACE_RECOGNITION,
|
|
2815
3088
|
PathBudgetExceeded,
|
|
@@ -2840,12 +3113,15 @@ export {
|
|
|
2840
3113
|
firstWrittenReading,
|
|
2841
3114
|
formatPackHealth,
|
|
2842
3115
|
guardsHoldOn,
|
|
3116
|
+
helperPathsOnVariables,
|
|
2843
3117
|
httpRouteDiscovery,
|
|
2844
3118
|
isListedTestFile,
|
|
3119
|
+
makeIgnoredDirectory,
|
|
2845
3120
|
makeTransitionId,
|
|
2846
3121
|
mapReading,
|
|
2847
3122
|
markReturnsAsExitCode,
|
|
2848
3123
|
matchesTestFileName,
|
|
3124
|
+
mergeReadShapes,
|
|
2849
3125
|
moduleInitStructure,
|
|
2850
3126
|
moduleOfFile,
|
|
2851
3127
|
noopTimer,
|
|
@@ -2854,6 +3130,7 @@ export {
|
|
|
2854
3130
|
projectFileStamp,
|
|
2855
3131
|
rawConditionToPredicate,
|
|
2856
3132
|
recordPackFailure,
|
|
3133
|
+
redirectDeliveryWhenSet,
|
|
2857
3134
|
registrationHelperDiscovery,
|
|
2858
3135
|
routeHelperIndex,
|
|
2859
3136
|
runDigest,
|
|
@@ -2862,6 +3139,7 @@ export {
|
|
|
2862
3139
|
settleModules,
|
|
2863
3140
|
sharedGatingConditions,
|
|
2864
3141
|
sourceRefsOf,
|
|
3142
|
+
splitAtHandOffs,
|
|
2865
3143
|
stampMayMissAWrite,
|
|
2866
3144
|
stampModuleImports,
|
|
2867
3145
|
stampModules,
|
|
@@ -2869,6 +3147,7 @@ export {
|
|
|
2869
3147
|
summaryCountsByPack,
|
|
2870
3148
|
tallyUnit,
|
|
2871
3149
|
terminalToOutput,
|
|
3150
|
+
throughHelper,
|
|
2872
3151
|
unreadableReading,
|
|
2873
3152
|
unwrapJsonStringify,
|
|
2874
3153
|
valueToReadFurtherFrom,
|