@suss/extractor 0.33.1 → 0.34.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/README.md +3 -3
- package/dist/index.cjs +664 -193
- package/dist/index.d.cts +1114 -933
- package/dist/index.d.ts +1114 -933
- package/dist/index.js +641 -180
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -30,10 +30,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
EnclosingNodes: () => EnclosingNodes,
|
|
33
34
|
IdMap: () => IdMap,
|
|
34
35
|
IdSet: () => IdSet,
|
|
36
|
+
KeptParses: () => KeptParses,
|
|
35
37
|
MAX_ENTRIES: () => MAX_ENTRIES,
|
|
36
38
|
MAX_PATHS: () => MAX_PATHS,
|
|
39
|
+
MODULE_SURFACE_RECOGNITION: () => MODULE_SURFACE_RECOGNITION,
|
|
37
40
|
PathBudgetExceeded: () => PathBudgetExceeded,
|
|
38
41
|
SKIP_CHILDREN: () => SKIP_CHILDREN,
|
|
39
42
|
UnmodeledFlow: () => UnmodeledFlow,
|
|
@@ -58,13 +61,18 @@ __export(index_exports, {
|
|
|
58
61
|
enumerateOrDegrade: () => enumerateOrDegrade,
|
|
59
62
|
enumerateStructuredPaths: () => enumerateStructuredPaths,
|
|
60
63
|
evaluatePackHealth: () => evaluatePackHealth,
|
|
64
|
+
extractionConfigStamp: () => extractionConfigStamp,
|
|
61
65
|
firstWrittenReading: () => firstWrittenReading,
|
|
62
66
|
formatPackHealth: () => formatPackHealth,
|
|
63
67
|
guardsHoldOn: () => guardsHoldOn,
|
|
64
68
|
httpRouteDiscovery: () => httpRouteDiscovery,
|
|
69
|
+
isListedTestFile: () => isListedTestFile,
|
|
65
70
|
makeTransitionId: () => makeTransitionId,
|
|
66
71
|
mapReading: () => mapReading,
|
|
72
|
+
markReturnsAsExitCode: () => markReturnsAsExitCode,
|
|
73
|
+
matchesTestFileName: () => matchesTestFileName,
|
|
67
74
|
moduleInitStructure: () => moduleInitStructure,
|
|
75
|
+
moduleOfFile: () => moduleOfFile,
|
|
68
76
|
noopTimer: () => noopTimer,
|
|
69
77
|
packGradients: () => packGradients,
|
|
70
78
|
paramToInput: () => paramToInput,
|
|
@@ -76,8 +84,12 @@ __export(index_exports, {
|
|
|
76
84
|
runDigest: () => runDigest,
|
|
77
85
|
runsBefore: () => runsBefore,
|
|
78
86
|
scopeOption: () => scopeOption,
|
|
87
|
+
settleModules: () => settleModules,
|
|
79
88
|
sharedGatingConditions: () => sharedGatingConditions,
|
|
89
|
+
sourceRefsOf: () => sourceRefsOf,
|
|
90
|
+
stampMayMissAWrite: () => stampMayMissAWrite,
|
|
80
91
|
stampModuleImports: () => stampModuleImports,
|
|
92
|
+
stampModules: () => stampModules,
|
|
81
93
|
storageSystemOption: () => storageSystemOption,
|
|
82
94
|
summaryCountsByPack: () => summaryCountsByPack,
|
|
83
95
|
tallyUnit: () => tallyUnit,
|
|
@@ -90,8 +102,8 @@ __export(index_exports, {
|
|
|
90
102
|
writtenReading: () => writtenReading
|
|
91
103
|
});
|
|
92
104
|
module.exports = __toCommonJS(index_exports);
|
|
93
|
-
var
|
|
94
|
-
var
|
|
105
|
+
var import_node_crypto4 = require("crypto");
|
|
106
|
+
var import_behavioral_ir6 = require("@suss/behavioral-ir");
|
|
95
107
|
|
|
96
108
|
// src/contractStatusGaps.ts
|
|
97
109
|
var import_behavioral_ir = require("@suss/behavioral-ir");
|
|
@@ -354,6 +366,56 @@ function withDistinctIds(transitions) {
|
|
|
354
366
|
});
|
|
355
367
|
}
|
|
356
368
|
|
|
369
|
+
// src/declaredModules.ts
|
|
370
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
371
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
372
|
+
var MODULE_SURFACE_RECOGNITION = "modules";
|
|
373
|
+
function settleModules(modules, candidates) {
|
|
374
|
+
return (modules ?? []).map((module2) => ({
|
|
375
|
+
...module2,
|
|
376
|
+
public: module2.public ?? candidates.map(
|
|
377
|
+
(one) => import_node_path.default.join(module2.root, one.replace("{name}", module2.name))
|
|
378
|
+
).filter((file) => import_node_fs.default.existsSync(file))
|
|
379
|
+
}));
|
|
380
|
+
}
|
|
381
|
+
function isInside(file, root) {
|
|
382
|
+
const relative = import_node_path.default.relative(root, file);
|
|
383
|
+
return relative !== "" && !relative.startsWith("..") && !import_node_path.default.isAbsolute(relative);
|
|
384
|
+
}
|
|
385
|
+
function moduleOfFile(modules, file) {
|
|
386
|
+
const byPublicFile = modules.find((module2) => module2.public.includes(file));
|
|
387
|
+
if (byPublicFile !== void 0) {
|
|
388
|
+
return byPublicFile;
|
|
389
|
+
}
|
|
390
|
+
let deepest;
|
|
391
|
+
for (const module2 of modules) {
|
|
392
|
+
if (isInside(file, module2.root) && (deepest === void 0 || module2.root.length > deepest.root.length)) {
|
|
393
|
+
deepest = module2;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return deepest;
|
|
397
|
+
}
|
|
398
|
+
function stampModules(summaries, modules, root) {
|
|
399
|
+
if (modules.length === 0) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
for (const summary of summaries) {
|
|
403
|
+
const file = import_node_path.default.resolve(root ?? "", summary.location.file);
|
|
404
|
+
const module2 = moduleOfFile(modules, file);
|
|
405
|
+
if (module2 !== void 0) {
|
|
406
|
+
summary.location.module = module2.name;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function modulesStamp(modules) {
|
|
411
|
+
if (modules === void 0 || modules.length === 0) {
|
|
412
|
+
return void 0;
|
|
413
|
+
}
|
|
414
|
+
return JSON.stringify(
|
|
415
|
+
modules.map((module2) => [module2.name, module2.root, [...module2.public]])
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
357
419
|
// src/effectGuards.ts
|
|
358
420
|
var keyOf = (condition) => `${condition.polarity}:${condition.sourceText}`;
|
|
359
421
|
var opposite = (condition) => `${condition.polarity === "positive" ? "negative" : "positive"}:${condition.sourceText}`;
|
|
@@ -370,6 +432,41 @@ function runsBefore(effectLine, terminalEndLine) {
|
|
|
370
432
|
return effectLine <= terminalEndLine;
|
|
371
433
|
}
|
|
372
434
|
|
|
435
|
+
// src/exitCode.ts
|
|
436
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
437
|
+
var import_behavioral_ir3 = require("@suss/behavioral-ir");
|
|
438
|
+
function markReturnsAsExitCode(summaries, returnsTheCode, workspaceRoot) {
|
|
439
|
+
for (const summary of summaries) {
|
|
440
|
+
const span = summary.location.span;
|
|
441
|
+
const file = workspaceRoot === void 0 ? summary.location.file : import_node_path2.default.resolve(workspaceRoot, summary.location.file);
|
|
442
|
+
markExitCodeFrom(
|
|
443
|
+
summary,
|
|
444
|
+
span !== void 0 && returnsTheCode.has((0, import_behavioral_ir3.declarationKey)(file, span))
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
function markExitCodeFrom(summary, marked) {
|
|
449
|
+
const process2 = summary.metadata?.process;
|
|
450
|
+
if (marked) {
|
|
451
|
+
summary.metadata = {
|
|
452
|
+
...summary.metadata ?? {},
|
|
453
|
+
process: { ...process2 ?? {}, exitCodeFrom: "return" }
|
|
454
|
+
};
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (process2 === void 0 || !("exitCodeFrom" in process2)) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
const { exitCodeFrom: _dropped, ...rest } = process2;
|
|
461
|
+
const { process: _process, ...others } = summary.metadata ?? {};
|
|
462
|
+
const left = Object.keys(rest).length === 0 ? others : { ...others, process: rest };
|
|
463
|
+
if (Object.keys(left).length === 0) {
|
|
464
|
+
Reflect.deleteProperty(summary, "metadata");
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
summary.metadata = left;
|
|
468
|
+
}
|
|
469
|
+
|
|
373
470
|
// src/moduleImports.ts
|
|
374
471
|
function stampModuleImports(summaries, importsOf) {
|
|
375
472
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -446,8 +543,8 @@ function httpRouteDiscovery(opts) {
|
|
|
446
543
|
registrationChain: [...opts.methods]
|
|
447
544
|
},
|
|
448
545
|
bindingExtraction: {
|
|
449
|
-
// `.all` registers every method, so it records "*", which
|
|
450
|
-
//
|
|
546
|
+
// `.all` registers every method, so it records "*", which pairs with
|
|
547
|
+
// any method.
|
|
451
548
|
method: {
|
|
452
549
|
type: "fromRegistration",
|
|
453
550
|
position: "methodName",
|
|
@@ -463,10 +560,9 @@ function httpRouteDiscovery(opts) {
|
|
|
463
560
|
}
|
|
464
561
|
return [
|
|
465
562
|
...calls,
|
|
466
|
-
// Routes registered in a loop over an array of specs,
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
// never touches this library's routable is left alone.
|
|
563
|
+
// Routes registered in a loop over an array of specs, which the calls
|
|
564
|
+
// above cannot see. The receiver must come from the same import, so a
|
|
565
|
+
// loop that never touches this library's routable is left alone.
|
|
470
566
|
{
|
|
471
567
|
kind,
|
|
472
568
|
match: {
|
|
@@ -613,7 +709,7 @@ var configuredCallOption = import_zod.z.object({
|
|
|
613
709
|
receiver: import_zod.z.string(),
|
|
614
710
|
/** Method that performs the send. */
|
|
615
711
|
method: import_zod.z.string(),
|
|
616
|
-
/**
|
|
712
|
+
/** Index of the argument that is the subject. */
|
|
617
713
|
subjectArg: import_zod.z.number(),
|
|
618
714
|
/**
|
|
619
715
|
* Which argument the message body is. Left out when the method has no
|
|
@@ -624,7 +720,7 @@ var configuredCallOption = import_zod.z.object({
|
|
|
624
720
|
}).strict();
|
|
625
721
|
|
|
626
722
|
// src/paths/enumeratePaths.ts
|
|
627
|
-
var
|
|
723
|
+
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
628
724
|
var MAX_PATHS = 256;
|
|
629
725
|
var UnmodeledFlow = class extends Error {
|
|
630
726
|
};
|
|
@@ -668,12 +764,12 @@ var loopCompletedCond = (headerText, exit) => fixedCond(
|
|
|
668
764
|
exit === "throw" ? "earlyThrow" : "earlyReturn"
|
|
669
765
|
);
|
|
670
766
|
var catchEntryCond = () => fixedCond(
|
|
671
|
-
{ sourceText:
|
|
767
|
+
{ sourceText: import_behavioral_ir4.CATCH_ENTRY_TEXT, expression: null },
|
|
672
768
|
"positive",
|
|
673
769
|
"catchBlock"
|
|
674
770
|
);
|
|
675
|
-
function classify(
|
|
676
|
-
return
|
|
771
|
+
function classify(path6, home, isAncestorOrSelf) {
|
|
772
|
+
return path6.map((cond) => {
|
|
677
773
|
if (cond.branchStmt === null) {
|
|
678
774
|
return cond.info;
|
|
679
775
|
}
|
|
@@ -738,9 +834,9 @@ function chargeBudget(state) {
|
|
|
738
834
|
);
|
|
739
835
|
}
|
|
740
836
|
}
|
|
741
|
-
function recordTerminal(ctx, terminal, home,
|
|
837
|
+
function recordTerminal(ctx, terminal, home, path6) {
|
|
742
838
|
chargeBudget(ctx.state);
|
|
743
|
-
const info = classify(
|
|
839
|
+
const info = classify(path6, home, ctx.isAncestorOrSelf);
|
|
744
840
|
const existing = ctx.state.byTerminal.get(terminal) ?? [];
|
|
745
841
|
existing.push(info);
|
|
746
842
|
ctx.state.byTerminal.set(terminal, existing);
|
|
@@ -751,15 +847,15 @@ function containsTerminal(ctx, stmt) {
|
|
|
751
847
|
}
|
|
752
848
|
return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
|
|
753
849
|
}
|
|
754
|
-
function stepIf(stmt,
|
|
850
|
+
function stepIf(stmt, path6, ctx) {
|
|
755
851
|
const thenExit = exitKindOfList(stmt.thenBody);
|
|
756
852
|
const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
|
|
757
853
|
const thenPath = [
|
|
758
|
-
...
|
|
854
|
+
...path6,
|
|
759
855
|
branchCond(stmt, stmt.condition, "positive", elseExit)
|
|
760
856
|
];
|
|
761
857
|
const elsePath = [
|
|
762
|
-
...
|
|
858
|
+
...path6,
|
|
763
859
|
branchCond(
|
|
764
860
|
stmt,
|
|
765
861
|
stmt.condition,
|
|
@@ -776,7 +872,7 @@ function stepIf(stmt, path4, ctx) {
|
|
|
776
872
|
}
|
|
777
873
|
return out;
|
|
778
874
|
}
|
|
779
|
-
function stepSwitch(stmt,
|
|
875
|
+
function stepSwitch(stmt, path6, ctx) {
|
|
780
876
|
const out = [];
|
|
781
877
|
const negations = [];
|
|
782
878
|
let defaultRanBody = false;
|
|
@@ -786,7 +882,7 @@ function stepSwitch(stmt, path4, ctx) {
|
|
|
786
882
|
if (hasStrayBreak(group.body)) {
|
|
787
883
|
throw new UnmodeledFlow("non-trailing break in switch clause");
|
|
788
884
|
}
|
|
789
|
-
const groupPath = group.condition === null ? [...
|
|
885
|
+
const groupPath = group.condition === null ? [...path6, ...negations] : [...path6, fixedCond(group.condition, "positive", "explicit")];
|
|
790
886
|
const conts = enumerate(ctx, group.body, groupPath);
|
|
791
887
|
if (conts.length > 0) {
|
|
792
888
|
if (!group.hasTrailingBreak && !fallthroughSafe) {
|
|
@@ -803,24 +899,24 @@ function stepSwitch(stmt, path4, ctx) {
|
|
|
803
899
|
}
|
|
804
900
|
}
|
|
805
901
|
if (!defaultRanBody) {
|
|
806
|
-
out.push([...
|
|
902
|
+
out.push([...path6, ...negations]);
|
|
807
903
|
}
|
|
808
904
|
return out;
|
|
809
905
|
}
|
|
810
|
-
function stepLoop(stmt,
|
|
906
|
+
function stepLoop(stmt, path6, ctx) {
|
|
811
907
|
const bodyExit = exitKindOfList(stmt.body);
|
|
812
908
|
if (containsTerminal(ctx, stmt)) {
|
|
813
909
|
enumerate(ctx, stmt.body, [
|
|
814
|
-
...
|
|
910
|
+
...path6,
|
|
815
911
|
loopIterationCond(stmt.condition.sourceText)
|
|
816
912
|
]);
|
|
817
913
|
}
|
|
818
914
|
if (bodyExit !== null) {
|
|
819
|
-
return [[...
|
|
915
|
+
return [[...path6, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
|
|
820
916
|
}
|
|
821
|
-
return [
|
|
917
|
+
return [path6];
|
|
822
918
|
}
|
|
823
|
-
function stepTry(stmt,
|
|
919
|
+
function stepTry(stmt, path6, ctx) {
|
|
824
920
|
if (stmt.finallyBody !== null) {
|
|
825
921
|
const finallyHasTerminal = stmt.finallyBody.some(
|
|
826
922
|
(s) => containsTerminal(ctx, s)
|
|
@@ -830,22 +926,22 @@ function stepTry(stmt, path4, ctx) {
|
|
|
830
926
|
}
|
|
831
927
|
}
|
|
832
928
|
const out = [];
|
|
833
|
-
out.push(...enumerate(ctx, stmt.tryBody,
|
|
929
|
+
out.push(...enumerate(ctx, stmt.tryBody, path6));
|
|
834
930
|
if (stmt.catchBody !== null) {
|
|
835
|
-
const catchPath = [...
|
|
931
|
+
const catchPath = [...path6, catchEntryCond()];
|
|
836
932
|
out.push(...enumerate(ctx, stmt.catchBody, catchPath));
|
|
837
933
|
}
|
|
838
934
|
return out;
|
|
839
935
|
}
|
|
840
|
-
function stepExit(stmt,
|
|
936
|
+
function stepExit(stmt, path6, ctx) {
|
|
841
937
|
const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
|
|
842
938
|
if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
|
|
843
|
-
collector.push(
|
|
939
|
+
collector.push(path6);
|
|
844
940
|
}
|
|
845
941
|
return [];
|
|
846
942
|
}
|
|
847
|
-
function stepOpaque(_stmt,
|
|
848
|
-
return [
|
|
943
|
+
function stepOpaque(_stmt, path6, _ctx) {
|
|
944
|
+
return [path6];
|
|
849
945
|
}
|
|
850
946
|
var stepHandlers = {
|
|
851
947
|
if: stepIf,
|
|
@@ -855,20 +951,20 @@ var stepHandlers = {
|
|
|
855
951
|
exit: stepExit,
|
|
856
952
|
opaque: stepOpaque
|
|
857
953
|
};
|
|
858
|
-
function stepCallback(ctx, body,
|
|
954
|
+
function stepCallback(ctx, body, path6) {
|
|
859
955
|
const exits = [];
|
|
860
956
|
ctx.state.callbackExits.push(exits);
|
|
861
957
|
let fellThrough;
|
|
862
958
|
try {
|
|
863
|
-
fellThrough = enumerate(ctx, body,
|
|
959
|
+
fellThrough = enumerate(ctx, body, path6);
|
|
864
960
|
} finally {
|
|
865
961
|
ctx.state.callbackExits.pop();
|
|
866
962
|
}
|
|
867
963
|
const out = [...fellThrough, ...exits];
|
|
868
|
-
return out.length === 0 ? [
|
|
964
|
+
return out.length === 0 ? [path6] : out;
|
|
869
965
|
}
|
|
870
|
-
function stepStatement(ctx, stmt,
|
|
871
|
-
let paths = [
|
|
966
|
+
function stepStatement(ctx, stmt, path6) {
|
|
967
|
+
let paths = [path6];
|
|
872
968
|
for (const body of stmt.callbacks ?? []) {
|
|
873
969
|
paths = paths.flatMap((each) => stepCallback(ctx, body, each));
|
|
874
970
|
}
|
|
@@ -949,8 +1045,8 @@ function enumerate(ctx, stmts, prefix) {
|
|
|
949
1045
|
let frontiers = [[...prefix]];
|
|
950
1046
|
for (const stmt of stmts) {
|
|
951
1047
|
const nextFrontiers = [];
|
|
952
|
-
for (const
|
|
953
|
-
nextFrontiers.push(...stepStatement(ctx, stmt,
|
|
1048
|
+
for (const path6 of mergeRejoined(frontiers)) {
|
|
1049
|
+
nextFrontiers.push(...stepStatement(ctx, stmt, path6));
|
|
954
1050
|
}
|
|
955
1051
|
frontiers = nextFrontiers;
|
|
956
1052
|
if (frontiers.length > MAX_PATHS) {
|
|
@@ -1001,9 +1097,9 @@ function enumerateStructuredPaths(input) {
|
|
|
1001
1097
|
isAncestorOrSelf
|
|
1002
1098
|
};
|
|
1003
1099
|
const continuations = withRejoined(enumerate(ctx, input.statements, []));
|
|
1004
|
-
for (const
|
|
1100
|
+
for (const path6 of continuations) {
|
|
1005
1101
|
chargeBudget(state);
|
|
1006
|
-
state.fallthrough.push(classify(
|
|
1102
|
+
state.fallthrough.push(classify(path6, null, isAncestorOrSelf));
|
|
1007
1103
|
}
|
|
1008
1104
|
return { byTerminal: state.byTerminal, fallthrough: state.fallthrough };
|
|
1009
1105
|
}
|
|
@@ -1046,8 +1142,8 @@ function sharedGatingConditions(paths, readPredicate) {
|
|
|
1046
1142
|
return [];
|
|
1047
1143
|
}
|
|
1048
1144
|
const shared = new Set(first.map(keyOf2));
|
|
1049
|
-
for (const
|
|
1050
|
-
const here = new Set(
|
|
1145
|
+
for (const path6 of rest) {
|
|
1146
|
+
const here = new Set(path6.map(keyOf2));
|
|
1051
1147
|
for (const value of shared) {
|
|
1052
1148
|
if (!here.has(value)) {
|
|
1053
1149
|
shared.delete(value);
|
|
@@ -1077,7 +1173,7 @@ var IdSet = class {
|
|
|
1077
1173
|
has(node) {
|
|
1078
1174
|
return this.byKey.has(node.id);
|
|
1079
1175
|
}
|
|
1080
|
-
/** The
|
|
1176
|
+
/** The wrapper that was added, which may be a different object from `node`. */
|
|
1081
1177
|
get(node) {
|
|
1082
1178
|
return this.byKey.get(node.id);
|
|
1083
1179
|
}
|
|
@@ -1108,6 +1204,51 @@ var IdMap = class {
|
|
|
1108
1204
|
}
|
|
1109
1205
|
};
|
|
1110
1206
|
|
|
1207
|
+
// src/paths/nodeReads.ts
|
|
1208
|
+
var EnclosingNodes = class {
|
|
1209
|
+
constructor(types) {
|
|
1210
|
+
this.types = types;
|
|
1211
|
+
}
|
|
1212
|
+
types;
|
|
1213
|
+
byTree = /* @__PURE__ */ new WeakMap();
|
|
1214
|
+
/**
|
|
1215
|
+
* The nearest ancestor of one of the types, or null when there is none.
|
|
1216
|
+
* Every node passed on the way up has the same result, so each one is
|
|
1217
|
+
* kept, and a later read from a sibling stops one step up.
|
|
1218
|
+
*/
|
|
1219
|
+
of(node) {
|
|
1220
|
+
const kept = this.keptFor(node.tree);
|
|
1221
|
+
const known = kept.get(node.id);
|
|
1222
|
+
if (known !== void 0) {
|
|
1223
|
+
return known;
|
|
1224
|
+
}
|
|
1225
|
+
const passed = [node.id];
|
|
1226
|
+
let current = node.parent;
|
|
1227
|
+
while (current !== null && !this.types.has(current.type)) {
|
|
1228
|
+
const above = kept.get(current.id);
|
|
1229
|
+
if (above !== void 0) {
|
|
1230
|
+
current = above;
|
|
1231
|
+
break;
|
|
1232
|
+
}
|
|
1233
|
+
passed.push(current.id);
|
|
1234
|
+
current = current.parent;
|
|
1235
|
+
}
|
|
1236
|
+
for (const id of passed) {
|
|
1237
|
+
kept.set(id, current);
|
|
1238
|
+
}
|
|
1239
|
+
return current;
|
|
1240
|
+
}
|
|
1241
|
+
keptFor(tree) {
|
|
1242
|
+
const known = this.byTree.get(tree);
|
|
1243
|
+
if (known !== void 0) {
|
|
1244
|
+
return known;
|
|
1245
|
+
}
|
|
1246
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
1247
|
+
this.byTree.set(tree, fresh);
|
|
1248
|
+
return fresh;
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
|
|
1111
1252
|
// src/paths/nodeWalk.ts
|
|
1112
1253
|
var SKIP_CHILDREN = /* @__PURE__ */ Symbol("skipChildren");
|
|
1113
1254
|
function walkDescendants(root, carried, visitor) {
|
|
@@ -1124,23 +1265,23 @@ function walkDescendants(root, carried, visitor) {
|
|
|
1124
1265
|
}
|
|
1125
1266
|
|
|
1126
1267
|
// src/projectRoot.ts
|
|
1127
|
-
var
|
|
1268
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
1128
1269
|
function commonDirectoryOf(files) {
|
|
1129
|
-
const absolute = files.filter((f) =>
|
|
1270
|
+
const absolute = files.filter((f) => import_node_path3.default.isAbsolute(f));
|
|
1130
1271
|
const first = absolute[0];
|
|
1131
1272
|
if (first === void 0) {
|
|
1132
1273
|
return void 0;
|
|
1133
1274
|
}
|
|
1134
|
-
let shared =
|
|
1275
|
+
let shared = import_node_path3.default.dirname(first).split(import_node_path3.default.sep);
|
|
1135
1276
|
for (const file of absolute.slice(1)) {
|
|
1136
|
-
const parts =
|
|
1277
|
+
const parts = import_node_path3.default.dirname(file).split(import_node_path3.default.sep);
|
|
1137
1278
|
let i = 0;
|
|
1138
1279
|
while (i < shared.length && i < parts.length && shared[i] === parts[i]) {
|
|
1139
1280
|
i += 1;
|
|
1140
1281
|
}
|
|
1141
1282
|
shared = shared.slice(0, i);
|
|
1142
1283
|
}
|
|
1143
|
-
const joined = shared.join(
|
|
1284
|
+
const joined = shared.join(import_node_path3.default.sep);
|
|
1144
1285
|
return joined.length > 1 ? joined : void 0;
|
|
1145
1286
|
}
|
|
1146
1287
|
|
|
@@ -1197,11 +1338,79 @@ function valueToReadFurtherFrom(reading) {
|
|
|
1197
1338
|
return reading.kind === "written" ? reading.value : null;
|
|
1198
1339
|
}
|
|
1199
1340
|
|
|
1341
|
+
// src/testFiles.ts
|
|
1342
|
+
function isListedTestFile(file, listed) {
|
|
1343
|
+
if (listed === void 0) {
|
|
1344
|
+
return true;
|
|
1345
|
+
}
|
|
1346
|
+
const whole = withForwardSlashes(file);
|
|
1347
|
+
return listed.some((entry) => {
|
|
1348
|
+
const tail = withForwardSlashes(entry).replace(/^\.\//, "");
|
|
1349
|
+
return whole === tail || whole.endsWith(`/${tail}`);
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
function matchesTestFileName(file, patterns) {
|
|
1353
|
+
const base = withForwardSlashes(file).split("/").pop() ?? "";
|
|
1354
|
+
return patterns.some((pattern) => globToRegExp(pattern).test(base));
|
|
1355
|
+
}
|
|
1356
|
+
function globToRegExp(pattern) {
|
|
1357
|
+
const escaped = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
1358
|
+
return new RegExp(`^${escaped}$`);
|
|
1359
|
+
}
|
|
1360
|
+
function withForwardSlashes(file) {
|
|
1361
|
+
return file.replace(/\\/g, "/");
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// src/valueSources.ts
|
|
1365
|
+
var QUOTED_LENGTH = 80;
|
|
1366
|
+
function sourceRefsOf(leaves, spelling) {
|
|
1367
|
+
const refs = [];
|
|
1368
|
+
const said = /* @__PURE__ */ new Set();
|
|
1369
|
+
for (const leaf of leaves) {
|
|
1370
|
+
const ref = convertedFrom(refOf(leaf, spelling), leaf.conversions);
|
|
1371
|
+
const spelled = JSON.stringify(ref);
|
|
1372
|
+
if (!said.has(spelled)) {
|
|
1373
|
+
said.add(spelled);
|
|
1374
|
+
refs.push(ref);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return refs;
|
|
1378
|
+
}
|
|
1379
|
+
function convertedFrom(ref, conversions) {
|
|
1380
|
+
return conversions.reduceRight(
|
|
1381
|
+
(from, method) => ({
|
|
1382
|
+
type: "derived",
|
|
1383
|
+
from,
|
|
1384
|
+
derivation: { type: "methodCall", method, args: [] }
|
|
1385
|
+
}),
|
|
1386
|
+
ref
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
function refOf(leaf, spelling) {
|
|
1390
|
+
const whole = leaf.computedAt === null;
|
|
1391
|
+
const input = whole ? spelling.inputOf(leaf) : null;
|
|
1392
|
+
if (input !== null) {
|
|
1393
|
+
return input;
|
|
1394
|
+
}
|
|
1395
|
+
if (whole && leaf.end.is === "written" && leaf.path.length === 0) {
|
|
1396
|
+
const literal = spelling.literalAt(leaf.key);
|
|
1397
|
+
if (literal !== void 0) {
|
|
1398
|
+
return { type: "literal", value: literal };
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
const at = leaf.computedAt ?? leaf.key;
|
|
1402
|
+
return { type: "unresolved", sourceText: quoted(spelling.textAt(at), at) };
|
|
1403
|
+
}
|
|
1404
|
+
function quoted(text, key) {
|
|
1405
|
+
const written = (text ?? key.slice(key.lastIndexOf("#") + 1)).replace(/\s+/g, " ").trim();
|
|
1406
|
+
return written.length <= QUOTED_LENGTH ? written : `${written.slice(0, QUOTED_LENGTH - 3)}...`;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1200
1409
|
// src/adapterStamp.ts
|
|
1201
1410
|
var import_node_crypto = require("crypto");
|
|
1202
|
-
var
|
|
1411
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
1203
1412
|
var import_node_module = require("module");
|
|
1204
|
-
var
|
|
1413
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
1205
1414
|
var import_node_url = require("url");
|
|
1206
1415
|
var import_meta = {};
|
|
1207
1416
|
var ANALYSIS_PACKAGES = [
|
|
@@ -1244,16 +1453,16 @@ function createAdapterStamp(config) {
|
|
|
1244
1453
|
function readAdapterCodeStamp(moduleUrl) {
|
|
1245
1454
|
try {
|
|
1246
1455
|
const selfPath = (0, import_node_url.fileURLToPath)(moduleUrl);
|
|
1247
|
-
const hash = computeDistHashFrom(
|
|
1456
|
+
const hash = computeDistHashFrom(import_node_path4.default.dirname(selfPath));
|
|
1248
1457
|
return hash.length > 0 ? { kind: "bundle", hash } : SOURCE_STAMP;
|
|
1249
1458
|
} catch {
|
|
1250
1459
|
return SOURCE_STAMP;
|
|
1251
1460
|
}
|
|
1252
1461
|
}
|
|
1253
1462
|
function computeDistHashFrom(dir) {
|
|
1254
|
-
const candidates = [
|
|
1463
|
+
const candidates = [import_node_path4.default.join(dir, "index.js"), import_node_path4.default.join(dir, "index.cjs")];
|
|
1255
1464
|
for (const candidate of candidates) {
|
|
1256
|
-
if (!
|
|
1465
|
+
if (!import_node_fs2.default.existsSync(candidate)) {
|
|
1257
1466
|
continue;
|
|
1258
1467
|
}
|
|
1259
1468
|
return computeContentHash([candidate, ...analysisBundles()]);
|
|
@@ -1267,7 +1476,7 @@ function computeContentHash(paths) {
|
|
|
1267
1476
|
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
1268
1477
|
for (const file of paths) {
|
|
1269
1478
|
try {
|
|
1270
|
-
hash.update(
|
|
1479
|
+
hash.update(import_node_fs2.default.readFileSync(file));
|
|
1271
1480
|
} catch {
|
|
1272
1481
|
return "";
|
|
1273
1482
|
}
|
|
@@ -1283,13 +1492,29 @@ function projectFileStamp(paths) {
|
|
|
1283
1492
|
hash.update(file);
|
|
1284
1493
|
hash.update("\0");
|
|
1285
1494
|
try {
|
|
1286
|
-
hash.update(
|
|
1495
|
+
hash.update(import_node_fs2.default.readFileSync(file));
|
|
1287
1496
|
} catch {
|
|
1288
1497
|
hash.update("absent");
|
|
1289
1498
|
}
|
|
1290
1499
|
}
|
|
1291
1500
|
return hash.digest("hex").slice(0, 16);
|
|
1292
1501
|
}
|
|
1502
|
+
function extractionConfigStamp(config) {
|
|
1503
|
+
const parts = [
|
|
1504
|
+
["gapHandling", config.gapHandling ?? "permissive"],
|
|
1505
|
+
["includeReachable", optionalText(config.includeReachable)],
|
|
1506
|
+
["workspaceRoot", config.workspaceRoot],
|
|
1507
|
+
["projectRoot", config.projectRoot],
|
|
1508
|
+
["importRoots", config.importRoots?.join(import_node_path4.default.delimiter)],
|
|
1509
|
+
["modules", modulesStamp(config.modules)]
|
|
1510
|
+
];
|
|
1511
|
+
return parts.flatMap(
|
|
1512
|
+
([name, value]) => value === void 0 ? [] : [`${name}=${value}`]
|
|
1513
|
+
).join(",");
|
|
1514
|
+
}
|
|
1515
|
+
function optionalText(value) {
|
|
1516
|
+
return value === void 0 ? void 0 : String(value);
|
|
1517
|
+
}
|
|
1293
1518
|
function runDigest(packsDigest, packs, files) {
|
|
1294
1519
|
const inputs = packs.flatMap((pack) => pack.discoveryInputs?.(files) ?? []);
|
|
1295
1520
|
return `${packsDigest}|reads:${projectFileStamp(inputs)}`;
|
|
@@ -1307,10 +1532,118 @@ function analysisBundles() {
|
|
|
1307
1532
|
}
|
|
1308
1533
|
|
|
1309
1534
|
// src/cache.ts
|
|
1535
|
+
var import_node_crypto3 = require("crypto");
|
|
1536
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
1537
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
1538
|
+
|
|
1539
|
+
// src/cacheStamps.ts
|
|
1310
1540
|
var import_node_crypto2 = require("crypto");
|
|
1311
1541
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
1312
|
-
var
|
|
1313
|
-
|
|
1542
|
+
var RECENT_CHANGE_MS = 2e3;
|
|
1543
|
+
function stampMayMissAWrite(stat, statAt) {
|
|
1544
|
+
return Math.max(stat.mtimeMs, stat.ctimeMs) > statAt - RECENT_CHANGE_MS;
|
|
1545
|
+
}
|
|
1546
|
+
async function startRun(files, configPath) {
|
|
1547
|
+
const startedAt = Date.now();
|
|
1548
|
+
const config = configPath === void 0 ? null : await statAtStart(configPath);
|
|
1549
|
+
const stats = await Promise.all(files.map(statAtStart));
|
|
1550
|
+
stats.sort(
|
|
1551
|
+
(a, b) => a.stamp.path < b.stamp.path ? -1 : a.stamp.path > b.stamp.path ? 1 : 0
|
|
1552
|
+
);
|
|
1553
|
+
return {
|
|
1554
|
+
startedAt,
|
|
1555
|
+
config: config?.ctimeMs === null ? null : config,
|
|
1556
|
+
files: stats,
|
|
1557
|
+
hashes: /* @__PURE__ */ new Map()
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
async function statAtStart(filePath) {
|
|
1561
|
+
try {
|
|
1562
|
+
const stat = await import_promises.default.stat(filePath);
|
|
1563
|
+
return {
|
|
1564
|
+
stamp: { path: filePath, mtimeMs: stat.mtimeMs, size: stat.size },
|
|
1565
|
+
ctimeMs: stat.ctimeMs
|
|
1566
|
+
};
|
|
1567
|
+
} catch {
|
|
1568
|
+
return { stamp: { path: filePath, mtimeMs: -1, size: -1 }, ctimeMs: null };
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
async function hashOf(run, filePath) {
|
|
1572
|
+
const known = run.hashes.get(filePath);
|
|
1573
|
+
if (known !== void 0) {
|
|
1574
|
+
return known;
|
|
1575
|
+
}
|
|
1576
|
+
const hash = await hashFile(filePath);
|
|
1577
|
+
run.hashes.set(filePath, hash);
|
|
1578
|
+
return hash;
|
|
1579
|
+
}
|
|
1580
|
+
async function hashRecentChanges(run) {
|
|
1581
|
+
const recent = [...run.config === null ? [] : [run.config], ...run.files].filter(
|
|
1582
|
+
(file) => file.ctimeMs !== null && stampMayMissAWrite(
|
|
1583
|
+
{ mtimeMs: file.stamp.mtimeMs, ctimeMs: file.ctimeMs },
|
|
1584
|
+
run.startedAt
|
|
1585
|
+
)
|
|
1586
|
+
).map((file) => file.stamp.path);
|
|
1587
|
+
await Promise.all(recent.map((filePath) => hashOf(run, filePath)));
|
|
1588
|
+
}
|
|
1589
|
+
async function stillMatches(stored, found, run) {
|
|
1590
|
+
if (!fileStampEquals(stored, found)) {
|
|
1591
|
+
return false;
|
|
1592
|
+
}
|
|
1593
|
+
if (stored === null || stored.verifyHash !== true) {
|
|
1594
|
+
return true;
|
|
1595
|
+
}
|
|
1596
|
+
return await hashOf(run, stored.path) === stored.contentHash;
|
|
1597
|
+
}
|
|
1598
|
+
async function filesStillMatch(stored, run) {
|
|
1599
|
+
if (stored.length !== run.files.length || !stored.every((s, i) => fileStampEquals(s, run.files[i]?.stamp ?? null))) {
|
|
1600
|
+
return false;
|
|
1601
|
+
}
|
|
1602
|
+
const checks = await Promise.all(
|
|
1603
|
+
stored.map((s, i) => stillMatches(s, run.files[i]?.stamp ?? null, run))
|
|
1604
|
+
);
|
|
1605
|
+
return checks.every(Boolean);
|
|
1606
|
+
}
|
|
1607
|
+
async function recordedStamp(start, run, prior) {
|
|
1608
|
+
if (start.ctimeMs === null) {
|
|
1609
|
+
return start.stamp;
|
|
1610
|
+
}
|
|
1611
|
+
const filePath = start.stamp.path;
|
|
1612
|
+
const now = await import_promises.default.stat(filePath).catch(() => null);
|
|
1613
|
+
if (now === null || now.mtimeMs !== start.stamp.mtimeMs || now.size !== start.stamp.size || now.ctimeMs !== start.ctimeMs) {
|
|
1614
|
+
return null;
|
|
1615
|
+
}
|
|
1616
|
+
const atStart = { mtimeMs: start.stamp.mtimeMs, ctimeMs: start.ctimeMs };
|
|
1617
|
+
if (stampMayMissAWrite(atStart, run.startedAt)) {
|
|
1618
|
+
const readBefore = run.hashes.get(filePath);
|
|
1619
|
+
return readBefore === void 0 || readBefore === null ? null : { ...start.stamp, contentHash: readBefore, verifyHash: true };
|
|
1620
|
+
}
|
|
1621
|
+
const hash = run.hashes.get(filePath) ?? reusableHash(prior, start.stamp) ?? await hashFile(filePath);
|
|
1622
|
+
return hash === null ? start.stamp : { ...start.stamp, contentHash: hash };
|
|
1623
|
+
}
|
|
1624
|
+
function reusableHash(prior, stamp) {
|
|
1625
|
+
return prior !== void 0 && prior.verifyHash !== true && fileStampEquals(prior, stamp) ? prior.contentHash : void 0;
|
|
1626
|
+
}
|
|
1627
|
+
async function hashFile(filePath) {
|
|
1628
|
+
try {
|
|
1629
|
+
const content = await import_promises.default.readFile(filePath);
|
|
1630
|
+
return (0, import_node_crypto2.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
1631
|
+
} catch {
|
|
1632
|
+
return null;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
function fileStampEquals(a, b) {
|
|
1636
|
+
if (a === null && b === null) {
|
|
1637
|
+
return true;
|
|
1638
|
+
}
|
|
1639
|
+
if (a === null || b === null) {
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1642
|
+
return a.path === b.path && a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
// src/cache.ts
|
|
1646
|
+
var SCHEMA_VERSION = "9";
|
|
1314
1647
|
var MAX_ENTRIES = 2;
|
|
1315
1648
|
var ENTRY_PREFIX = "key-";
|
|
1316
1649
|
var ENTRY_DIR_NAME = new RegExp(`^${ENTRY_PREFIX}[0-9a-f]{16}$`);
|
|
@@ -1327,56 +1660,88 @@ function createCacheLayer(cacheDir) {
|
|
|
1327
1660
|
}
|
|
1328
1661
|
};
|
|
1329
1662
|
}
|
|
1663
|
+
const manifests = new ManifestReads();
|
|
1664
|
+
const runs = /* @__PURE__ */ new WeakMap();
|
|
1665
|
+
const runFor = async (input) => runs.get(input) ?? await startRun(input.files, input.configPath);
|
|
1666
|
+
const lookupWith = async (input, run) => {
|
|
1667
|
+
const entryDir = entryDirFor(cacheDir, input);
|
|
1668
|
+
const manifest = await manifests.readAtRunStart(
|
|
1669
|
+
import_node_path5.default.join(entryDir, "manifest.json")
|
|
1670
|
+
);
|
|
1671
|
+
if (manifest === null) {
|
|
1672
|
+
return missDiag(await describeAbsentEntry(cacheDir));
|
|
1673
|
+
}
|
|
1674
|
+
if (!await stillMatches(
|
|
1675
|
+
manifest.configStamp,
|
|
1676
|
+
run.config?.stamp ?? null,
|
|
1677
|
+
run
|
|
1678
|
+
)) {
|
|
1679
|
+
return missDiag("config-changed");
|
|
1680
|
+
}
|
|
1681
|
+
if (!await filesStillMatch(manifest.files, run)) {
|
|
1682
|
+
return missDiag("files-changed");
|
|
1683
|
+
}
|
|
1684
|
+
await markUsed(entryDir);
|
|
1685
|
+
manifests.forget();
|
|
1686
|
+
return {
|
|
1687
|
+
kind: "hit",
|
|
1688
|
+
summaries: manifest.summaries,
|
|
1689
|
+
diagnostic: { kind: "hit" }
|
|
1690
|
+
};
|
|
1691
|
+
};
|
|
1330
1692
|
return {
|
|
1331
1693
|
async tryHit(input) {
|
|
1332
1694
|
const result = await this.lookup(input);
|
|
1333
1695
|
return result.kind === "hit" ? result.summaries : null;
|
|
1334
1696
|
},
|
|
1335
1697
|
async lookup(input) {
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
)
|
|
1340
|
-
|
|
1341
|
-
return missDiag(await describeAbsentEntry(cacheDir));
|
|
1698
|
+
const run = await startRun(input.files, input.configPath);
|
|
1699
|
+
runs.set(input, run);
|
|
1700
|
+
const result = await lookupWith(input, run);
|
|
1701
|
+
if (result.kind === "miss") {
|
|
1702
|
+
await hashRecentChanges(run);
|
|
1342
1703
|
}
|
|
1343
|
-
|
|
1344
|
-
if (!fileStampEquals(manifest.configStamp, currentConfigStamp)) {
|
|
1345
|
-
return missDiag("config-changed");
|
|
1346
|
-
}
|
|
1347
|
-
const currentFiles = await resolveFileStamps(input);
|
|
1348
|
-
if (!fileStampsEqual(manifest.files, currentFiles)) {
|
|
1349
|
-
return missDiag("files-changed");
|
|
1350
|
-
}
|
|
1351
|
-
await markUsed(entryDir);
|
|
1352
|
-
return {
|
|
1353
|
-
kind: "hit",
|
|
1354
|
-
summaries: manifest.summaries,
|
|
1355
|
-
diagnostic: { kind: "hit" }
|
|
1356
|
-
};
|
|
1704
|
+
return result;
|
|
1357
1705
|
},
|
|
1358
1706
|
async plan(input) {
|
|
1359
1707
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1360
|
-
const manifest = await
|
|
1361
|
-
|
|
1708
|
+
const manifest = await manifests.readAgain(
|
|
1709
|
+
import_node_path5.default.join(entryDir, "manifest.json")
|
|
1362
1710
|
);
|
|
1363
1711
|
if (manifest === null || manifest.roots === void 0 || manifest.rootMeta === void 0 || manifest.owners === void 0) {
|
|
1364
1712
|
return null;
|
|
1365
1713
|
}
|
|
1366
|
-
const
|
|
1367
|
-
if (!
|
|
1714
|
+
const run = await runFor(input);
|
|
1715
|
+
if (!await stillMatches(
|
|
1716
|
+
manifest.configStamp,
|
|
1717
|
+
run.config?.stamp ?? null,
|
|
1718
|
+
run
|
|
1719
|
+
)) {
|
|
1368
1720
|
return null;
|
|
1369
1721
|
}
|
|
1370
1722
|
await markUsed(entryDir);
|
|
1371
|
-
return buildPlan(manifest,
|
|
1723
|
+
return buildPlan(manifest, run);
|
|
1372
1724
|
},
|
|
1373
1725
|
async write(input, summaries, attribution) {
|
|
1374
1726
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1375
|
-
const previous = await
|
|
1376
|
-
|
|
1727
|
+
const previous = await manifests.readAgain(
|
|
1728
|
+
import_node_path5.default.join(entryDir, "manifest.json")
|
|
1377
1729
|
);
|
|
1378
|
-
|
|
1379
|
-
const
|
|
1730
|
+
manifests.forget();
|
|
1731
|
+
const known = runs.get(input);
|
|
1732
|
+
const run = known ?? await runFor(input);
|
|
1733
|
+
if (known === void 0) {
|
|
1734
|
+
await hashRecentChanges(run);
|
|
1735
|
+
}
|
|
1736
|
+
runs.delete(input);
|
|
1737
|
+
const configStamp = run.config === null ? null : await recordedStamp(run.config, run, void 0);
|
|
1738
|
+
const prior = new Map((previous?.files ?? []).map((f) => [f.path, f]));
|
|
1739
|
+
const recorded = await Promise.all(
|
|
1740
|
+
run.files.map(
|
|
1741
|
+
(file) => recordedStamp(file, run, prior.get(file.stamp.path))
|
|
1742
|
+
)
|
|
1743
|
+
);
|
|
1744
|
+
const files = recorded.filter((stamp) => stamp !== null);
|
|
1380
1745
|
const manifest = {
|
|
1381
1746
|
schemaVersion: SCHEMA_VERSION,
|
|
1382
1747
|
adapterPacksDigest: input.adapterPacksDigest,
|
|
@@ -1385,19 +1750,20 @@ function createCacheLayer(cacheDir) {
|
|
|
1385
1750
|
summaries,
|
|
1386
1751
|
...attribution === void 0 ? {} : encodeAttribution(attribution)
|
|
1387
1752
|
};
|
|
1388
|
-
await
|
|
1389
|
-
await
|
|
1390
|
-
|
|
1753
|
+
await import_promises2.default.mkdir(entryDir, { recursive: true });
|
|
1754
|
+
await import_promises2.default.writeFile(
|
|
1755
|
+
import_node_path5.default.join(entryDir, "manifest.json"),
|
|
1391
1756
|
JSON.stringify(manifest)
|
|
1392
1757
|
);
|
|
1393
1758
|
await evictOldEntries(cacheDir, entryDir);
|
|
1394
1759
|
}
|
|
1395
1760
|
};
|
|
1396
1761
|
}
|
|
1397
|
-
async function buildPlan(manifest,
|
|
1762
|
+
async function buildPlan(manifest, run) {
|
|
1398
1763
|
const stored = new Map(manifest.files.map((f) => [f.path, f]));
|
|
1399
|
-
const current = new Map(
|
|
1764
|
+
const current = new Map(run.files.map((f) => [f.stamp.path, f.stamp]));
|
|
1400
1765
|
const changed = /* @__PURE__ */ new Set();
|
|
1766
|
+
const added = /* @__PURE__ */ new Set();
|
|
1401
1767
|
const removed = /* @__PURE__ */ new Set();
|
|
1402
1768
|
for (const p of stored.keys()) {
|
|
1403
1769
|
if (!current.has(p)) {
|
|
@@ -1409,17 +1775,20 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1409
1775
|
const before = stored.get(p);
|
|
1410
1776
|
if (before === void 0) {
|
|
1411
1777
|
changed.add(p);
|
|
1778
|
+
added.add(p);
|
|
1412
1779
|
} else if (!fileStampEquals(before, stamp)) {
|
|
1413
1780
|
if (before.contentHash === void 0) {
|
|
1414
1781
|
changed.add(p);
|
|
1415
1782
|
} else {
|
|
1416
1783
|
toVerify.push(p);
|
|
1417
1784
|
}
|
|
1785
|
+
} else if (before.verifyHash === true) {
|
|
1786
|
+
toVerify.push(p);
|
|
1418
1787
|
}
|
|
1419
1788
|
}
|
|
1420
1789
|
await Promise.all(
|
|
1421
1790
|
toVerify.map(async (p) => {
|
|
1422
|
-
const hash = await
|
|
1791
|
+
const hash = await hashOf(run, p);
|
|
1423
1792
|
if (hash === null || hash !== stored.get(p)?.contentHash) {
|
|
1424
1793
|
changed.add(p);
|
|
1425
1794
|
}
|
|
@@ -1428,6 +1797,10 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1428
1797
|
const roots = /* @__PURE__ */ new Map();
|
|
1429
1798
|
const rootNames = manifest.roots ?? [];
|
|
1430
1799
|
const depPaths = manifest.depPaths ?? [];
|
|
1800
|
+
const pathsOf = (ids) => ids.flatMap((d) => {
|
|
1801
|
+
const p = depPaths[d];
|
|
1802
|
+
return p === void 0 ? [] : [p];
|
|
1803
|
+
});
|
|
1431
1804
|
let rootsDeclined = 0;
|
|
1432
1805
|
rootNames.forEach((rootPath, i) => {
|
|
1433
1806
|
const meta = manifest.rootMeta?.[i];
|
|
@@ -1440,35 +1813,54 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1440
1813
|
roots.set(rootPath, {
|
|
1441
1814
|
path: rootPath,
|
|
1442
1815
|
cacheable: meta.cacheable,
|
|
1443
|
-
deps: meta.deps
|
|
1444
|
-
const p = depPaths[d];
|
|
1445
|
-
return p === void 0 ? [] : [p];
|
|
1446
|
-
}),
|
|
1816
|
+
deps: pathsOf(meta.deps),
|
|
1447
1817
|
claims: meta.claims,
|
|
1448
1818
|
meta: meta.meta,
|
|
1449
|
-
packs: meta.packs
|
|
1819
|
+
packs: meta.packs,
|
|
1820
|
+
...meta.imports === void 0 ? {} : { imports: pathsOf(meta.imports) }
|
|
1450
1821
|
});
|
|
1451
1822
|
});
|
|
1823
|
+
const unchanged = (filePath, deps) => current.has(filePath) && !changed.has(filePath) && !deps.some((d) => changed.has(d) || removed.has(d));
|
|
1452
1824
|
const validRoots = /* @__PURE__ */ new Set();
|
|
1453
1825
|
for (const [rootPath, record] of roots) {
|
|
1454
|
-
if (
|
|
1455
|
-
|
|
1826
|
+
if (record.cacheable && unchanged(rootPath, record.deps)) {
|
|
1827
|
+
validRoots.add(rootPath);
|
|
1456
1828
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1829
|
+
}
|
|
1830
|
+
const units = (manifest.units ?? []).flatMap((stored2) => {
|
|
1831
|
+
const file = depPaths[stored2.file];
|
|
1832
|
+
return file === void 0 ? [] : [
|
|
1833
|
+
{
|
|
1834
|
+
key: stored2.key,
|
|
1835
|
+
file,
|
|
1836
|
+
deps: pathsOf(stored2.deps),
|
|
1837
|
+
data: stored2.data
|
|
1838
|
+
}
|
|
1839
|
+
];
|
|
1840
|
+
});
|
|
1841
|
+
const validUnits = /* @__PURE__ */ new Map();
|
|
1842
|
+
for (const unit of units) {
|
|
1843
|
+
if (unchanged(unit.file, unit.deps)) {
|
|
1844
|
+
validUnits.set(unit.key, unit);
|
|
1459
1845
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1846
|
+
}
|
|
1847
|
+
const resolvedImports = /* @__PURE__ */ new Map();
|
|
1848
|
+
if (added.size === 0 && removed.size === 0) {
|
|
1849
|
+
for (const [rootPath, record] of roots) {
|
|
1850
|
+
if (record.imports !== void 0 && !changed.has(rootPath)) {
|
|
1851
|
+
resolvedImports.set(rootPath, record.imports);
|
|
1852
|
+
}
|
|
1463
1853
|
}
|
|
1464
1854
|
}
|
|
1465
1855
|
const owners = manifest.owners ?? [];
|
|
1466
1856
|
return {
|
|
1467
1857
|
changed,
|
|
1468
1858
|
removed,
|
|
1859
|
+
resolvedImports,
|
|
1469
1860
|
roots,
|
|
1470
1861
|
validRoots,
|
|
1471
1862
|
rootsDeclined,
|
|
1863
|
+
validUnits,
|
|
1472
1864
|
reuse(valid) {
|
|
1473
1865
|
const summaries = [];
|
|
1474
1866
|
const reusedOwners = [];
|
|
@@ -1495,7 +1887,8 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1495
1887
|
const p = rootNames[o];
|
|
1496
1888
|
return p === void 0 ? [] : [p];
|
|
1497
1889
|
})
|
|
1498
|
-
)
|
|
1890
|
+
),
|
|
1891
|
+
units
|
|
1499
1892
|
};
|
|
1500
1893
|
}
|
|
1501
1894
|
};
|
|
@@ -1520,7 +1913,8 @@ function encodeAttribution(attribution) {
|
|
|
1520
1913
|
deps: r.deps.map(depIdOf),
|
|
1521
1914
|
claims: r.claims,
|
|
1522
1915
|
meta: r.meta,
|
|
1523
|
-
packs: r.packs
|
|
1916
|
+
packs: r.packs,
|
|
1917
|
+
...r.imports === void 0 ? {} : { imports: r.imports.map(depIdOf) }
|
|
1524
1918
|
}));
|
|
1525
1919
|
const owners = attribution.owners.map(
|
|
1526
1920
|
(ownerPaths) => ownerPaths.flatMap((p) => {
|
|
@@ -1528,32 +1922,23 @@ function encodeAttribution(attribution) {
|
|
|
1528
1922
|
return i === void 0 ? [] : [i];
|
|
1529
1923
|
})
|
|
1530
1924
|
);
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
);
|
|
1545
|
-
}
|
|
1546
|
-
async function hashFile(filePath) {
|
|
1547
|
-
try {
|
|
1548
|
-
const content = await import_promises.default.readFile(filePath);
|
|
1549
|
-
return (0, import_node_crypto2.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
1550
|
-
} catch {
|
|
1551
|
-
return null;
|
|
1552
|
-
}
|
|
1925
|
+
const units = attribution.units?.map((unit) => ({
|
|
1926
|
+
key: unit.key,
|
|
1927
|
+
file: depIdOf(unit.file),
|
|
1928
|
+
deps: unit.deps.map(depIdOf),
|
|
1929
|
+
data: unit.data
|
|
1930
|
+
}));
|
|
1931
|
+
return {
|
|
1932
|
+
roots,
|
|
1933
|
+
rootMeta,
|
|
1934
|
+
depPaths,
|
|
1935
|
+
owners,
|
|
1936
|
+
...units === void 0 ? {} : { units }
|
|
1937
|
+
};
|
|
1553
1938
|
}
|
|
1554
1939
|
async function describeAbsentEntry(cacheDir) {
|
|
1555
1940
|
try {
|
|
1556
|
-
const entries = await
|
|
1941
|
+
const entries = await import_promises2.default.readdir(cacheDir, { withFileTypes: true });
|
|
1557
1942
|
return entries.some((e) => e.isDirectory() && isEntryDir(e.name)) ? "key-changed" : "no-manifest";
|
|
1558
1943
|
} catch {
|
|
1559
1944
|
return "no-manifest";
|
|
@@ -1565,8 +1950,8 @@ function entryDirFor(cacheDir, input) {
|
|
|
1565
1950
|
input.adapterPacksDigest,
|
|
1566
1951
|
input.configPath ?? ""
|
|
1567
1952
|
].join(" ");
|
|
1568
|
-
const name = (0,
|
|
1569
|
-
return
|
|
1953
|
+
const name = (0, import_node_crypto3.createHash)("sha256").update(key).digest("hex").slice(0, 16);
|
|
1954
|
+
return import_node_path5.default.join(cacheDir, `${ENTRY_PREFIX}${name}`);
|
|
1570
1955
|
}
|
|
1571
1956
|
function isEntryDir(name) {
|
|
1572
1957
|
return ENTRY_DIR_NAME.test(name);
|
|
@@ -1574,24 +1959,24 @@ function isEntryDir(name) {
|
|
|
1574
1959
|
async function markUsed(entryDir) {
|
|
1575
1960
|
const now = /* @__PURE__ */ new Date();
|
|
1576
1961
|
try {
|
|
1577
|
-
await
|
|
1962
|
+
await import_promises2.default.utimes(entryDir, now, now);
|
|
1578
1963
|
} catch {
|
|
1579
1964
|
}
|
|
1580
1965
|
}
|
|
1581
1966
|
async function evictOldEntries(cacheDir, keepDir) {
|
|
1582
1967
|
try {
|
|
1583
|
-
await
|
|
1584
|
-
const entries = await
|
|
1968
|
+
await import_promises2.default.rm(import_node_path5.default.join(cacheDir, "manifest.json"), { force: true });
|
|
1969
|
+
const entries = await import_promises2.default.readdir(cacheDir, { withFileTypes: true });
|
|
1585
1970
|
const dirs = await Promise.all(
|
|
1586
1971
|
entries.filter((e) => e.isDirectory() && isEntryDir(e.name)).map(async (e) => {
|
|
1587
|
-
const dir =
|
|
1588
|
-
const stat = await
|
|
1972
|
+
const dir = import_node_path5.default.join(cacheDir, e.name);
|
|
1973
|
+
const stat = await import_promises2.default.stat(dir);
|
|
1589
1974
|
return { dir, mtimeMs: stat.mtimeMs };
|
|
1590
1975
|
})
|
|
1591
1976
|
);
|
|
1592
1977
|
const doomed = dirs.filter((d) => d.dir !== keepDir).sort((a, b) => b.mtimeMs - a.mtimeMs).slice(MAX_ENTRIES - 1);
|
|
1593
1978
|
await Promise.all(
|
|
1594
|
-
doomed.map((d) =>
|
|
1979
|
+
doomed.map((d) => import_promises2.default.rm(d.dir, { recursive: true, force: true }))
|
|
1595
1980
|
);
|
|
1596
1981
|
} catch {
|
|
1597
1982
|
}
|
|
@@ -1602,54 +1987,44 @@ function missDiag(reason) {
|
|
|
1602
1987
|
diagnostic: { kind: "miss", missReason: reason }
|
|
1603
1988
|
};
|
|
1604
1989
|
}
|
|
1605
|
-
|
|
1990
|
+
var ManifestReads = class {
|
|
1991
|
+
last = null;
|
|
1992
|
+
async readAtRunStart(manifestPath) {
|
|
1993
|
+
const stamp = await manifestStamp(manifestPath);
|
|
1994
|
+
const manifest = await readManifest(manifestPath);
|
|
1995
|
+
this.last = { path: manifestPath, stamp, manifest };
|
|
1996
|
+
return manifest;
|
|
1997
|
+
}
|
|
1998
|
+
async readAgain(manifestPath) {
|
|
1999
|
+
const last = this.last;
|
|
2000
|
+
if (last !== null && last.path === manifestPath && last.stamp !== null && last.stamp === await manifestStamp(manifestPath)) {
|
|
2001
|
+
return last.manifest;
|
|
2002
|
+
}
|
|
2003
|
+
return await this.readAtRunStart(manifestPath);
|
|
2004
|
+
}
|
|
2005
|
+
forget() {
|
|
2006
|
+
this.last = null;
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
async function manifestStamp(manifestPath) {
|
|
1606
2010
|
try {
|
|
1607
|
-
const
|
|
1608
|
-
return
|
|
2011
|
+
const stat = await import_promises2.default.stat(manifestPath);
|
|
2012
|
+
return `${stat.ino}:${stat.mtimeMs}:${stat.size}`;
|
|
1609
2013
|
} catch {
|
|
1610
2014
|
return null;
|
|
1611
2015
|
}
|
|
1612
2016
|
}
|
|
1613
|
-
async function
|
|
1614
|
-
if (configPath === void 0) {
|
|
1615
|
-
return null;
|
|
1616
|
-
}
|
|
2017
|
+
async function readManifest(manifestPath) {
|
|
1617
2018
|
try {
|
|
1618
|
-
const
|
|
1619
|
-
return
|
|
2019
|
+
const raw = await import_promises2.default.readFile(manifestPath, "utf-8");
|
|
2020
|
+
return JSON.parse(raw);
|
|
1620
2021
|
} catch {
|
|
1621
2022
|
return null;
|
|
1622
2023
|
}
|
|
1623
2024
|
}
|
|
1624
|
-
async function resolveFileStamps(input) {
|
|
1625
|
-
const stamped = await Promise.all(
|
|
1626
|
-
input.files.map(async (p) => {
|
|
1627
|
-
try {
|
|
1628
|
-
const stat = await import_promises.default.stat(p);
|
|
1629
|
-
return { path: p, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
1630
|
-
} catch {
|
|
1631
|
-
return { path: p, mtimeMs: -1, size: -1 };
|
|
1632
|
-
}
|
|
1633
|
-
})
|
|
1634
|
-
);
|
|
1635
|
-
stamped.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
1636
|
-
return stamped;
|
|
1637
|
-
}
|
|
1638
|
-
function fileStampsEqual(a, b) {
|
|
1639
|
-
return a.length === b.length && a.every((s, i) => fileStampEquals(s, b[i]));
|
|
1640
|
-
}
|
|
1641
|
-
function fileStampEquals(a, b) {
|
|
1642
|
-
if (a === null && b === null) {
|
|
1643
|
-
return true;
|
|
1644
|
-
}
|
|
1645
|
-
if (a === null || b === null) {
|
|
1646
|
-
return false;
|
|
1647
|
-
}
|
|
1648
|
-
return a.path === b.path && a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
1649
|
-
}
|
|
1650
2025
|
|
|
1651
2026
|
// src/extractionReport.ts
|
|
1652
|
-
var
|
|
2027
|
+
var import_behavioral_ir5 = require("@suss/behavioral-ir");
|
|
1653
2028
|
var emptyTally = () => ({
|
|
1654
2029
|
candidateFiles: 0,
|
|
1655
2030
|
unitsDiscovered: 0,
|
|
@@ -1699,7 +2074,7 @@ function summaryCountsByPack(summaries) {
|
|
|
1699
2074
|
}
|
|
1700
2075
|
const entry = counts.get(recognition) ?? emptyCounts();
|
|
1701
2076
|
entry.bound += 1;
|
|
1702
|
-
if (
|
|
2077
|
+
if (import_behavioral_ir5.BOUNDARY_ROLE[summary.kind] === "provider") {
|
|
1703
2078
|
entry.providers += 1;
|
|
1704
2079
|
}
|
|
1705
2080
|
if (summary.transitions.length > 0) {
|
|
@@ -1755,6 +2130,38 @@ function firstEmptyUngatedStage(packs, filesWalked) {
|
|
|
1755
2130
|
return "assembly";
|
|
1756
2131
|
}
|
|
1757
2132
|
|
|
2133
|
+
// src/keptParses.ts
|
|
2134
|
+
var KeptParses = class {
|
|
2135
|
+
constructor(release = () => {
|
|
2136
|
+
}) {
|
|
2137
|
+
this.release = release;
|
|
2138
|
+
}
|
|
2139
|
+
release;
|
|
2140
|
+
byFile = /* @__PURE__ */ new Map();
|
|
2141
|
+
async parse(file, source, make) {
|
|
2142
|
+
const kept = this.byFile.get(file);
|
|
2143
|
+
if (kept !== void 0 && kept.source === source) {
|
|
2144
|
+
return kept.value;
|
|
2145
|
+
}
|
|
2146
|
+
const value = await make(source);
|
|
2147
|
+
if (kept !== void 0) {
|
|
2148
|
+
this.release(kept.value);
|
|
2149
|
+
}
|
|
2150
|
+
this.byFile.set(file, { source, value });
|
|
2151
|
+
return value;
|
|
2152
|
+
}
|
|
2153
|
+
/** Lets go of every file not in this run. */
|
|
2154
|
+
keepOnly(files) {
|
|
2155
|
+
const wanted = new Set(files);
|
|
2156
|
+
for (const [file, kept] of this.byFile) {
|
|
2157
|
+
if (!wanted.has(file)) {
|
|
2158
|
+
this.release(kept.value);
|
|
2159
|
+
this.byFile.delete(file);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
|
|
1758
2165
|
// src/packHealth.ts
|
|
1759
2166
|
function stagesOf(funnel) {
|
|
1760
2167
|
const stages = [];
|
|
@@ -1801,8 +2208,8 @@ function funnelDrops(packs) {
|
|
|
1801
2208
|
function recognizersWithNoUnits(packs) {
|
|
1802
2209
|
return packs.filter(
|
|
1803
2210
|
(funnel) => funnel.recognizes && !funnel.discovers && funnel.gates.length > 0 && funnel.unresolvedGates.length === 0 && funnel.candidateFiles > 0 && funnel.unitsInGatedFiles === 0 && // The closure walks a recognizer-only pack's gated exports as
|
|
1804
|
-
// roots, so effects recognized there mean the run worked and
|
|
1805
|
-
// the
|
|
2211
|
+
// roots, so effects recognized there mean the run worked and only
|
|
2212
|
+
// the framework pack's attribution is missing.
|
|
1806
2213
|
funnel.effectsRecognized === 0
|
|
1807
2214
|
).map((funnel) => ({
|
|
1808
2215
|
label: funnel.pack,
|
|
@@ -2044,7 +2451,7 @@ function makeTransitionId(functionName, branch) {
|
|
|
2044
2451
|
const { terminal } = branch;
|
|
2045
2452
|
const statusKey = terminal.statusCode === null ? "none" : terminal.statusCode.type === "literal" ? String(terminal.statusCode.value) : `dyn:${terminal.statusCode.sourceText}`;
|
|
2046
2453
|
const conditionSig = branch.conditions.map((c) => `${c.polarity}:${c.sourceText}`).join(";");
|
|
2047
|
-
const conditionHash = (0,
|
|
2454
|
+
const conditionHash = (0, import_node_crypto4.createHash)("sha1").update(conditionSig).digest("hex").slice(0, 7);
|
|
2048
2455
|
return `${functionName}:${terminal.kind}:${statusKey}:${conditionHash}`;
|
|
2049
2456
|
}
|
|
2050
2457
|
function collapseReading(table, reading) {
|
|
@@ -2112,7 +2519,40 @@ function effectsOfBranch(branch) {
|
|
|
2112
2519
|
...branch.effects.map(effectToIR),
|
|
2113
2520
|
...branch.extraEffects ?? []
|
|
2114
2521
|
];
|
|
2115
|
-
return (0,
|
|
2522
|
+
return (0, import_behavioral_ir6.foldRepeatedEffects)(effects.map(withNormalizedCallee));
|
|
2523
|
+
}
|
|
2524
|
+
function provenanceOf(raw, effects) {
|
|
2525
|
+
if (raw.length === 0) {
|
|
2526
|
+
return [];
|
|
2527
|
+
}
|
|
2528
|
+
const positionOf = new Map(effects.map((one, at) => [(0, import_behavioral_ir6.effectKey)(one), at]));
|
|
2529
|
+
const bySlot = /* @__PURE__ */ new Map();
|
|
2530
|
+
const said = /* @__PURE__ */ new Map();
|
|
2531
|
+
for (const one of raw) {
|
|
2532
|
+
const effect = positionOf.get((0, import_behavioral_ir6.effectKey)(withNormalizedCallee(one.effect)));
|
|
2533
|
+
if (effect === void 0) {
|
|
2534
|
+
continue;
|
|
2535
|
+
}
|
|
2536
|
+
const slotKey = `${effect}\0${one.slot}\0${one.name}`;
|
|
2537
|
+
let entry = bySlot.get(slotKey);
|
|
2538
|
+
let seen = said.get(slotKey);
|
|
2539
|
+
if (entry === void 0 || seen === void 0) {
|
|
2540
|
+
entry = { at: { slot: one.slot, effect, name: one.name }, from: [] };
|
|
2541
|
+
seen = /* @__PURE__ */ new Set();
|
|
2542
|
+
bySlot.set(slotKey, entry);
|
|
2543
|
+
said.set(slotKey, seen);
|
|
2544
|
+
}
|
|
2545
|
+
for (const source of one.from) {
|
|
2546
|
+
const spelled = JSON.stringify(source);
|
|
2547
|
+
if (!seen.has(spelled)) {
|
|
2548
|
+
seen.add(spelled);
|
|
2549
|
+
entry.from.push(source);
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
return [...bySlot.values()].sort(
|
|
2554
|
+
(a, b) => a.at.effect - b.at.effect || a.at.slot.localeCompare(b.at.slot) || a.at.name.localeCompare(b.at.name)
|
|
2555
|
+
);
|
|
2116
2556
|
}
|
|
2117
2557
|
function withNormalizedCallee(effect) {
|
|
2118
2558
|
if (effect.type !== "invocation" && effect.type !== "interaction") {
|
|
@@ -2121,7 +2561,7 @@ function withNormalizedCallee(effect) {
|
|
|
2121
2561
|
if (effect.callee === void 0) {
|
|
2122
2562
|
return effect;
|
|
2123
2563
|
}
|
|
2124
|
-
return { ...effect, callee: (0,
|
|
2564
|
+
return { ...effect, callee: (0, import_behavioral_ir6.normalizeCalleeText)(effect.callee) };
|
|
2125
2565
|
}
|
|
2126
2566
|
function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
2127
2567
|
const transitions = raw.branches.map((rawBranch) => {
|
|
@@ -2129,17 +2569,22 @@ function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
|
2129
2569
|
const conditions = branch.conditions.map(
|
|
2130
2570
|
rawConditionToPredicate
|
|
2131
2571
|
);
|
|
2572
|
+
const effects = effectsOfBranch(branch);
|
|
2132
2573
|
const transition = {
|
|
2133
2574
|
id: makeTransitionId(raw.identity.name, branch),
|
|
2134
2575
|
conditions,
|
|
2135
2576
|
output: terminalToOutput(branch.terminal),
|
|
2136
|
-
effects
|
|
2577
|
+
effects,
|
|
2137
2578
|
location: branch.location,
|
|
2138
2579
|
isDefault: branch.isDefault
|
|
2139
2580
|
};
|
|
2140
2581
|
if (branch.expectedInput != null) {
|
|
2141
2582
|
transition.expectedInput = branch.expectedInput;
|
|
2142
2583
|
}
|
|
2584
|
+
const provenance = provenanceOf(branch.provenance ?? [], effects);
|
|
2585
|
+
if (provenance.length > 0) {
|
|
2586
|
+
transition.provenance = provenance;
|
|
2587
|
+
}
|
|
2143
2588
|
return transition;
|
|
2144
2589
|
});
|
|
2145
2590
|
const gaps = detectGaps(raw, transitions, options);
|
|
@@ -2181,25 +2626,28 @@ function buildMetadata(raw) {
|
|
|
2181
2626
|
let metadata = {};
|
|
2182
2627
|
const http = buildHttpMetadataValue(raw);
|
|
2183
2628
|
if (http !== null) {
|
|
2184
|
-
metadata = (0,
|
|
2629
|
+
metadata = (0, import_behavioral_ir6.withHttpMetadata)(metadata, http);
|
|
2185
2630
|
}
|
|
2186
2631
|
const graphql = buildGraphqlMetadataValue(raw);
|
|
2187
2632
|
if (graphql !== null) {
|
|
2188
|
-
metadata = (0,
|
|
2633
|
+
metadata = (0, import_behavioral_ir6.withGraphqlMetadata)(metadata, graphql);
|
|
2189
2634
|
}
|
|
2190
2635
|
if (raw.sourceDocumentLabel !== void 0) {
|
|
2191
|
-
metadata = (0,
|
|
2636
|
+
metadata = (0, import_behavioral_ir6.withSourceDocumentMetadata)(metadata, {
|
|
2192
2637
|
label: raw.sourceDocumentLabel
|
|
2193
2638
|
});
|
|
2194
2639
|
}
|
|
2195
2640
|
if (raw.mount !== void 0) {
|
|
2196
|
-
metadata = (0,
|
|
2641
|
+
metadata = (0, import_behavioral_ir6.withMountMetadata)(metadata, raw.mount);
|
|
2197
2642
|
}
|
|
2198
2643
|
if (raw.wrappers !== void 0 && raw.wrappers.length > 0) {
|
|
2199
|
-
metadata = (0,
|
|
2644
|
+
metadata = (0, import_behavioral_ir6.withWrapperMetadata)(metadata, { applied: raw.wrappers });
|
|
2200
2645
|
}
|
|
2201
2646
|
if (raw.requestSpelling !== void 0) {
|
|
2202
|
-
metadata = (0,
|
|
2647
|
+
metadata = (0, import_behavioral_ir6.withRequestSpellingMetadata)(metadata, raw.requestSpelling);
|
|
2648
|
+
}
|
|
2649
|
+
if (raw.test !== void 0) {
|
|
2650
|
+
metadata = (0, import_behavioral_ir6.withTestMetadata)(metadata, raw.test);
|
|
2203
2651
|
}
|
|
2204
2652
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
2205
2653
|
}
|
|
@@ -2252,7 +2700,7 @@ function answersWithHttpResponses(raw) {
|
|
|
2252
2700
|
if (raw.boundaryBinding === null || raw.boundaryBinding === void 0) {
|
|
2253
2701
|
return true;
|
|
2254
2702
|
}
|
|
2255
|
-
return (0,
|
|
2703
|
+
return (0, import_behavioral_ir6.exchangesHttpResponses)(raw.boundaryBinding);
|
|
2256
2704
|
}
|
|
2257
2705
|
function detectGaps(raw, transitions, options) {
|
|
2258
2706
|
if (options.gapHandling === "silent") {
|
|
@@ -2344,18 +2792,27 @@ function bodyToShape(body) {
|
|
|
2344
2792
|
}
|
|
2345
2793
|
return null;
|
|
2346
2794
|
}
|
|
2795
|
+
function statusValueRef(code) {
|
|
2796
|
+
if (code === null) {
|
|
2797
|
+
return null;
|
|
2798
|
+
}
|
|
2799
|
+
return code.type === "literal" ? { type: "literal", value: code.value } : { type: "unresolved", sourceText: code.sourceText };
|
|
2800
|
+
}
|
|
2347
2801
|
var terminalConverters = {
|
|
2348
2802
|
response: (t) => {
|
|
2349
|
-
const statusCode = t.statusCode ? t.statusCode.type === "literal" ? { type: "literal", value: t.statusCode.value } : { type: "unresolved", sourceText: t.statusCode.sourceText } : null;
|
|
2350
2803
|
const body = bodyToShape(t.body);
|
|
2351
|
-
return {
|
|
2804
|
+
return {
|
|
2805
|
+
type: "response",
|
|
2806
|
+
statusCode: statusValueRef(t.statusCode),
|
|
2807
|
+
body,
|
|
2808
|
+
headers: {}
|
|
2809
|
+
};
|
|
2352
2810
|
},
|
|
2353
2811
|
throw: (t) => {
|
|
2354
2812
|
if (t.statusCode && t.producesResponse === true) {
|
|
2355
|
-
const statusCode = t.statusCode.type === "literal" ? { type: "literal", value: t.statusCode.value } : { type: "unresolved", sourceText: t.statusCode.sourceText };
|
|
2356
2813
|
return {
|
|
2357
2814
|
type: "response",
|
|
2358
|
-
statusCode,
|
|
2815
|
+
statusCode: statusValueRef(t.statusCode),
|
|
2359
2816
|
body: bodyToShape(t.body),
|
|
2360
2817
|
headers: {}
|
|
2361
2818
|
};
|
|
@@ -2383,7 +2840,8 @@ var terminalConverters = {
|
|
|
2383
2840
|
type: "return",
|
|
2384
2841
|
value: bodyToShape(t.body)
|
|
2385
2842
|
}),
|
|
2386
|
-
void: (_t) => ({ type: "void" })
|
|
2843
|
+
void: (_t) => ({ type: "void" }),
|
|
2844
|
+
exit: (t) => ({ type: "exit", code: statusValueRef(t.statusCode) })
|
|
2387
2845
|
};
|
|
2388
2846
|
function terminalToOutput(terminal) {
|
|
2389
2847
|
return terminalConverters[terminal.kind](terminal);
|
|
@@ -2426,15 +2884,19 @@ function paramToInput(param) {
|
|
|
2426
2884
|
name: param.name,
|
|
2427
2885
|
position: param.position,
|
|
2428
2886
|
role: param.role,
|
|
2887
|
+
...param.field === void 0 ? {} : { field: param.field },
|
|
2429
2888
|
shape: param.typeText ? { type: "ref", name: param.typeText } : null
|
|
2430
2889
|
};
|
|
2431
2890
|
}
|
|
2432
2891
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2433
2892
|
0 && (module.exports = {
|
|
2893
|
+
EnclosingNodes,
|
|
2434
2894
|
IdMap,
|
|
2435
2895
|
IdSet,
|
|
2896
|
+
KeptParses,
|
|
2436
2897
|
MAX_ENTRIES,
|
|
2437
2898
|
MAX_PATHS,
|
|
2899
|
+
MODULE_SURFACE_RECOGNITION,
|
|
2438
2900
|
PathBudgetExceeded,
|
|
2439
2901
|
SKIP_CHILDREN,
|
|
2440
2902
|
UnmodeledFlow,
|
|
@@ -2459,13 +2921,18 @@ function paramToInput(param) {
|
|
|
2459
2921
|
enumerateOrDegrade,
|
|
2460
2922
|
enumerateStructuredPaths,
|
|
2461
2923
|
evaluatePackHealth,
|
|
2924
|
+
extractionConfigStamp,
|
|
2462
2925
|
firstWrittenReading,
|
|
2463
2926
|
formatPackHealth,
|
|
2464
2927
|
guardsHoldOn,
|
|
2465
2928
|
httpRouteDiscovery,
|
|
2929
|
+
isListedTestFile,
|
|
2466
2930
|
makeTransitionId,
|
|
2467
2931
|
mapReading,
|
|
2932
|
+
markReturnsAsExitCode,
|
|
2933
|
+
matchesTestFileName,
|
|
2468
2934
|
moduleInitStructure,
|
|
2935
|
+
moduleOfFile,
|
|
2469
2936
|
noopTimer,
|
|
2470
2937
|
packGradients,
|
|
2471
2938
|
paramToInput,
|
|
@@ -2477,8 +2944,12 @@ function paramToInput(param) {
|
|
|
2477
2944
|
runDigest,
|
|
2478
2945
|
runsBefore,
|
|
2479
2946
|
scopeOption,
|
|
2947
|
+
settleModules,
|
|
2480
2948
|
sharedGatingConditions,
|
|
2949
|
+
sourceRefsOf,
|
|
2950
|
+
stampMayMissAWrite,
|
|
2481
2951
|
stampModuleImports,
|
|
2952
|
+
stampModules,
|
|
2482
2953
|
storageSystemOption,
|
|
2483
2954
|
summaryCountsByPack,
|
|
2484
2955
|
tallyUnit,
|