@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.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { createHash as
|
|
2
|
+
import { createHash as createHash4 } from "crypto";
|
|
3
3
|
import {
|
|
4
|
+
effectKey,
|
|
4
5
|
exchangesHttpResponses as exchangesHttpResponses2,
|
|
5
6
|
foldRepeatedEffects,
|
|
6
7
|
normalizeCalleeText,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
withMountMetadata,
|
|
10
11
|
withRequestSpellingMetadata,
|
|
11
12
|
withSourceDocumentMetadata,
|
|
13
|
+
withTestMetadata,
|
|
12
14
|
withWrapperMetadata as withWrapperMetadata2
|
|
13
15
|
} from "@suss/behavioral-ir";
|
|
14
16
|
|
|
@@ -281,6 +283,56 @@ function withDistinctIds(transitions) {
|
|
|
281
283
|
});
|
|
282
284
|
}
|
|
283
285
|
|
|
286
|
+
// src/declaredModules.ts
|
|
287
|
+
import fs from "fs";
|
|
288
|
+
import path from "path";
|
|
289
|
+
var MODULE_SURFACE_RECOGNITION = "modules";
|
|
290
|
+
function settleModules(modules, candidates) {
|
|
291
|
+
return (modules ?? []).map((module) => ({
|
|
292
|
+
...module,
|
|
293
|
+
public: module.public ?? candidates.map(
|
|
294
|
+
(one) => path.join(module.root, one.replace("{name}", module.name))
|
|
295
|
+
).filter((file) => fs.existsSync(file))
|
|
296
|
+
}));
|
|
297
|
+
}
|
|
298
|
+
function isInside(file, root) {
|
|
299
|
+
const relative = path.relative(root, file);
|
|
300
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
301
|
+
}
|
|
302
|
+
function moduleOfFile(modules, file) {
|
|
303
|
+
const byPublicFile = modules.find((module) => module.public.includes(file));
|
|
304
|
+
if (byPublicFile !== void 0) {
|
|
305
|
+
return byPublicFile;
|
|
306
|
+
}
|
|
307
|
+
let deepest;
|
|
308
|
+
for (const module of modules) {
|
|
309
|
+
if (isInside(file, module.root) && (deepest === void 0 || module.root.length > deepest.root.length)) {
|
|
310
|
+
deepest = module;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return deepest;
|
|
314
|
+
}
|
|
315
|
+
function stampModules(summaries, modules, root) {
|
|
316
|
+
if (modules.length === 0) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
for (const summary of summaries) {
|
|
320
|
+
const file = path.resolve(root ?? "", summary.location.file);
|
|
321
|
+
const module = moduleOfFile(modules, file);
|
|
322
|
+
if (module !== void 0) {
|
|
323
|
+
summary.location.module = module.name;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function modulesStamp(modules) {
|
|
328
|
+
if (modules === void 0 || modules.length === 0) {
|
|
329
|
+
return void 0;
|
|
330
|
+
}
|
|
331
|
+
return JSON.stringify(
|
|
332
|
+
modules.map((module) => [module.name, module.root, [...module.public]])
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
284
336
|
// src/effectGuards.ts
|
|
285
337
|
var keyOf = (condition) => `${condition.polarity}:${condition.sourceText}`;
|
|
286
338
|
var opposite = (condition) => `${condition.polarity === "positive" ? "negative" : "positive"}:${condition.sourceText}`;
|
|
@@ -297,6 +349,41 @@ function runsBefore(effectLine, terminalEndLine) {
|
|
|
297
349
|
return effectLine <= terminalEndLine;
|
|
298
350
|
}
|
|
299
351
|
|
|
352
|
+
// src/exitCode.ts
|
|
353
|
+
import path2 from "path";
|
|
354
|
+
import { declarationKey } from "@suss/behavioral-ir";
|
|
355
|
+
function markReturnsAsExitCode(summaries, returnsTheCode, workspaceRoot) {
|
|
356
|
+
for (const summary of summaries) {
|
|
357
|
+
const span = summary.location.span;
|
|
358
|
+
const file = workspaceRoot === void 0 ? summary.location.file : path2.resolve(workspaceRoot, summary.location.file);
|
|
359
|
+
markExitCodeFrom(
|
|
360
|
+
summary,
|
|
361
|
+
span !== void 0 && returnsTheCode.has(declarationKey(file, span))
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function markExitCodeFrom(summary, marked) {
|
|
366
|
+
const process2 = summary.metadata?.process;
|
|
367
|
+
if (marked) {
|
|
368
|
+
summary.metadata = {
|
|
369
|
+
...summary.metadata ?? {},
|
|
370
|
+
process: { ...process2 ?? {}, exitCodeFrom: "return" }
|
|
371
|
+
};
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (process2 === void 0 || !("exitCodeFrom" in process2)) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const { exitCodeFrom: _dropped, ...rest } = process2;
|
|
378
|
+
const { process: _process, ...others } = summary.metadata ?? {};
|
|
379
|
+
const left = Object.keys(rest).length === 0 ? others : { ...others, process: rest };
|
|
380
|
+
if (Object.keys(left).length === 0) {
|
|
381
|
+
Reflect.deleteProperty(summary, "metadata");
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
summary.metadata = left;
|
|
385
|
+
}
|
|
386
|
+
|
|
300
387
|
// src/moduleImports.ts
|
|
301
388
|
function stampModuleImports(summaries, importsOf) {
|
|
302
389
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -373,8 +460,8 @@ function httpRouteDiscovery(opts) {
|
|
|
373
460
|
registrationChain: [...opts.methods]
|
|
374
461
|
},
|
|
375
462
|
bindingExtraction: {
|
|
376
|
-
// `.all` registers every method, so it records "*", which
|
|
377
|
-
//
|
|
463
|
+
// `.all` registers every method, so it records "*", which pairs with
|
|
464
|
+
// any method.
|
|
378
465
|
method: {
|
|
379
466
|
type: "fromRegistration",
|
|
380
467
|
position: "methodName",
|
|
@@ -390,10 +477,9 @@ function httpRouteDiscovery(opts) {
|
|
|
390
477
|
}
|
|
391
478
|
return [
|
|
392
479
|
...calls,
|
|
393
|
-
// Routes registered in a loop over an array of specs,
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
// never touches this library's routable is left alone.
|
|
480
|
+
// Routes registered in a loop over an array of specs, which the calls
|
|
481
|
+
// above cannot see. The receiver must come from the same import, so a
|
|
482
|
+
// loop that never touches this library's routable is left alone.
|
|
397
483
|
{
|
|
398
484
|
kind,
|
|
399
485
|
match: {
|
|
@@ -540,7 +626,7 @@ var configuredCallOption = z.object({
|
|
|
540
626
|
receiver: z.string(),
|
|
541
627
|
/** Method that performs the send. */
|
|
542
628
|
method: z.string(),
|
|
543
|
-
/**
|
|
629
|
+
/** Index of the argument that is the subject. */
|
|
544
630
|
subjectArg: z.number(),
|
|
545
631
|
/**
|
|
546
632
|
* Which argument the message body is. Left out when the method has no
|
|
@@ -599,8 +685,8 @@ var catchEntryCond = () => fixedCond(
|
|
|
599
685
|
"positive",
|
|
600
686
|
"catchBlock"
|
|
601
687
|
);
|
|
602
|
-
function classify(
|
|
603
|
-
return
|
|
688
|
+
function classify(path6, home, isAncestorOrSelf) {
|
|
689
|
+
return path6.map((cond) => {
|
|
604
690
|
if (cond.branchStmt === null) {
|
|
605
691
|
return cond.info;
|
|
606
692
|
}
|
|
@@ -665,9 +751,9 @@ function chargeBudget(state) {
|
|
|
665
751
|
);
|
|
666
752
|
}
|
|
667
753
|
}
|
|
668
|
-
function recordTerminal(ctx, terminal, home,
|
|
754
|
+
function recordTerminal(ctx, terminal, home, path6) {
|
|
669
755
|
chargeBudget(ctx.state);
|
|
670
|
-
const info = classify(
|
|
756
|
+
const info = classify(path6, home, ctx.isAncestorOrSelf);
|
|
671
757
|
const existing = ctx.state.byTerminal.get(terminal) ?? [];
|
|
672
758
|
existing.push(info);
|
|
673
759
|
ctx.state.byTerminal.set(terminal, existing);
|
|
@@ -678,15 +764,15 @@ function containsTerminal(ctx, stmt) {
|
|
|
678
764
|
}
|
|
679
765
|
return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
|
|
680
766
|
}
|
|
681
|
-
function stepIf(stmt,
|
|
767
|
+
function stepIf(stmt, path6, ctx) {
|
|
682
768
|
const thenExit = exitKindOfList(stmt.thenBody);
|
|
683
769
|
const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
|
|
684
770
|
const thenPath = [
|
|
685
|
-
...
|
|
771
|
+
...path6,
|
|
686
772
|
branchCond(stmt, stmt.condition, "positive", elseExit)
|
|
687
773
|
];
|
|
688
774
|
const elsePath = [
|
|
689
|
-
...
|
|
775
|
+
...path6,
|
|
690
776
|
branchCond(
|
|
691
777
|
stmt,
|
|
692
778
|
stmt.condition,
|
|
@@ -703,7 +789,7 @@ function stepIf(stmt, path4, ctx) {
|
|
|
703
789
|
}
|
|
704
790
|
return out;
|
|
705
791
|
}
|
|
706
|
-
function stepSwitch(stmt,
|
|
792
|
+
function stepSwitch(stmt, path6, ctx) {
|
|
707
793
|
const out = [];
|
|
708
794
|
const negations = [];
|
|
709
795
|
let defaultRanBody = false;
|
|
@@ -713,7 +799,7 @@ function stepSwitch(stmt, path4, ctx) {
|
|
|
713
799
|
if (hasStrayBreak(group.body)) {
|
|
714
800
|
throw new UnmodeledFlow("non-trailing break in switch clause");
|
|
715
801
|
}
|
|
716
|
-
const groupPath = group.condition === null ? [...
|
|
802
|
+
const groupPath = group.condition === null ? [...path6, ...negations] : [...path6, fixedCond(group.condition, "positive", "explicit")];
|
|
717
803
|
const conts = enumerate(ctx, group.body, groupPath);
|
|
718
804
|
if (conts.length > 0) {
|
|
719
805
|
if (!group.hasTrailingBreak && !fallthroughSafe) {
|
|
@@ -730,24 +816,24 @@ function stepSwitch(stmt, path4, ctx) {
|
|
|
730
816
|
}
|
|
731
817
|
}
|
|
732
818
|
if (!defaultRanBody) {
|
|
733
|
-
out.push([...
|
|
819
|
+
out.push([...path6, ...negations]);
|
|
734
820
|
}
|
|
735
821
|
return out;
|
|
736
822
|
}
|
|
737
|
-
function stepLoop(stmt,
|
|
823
|
+
function stepLoop(stmt, path6, ctx) {
|
|
738
824
|
const bodyExit = exitKindOfList(stmt.body);
|
|
739
825
|
if (containsTerminal(ctx, stmt)) {
|
|
740
826
|
enumerate(ctx, stmt.body, [
|
|
741
|
-
...
|
|
827
|
+
...path6,
|
|
742
828
|
loopIterationCond(stmt.condition.sourceText)
|
|
743
829
|
]);
|
|
744
830
|
}
|
|
745
831
|
if (bodyExit !== null) {
|
|
746
|
-
return [[...
|
|
832
|
+
return [[...path6, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
|
|
747
833
|
}
|
|
748
|
-
return [
|
|
834
|
+
return [path6];
|
|
749
835
|
}
|
|
750
|
-
function stepTry(stmt,
|
|
836
|
+
function stepTry(stmt, path6, ctx) {
|
|
751
837
|
if (stmt.finallyBody !== null) {
|
|
752
838
|
const finallyHasTerminal = stmt.finallyBody.some(
|
|
753
839
|
(s) => containsTerminal(ctx, s)
|
|
@@ -757,22 +843,22 @@ function stepTry(stmt, path4, ctx) {
|
|
|
757
843
|
}
|
|
758
844
|
}
|
|
759
845
|
const out = [];
|
|
760
|
-
out.push(...enumerate(ctx, stmt.tryBody,
|
|
846
|
+
out.push(...enumerate(ctx, stmt.tryBody, path6));
|
|
761
847
|
if (stmt.catchBody !== null) {
|
|
762
|
-
const catchPath = [...
|
|
848
|
+
const catchPath = [...path6, catchEntryCond()];
|
|
763
849
|
out.push(...enumerate(ctx, stmt.catchBody, catchPath));
|
|
764
850
|
}
|
|
765
851
|
return out;
|
|
766
852
|
}
|
|
767
|
-
function stepExit(stmt,
|
|
853
|
+
function stepExit(stmt, path6, ctx) {
|
|
768
854
|
const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
|
|
769
855
|
if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
|
|
770
|
-
collector.push(
|
|
856
|
+
collector.push(path6);
|
|
771
857
|
}
|
|
772
858
|
return [];
|
|
773
859
|
}
|
|
774
|
-
function stepOpaque(_stmt,
|
|
775
|
-
return [
|
|
860
|
+
function stepOpaque(_stmt, path6, _ctx) {
|
|
861
|
+
return [path6];
|
|
776
862
|
}
|
|
777
863
|
var stepHandlers = {
|
|
778
864
|
if: stepIf,
|
|
@@ -782,20 +868,20 @@ var stepHandlers = {
|
|
|
782
868
|
exit: stepExit,
|
|
783
869
|
opaque: stepOpaque
|
|
784
870
|
};
|
|
785
|
-
function stepCallback(ctx, body,
|
|
871
|
+
function stepCallback(ctx, body, path6) {
|
|
786
872
|
const exits = [];
|
|
787
873
|
ctx.state.callbackExits.push(exits);
|
|
788
874
|
let fellThrough;
|
|
789
875
|
try {
|
|
790
|
-
fellThrough = enumerate(ctx, body,
|
|
876
|
+
fellThrough = enumerate(ctx, body, path6);
|
|
791
877
|
} finally {
|
|
792
878
|
ctx.state.callbackExits.pop();
|
|
793
879
|
}
|
|
794
880
|
const out = [...fellThrough, ...exits];
|
|
795
|
-
return out.length === 0 ? [
|
|
881
|
+
return out.length === 0 ? [path6] : out;
|
|
796
882
|
}
|
|
797
|
-
function stepStatement(ctx, stmt,
|
|
798
|
-
let paths = [
|
|
883
|
+
function stepStatement(ctx, stmt, path6) {
|
|
884
|
+
let paths = [path6];
|
|
799
885
|
for (const body of stmt.callbacks ?? []) {
|
|
800
886
|
paths = paths.flatMap((each) => stepCallback(ctx, body, each));
|
|
801
887
|
}
|
|
@@ -876,8 +962,8 @@ function enumerate(ctx, stmts, prefix) {
|
|
|
876
962
|
let frontiers = [[...prefix]];
|
|
877
963
|
for (const stmt of stmts) {
|
|
878
964
|
const nextFrontiers = [];
|
|
879
|
-
for (const
|
|
880
|
-
nextFrontiers.push(...stepStatement(ctx, stmt,
|
|
965
|
+
for (const path6 of mergeRejoined(frontiers)) {
|
|
966
|
+
nextFrontiers.push(...stepStatement(ctx, stmt, path6));
|
|
881
967
|
}
|
|
882
968
|
frontiers = nextFrontiers;
|
|
883
969
|
if (frontiers.length > MAX_PATHS) {
|
|
@@ -928,9 +1014,9 @@ function enumerateStructuredPaths(input) {
|
|
|
928
1014
|
isAncestorOrSelf
|
|
929
1015
|
};
|
|
930
1016
|
const continuations = withRejoined(enumerate(ctx, input.statements, []));
|
|
931
|
-
for (const
|
|
1017
|
+
for (const path6 of continuations) {
|
|
932
1018
|
chargeBudget(state);
|
|
933
|
-
state.fallthrough.push(classify(
|
|
1019
|
+
state.fallthrough.push(classify(path6, null, isAncestorOrSelf));
|
|
934
1020
|
}
|
|
935
1021
|
return { byTerminal: state.byTerminal, fallthrough: state.fallthrough };
|
|
936
1022
|
}
|
|
@@ -973,8 +1059,8 @@ function sharedGatingConditions(paths, readPredicate) {
|
|
|
973
1059
|
return [];
|
|
974
1060
|
}
|
|
975
1061
|
const shared = new Set(first.map(keyOf2));
|
|
976
|
-
for (const
|
|
977
|
-
const here = new Set(
|
|
1062
|
+
for (const path6 of rest) {
|
|
1063
|
+
const here = new Set(path6.map(keyOf2));
|
|
978
1064
|
for (const value of shared) {
|
|
979
1065
|
if (!here.has(value)) {
|
|
980
1066
|
shared.delete(value);
|
|
@@ -1004,7 +1090,7 @@ var IdSet = class {
|
|
|
1004
1090
|
has(node) {
|
|
1005
1091
|
return this.byKey.has(node.id);
|
|
1006
1092
|
}
|
|
1007
|
-
/** The
|
|
1093
|
+
/** The wrapper that was added, which may be a different object from `node`. */
|
|
1008
1094
|
get(node) {
|
|
1009
1095
|
return this.byKey.get(node.id);
|
|
1010
1096
|
}
|
|
@@ -1035,6 +1121,51 @@ var IdMap = class {
|
|
|
1035
1121
|
}
|
|
1036
1122
|
};
|
|
1037
1123
|
|
|
1124
|
+
// src/paths/nodeReads.ts
|
|
1125
|
+
var EnclosingNodes = class {
|
|
1126
|
+
constructor(types) {
|
|
1127
|
+
this.types = types;
|
|
1128
|
+
}
|
|
1129
|
+
types;
|
|
1130
|
+
byTree = /* @__PURE__ */ new WeakMap();
|
|
1131
|
+
/**
|
|
1132
|
+
* The nearest ancestor of one of the types, or null when there is none.
|
|
1133
|
+
* Every node passed on the way up has the same result, so each one is
|
|
1134
|
+
* kept, and a later read from a sibling stops one step up.
|
|
1135
|
+
*/
|
|
1136
|
+
of(node) {
|
|
1137
|
+
const kept = this.keptFor(node.tree);
|
|
1138
|
+
const known = kept.get(node.id);
|
|
1139
|
+
if (known !== void 0) {
|
|
1140
|
+
return known;
|
|
1141
|
+
}
|
|
1142
|
+
const passed = [node.id];
|
|
1143
|
+
let current = node.parent;
|
|
1144
|
+
while (current !== null && !this.types.has(current.type)) {
|
|
1145
|
+
const above = kept.get(current.id);
|
|
1146
|
+
if (above !== void 0) {
|
|
1147
|
+
current = above;
|
|
1148
|
+
break;
|
|
1149
|
+
}
|
|
1150
|
+
passed.push(current.id);
|
|
1151
|
+
current = current.parent;
|
|
1152
|
+
}
|
|
1153
|
+
for (const id of passed) {
|
|
1154
|
+
kept.set(id, current);
|
|
1155
|
+
}
|
|
1156
|
+
return current;
|
|
1157
|
+
}
|
|
1158
|
+
keptFor(tree) {
|
|
1159
|
+
const known = this.byTree.get(tree);
|
|
1160
|
+
if (known !== void 0) {
|
|
1161
|
+
return known;
|
|
1162
|
+
}
|
|
1163
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
1164
|
+
this.byTree.set(tree, fresh);
|
|
1165
|
+
return fresh;
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
|
|
1038
1169
|
// src/paths/nodeWalk.ts
|
|
1039
1170
|
var SKIP_CHILDREN = /* @__PURE__ */ Symbol("skipChildren");
|
|
1040
1171
|
function walkDescendants(root, carried, visitor) {
|
|
@@ -1051,23 +1182,23 @@ function walkDescendants(root, carried, visitor) {
|
|
|
1051
1182
|
}
|
|
1052
1183
|
|
|
1053
1184
|
// src/projectRoot.ts
|
|
1054
|
-
import
|
|
1185
|
+
import path3 from "path";
|
|
1055
1186
|
function commonDirectoryOf(files) {
|
|
1056
|
-
const absolute = files.filter((f) =>
|
|
1187
|
+
const absolute = files.filter((f) => path3.isAbsolute(f));
|
|
1057
1188
|
const first = absolute[0];
|
|
1058
1189
|
if (first === void 0) {
|
|
1059
1190
|
return void 0;
|
|
1060
1191
|
}
|
|
1061
|
-
let shared =
|
|
1192
|
+
let shared = path3.dirname(first).split(path3.sep);
|
|
1062
1193
|
for (const file of absolute.slice(1)) {
|
|
1063
|
-
const parts =
|
|
1194
|
+
const parts = path3.dirname(file).split(path3.sep);
|
|
1064
1195
|
let i = 0;
|
|
1065
1196
|
while (i < shared.length && i < parts.length && shared[i] === parts[i]) {
|
|
1066
1197
|
i += 1;
|
|
1067
1198
|
}
|
|
1068
1199
|
shared = shared.slice(0, i);
|
|
1069
1200
|
}
|
|
1070
|
-
const joined = shared.join(
|
|
1201
|
+
const joined = shared.join(path3.sep);
|
|
1071
1202
|
return joined.length > 1 ? joined : void 0;
|
|
1072
1203
|
}
|
|
1073
1204
|
|
|
@@ -1124,11 +1255,79 @@ function valueToReadFurtherFrom(reading) {
|
|
|
1124
1255
|
return reading.kind === "written" ? reading.value : null;
|
|
1125
1256
|
}
|
|
1126
1257
|
|
|
1258
|
+
// src/testFiles.ts
|
|
1259
|
+
function isListedTestFile(file, listed) {
|
|
1260
|
+
if (listed === void 0) {
|
|
1261
|
+
return true;
|
|
1262
|
+
}
|
|
1263
|
+
const whole = withForwardSlashes(file);
|
|
1264
|
+
return listed.some((entry) => {
|
|
1265
|
+
const tail = withForwardSlashes(entry).replace(/^\.\//, "");
|
|
1266
|
+
return whole === tail || whole.endsWith(`/${tail}`);
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
function matchesTestFileName(file, patterns) {
|
|
1270
|
+
const base = withForwardSlashes(file).split("/").pop() ?? "";
|
|
1271
|
+
return patterns.some((pattern) => globToRegExp(pattern).test(base));
|
|
1272
|
+
}
|
|
1273
|
+
function globToRegExp(pattern) {
|
|
1274
|
+
const escaped = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
1275
|
+
return new RegExp(`^${escaped}$`);
|
|
1276
|
+
}
|
|
1277
|
+
function withForwardSlashes(file) {
|
|
1278
|
+
return file.replace(/\\/g, "/");
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// src/valueSources.ts
|
|
1282
|
+
var QUOTED_LENGTH = 80;
|
|
1283
|
+
function sourceRefsOf(leaves, spelling) {
|
|
1284
|
+
const refs = [];
|
|
1285
|
+
const said = /* @__PURE__ */ new Set();
|
|
1286
|
+
for (const leaf of leaves) {
|
|
1287
|
+
const ref = convertedFrom(refOf(leaf, spelling), leaf.conversions);
|
|
1288
|
+
const spelled = JSON.stringify(ref);
|
|
1289
|
+
if (!said.has(spelled)) {
|
|
1290
|
+
said.add(spelled);
|
|
1291
|
+
refs.push(ref);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
return refs;
|
|
1295
|
+
}
|
|
1296
|
+
function convertedFrom(ref, conversions) {
|
|
1297
|
+
return conversions.reduceRight(
|
|
1298
|
+
(from, method) => ({
|
|
1299
|
+
type: "derived",
|
|
1300
|
+
from,
|
|
1301
|
+
derivation: { type: "methodCall", method, args: [] }
|
|
1302
|
+
}),
|
|
1303
|
+
ref
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
function refOf(leaf, spelling) {
|
|
1307
|
+
const whole = leaf.computedAt === null;
|
|
1308
|
+
const input = whole ? spelling.inputOf(leaf) : null;
|
|
1309
|
+
if (input !== null) {
|
|
1310
|
+
return input;
|
|
1311
|
+
}
|
|
1312
|
+
if (whole && leaf.end.is === "written" && leaf.path.length === 0) {
|
|
1313
|
+
const literal = spelling.literalAt(leaf.key);
|
|
1314
|
+
if (literal !== void 0) {
|
|
1315
|
+
return { type: "literal", value: literal };
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
const at = leaf.computedAt ?? leaf.key;
|
|
1319
|
+
return { type: "unresolved", sourceText: quoted(spelling.textAt(at), at) };
|
|
1320
|
+
}
|
|
1321
|
+
function quoted(text, key) {
|
|
1322
|
+
const written = (text ?? key.slice(key.lastIndexOf("#") + 1)).replace(/\s+/g, " ").trim();
|
|
1323
|
+
return written.length <= QUOTED_LENGTH ? written : `${written.slice(0, QUOTED_LENGTH - 3)}...`;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1127
1326
|
// src/adapterStamp.ts
|
|
1128
1327
|
import { createHash } from "crypto";
|
|
1129
|
-
import
|
|
1328
|
+
import fs2 from "fs";
|
|
1130
1329
|
import { createRequire } from "module";
|
|
1131
|
-
import
|
|
1330
|
+
import path4 from "path";
|
|
1132
1331
|
import { fileURLToPath } from "url";
|
|
1133
1332
|
var ANALYSIS_PACKAGES = [
|
|
1134
1333
|
"@suss/extractor",
|
|
@@ -1170,16 +1369,16 @@ function createAdapterStamp(config) {
|
|
|
1170
1369
|
function readAdapterCodeStamp(moduleUrl) {
|
|
1171
1370
|
try {
|
|
1172
1371
|
const selfPath = fileURLToPath(moduleUrl);
|
|
1173
|
-
const hash = computeDistHashFrom(
|
|
1372
|
+
const hash = computeDistHashFrom(path4.dirname(selfPath));
|
|
1174
1373
|
return hash.length > 0 ? { kind: "bundle", hash } : SOURCE_STAMP;
|
|
1175
1374
|
} catch {
|
|
1176
1375
|
return SOURCE_STAMP;
|
|
1177
1376
|
}
|
|
1178
1377
|
}
|
|
1179
1378
|
function computeDistHashFrom(dir) {
|
|
1180
|
-
const candidates = [
|
|
1379
|
+
const candidates = [path4.join(dir, "index.js"), path4.join(dir, "index.cjs")];
|
|
1181
1380
|
for (const candidate of candidates) {
|
|
1182
|
-
if (!
|
|
1381
|
+
if (!fs2.existsSync(candidate)) {
|
|
1183
1382
|
continue;
|
|
1184
1383
|
}
|
|
1185
1384
|
return computeContentHash([candidate, ...analysisBundles()]);
|
|
@@ -1193,7 +1392,7 @@ function computeContentHash(paths) {
|
|
|
1193
1392
|
const hash = createHash("sha256");
|
|
1194
1393
|
for (const file of paths) {
|
|
1195
1394
|
try {
|
|
1196
|
-
hash.update(
|
|
1395
|
+
hash.update(fs2.readFileSync(file));
|
|
1197
1396
|
} catch {
|
|
1198
1397
|
return "";
|
|
1199
1398
|
}
|
|
@@ -1209,13 +1408,29 @@ function projectFileStamp(paths) {
|
|
|
1209
1408
|
hash.update(file);
|
|
1210
1409
|
hash.update("\0");
|
|
1211
1410
|
try {
|
|
1212
|
-
hash.update(
|
|
1411
|
+
hash.update(fs2.readFileSync(file));
|
|
1213
1412
|
} catch {
|
|
1214
1413
|
hash.update("absent");
|
|
1215
1414
|
}
|
|
1216
1415
|
}
|
|
1217
1416
|
return hash.digest("hex").slice(0, 16);
|
|
1218
1417
|
}
|
|
1418
|
+
function extractionConfigStamp(config) {
|
|
1419
|
+
const parts = [
|
|
1420
|
+
["gapHandling", config.gapHandling ?? "permissive"],
|
|
1421
|
+
["includeReachable", optionalText(config.includeReachable)],
|
|
1422
|
+
["workspaceRoot", config.workspaceRoot],
|
|
1423
|
+
["projectRoot", config.projectRoot],
|
|
1424
|
+
["importRoots", config.importRoots?.join(path4.delimiter)],
|
|
1425
|
+
["modules", modulesStamp(config.modules)]
|
|
1426
|
+
];
|
|
1427
|
+
return parts.flatMap(
|
|
1428
|
+
([name, value]) => value === void 0 ? [] : [`${name}=${value}`]
|
|
1429
|
+
).join(",");
|
|
1430
|
+
}
|
|
1431
|
+
function optionalText(value) {
|
|
1432
|
+
return value === void 0 ? void 0 : String(value);
|
|
1433
|
+
}
|
|
1219
1434
|
function runDigest(packsDigest, packs, files) {
|
|
1220
1435
|
const inputs = packs.flatMap((pack) => pack.discoveryInputs?.(files) ?? []);
|
|
1221
1436
|
return `${packsDigest}|reads:${projectFileStamp(inputs)}`;
|
|
@@ -1233,10 +1448,118 @@ function analysisBundles() {
|
|
|
1233
1448
|
}
|
|
1234
1449
|
|
|
1235
1450
|
// src/cache.ts
|
|
1451
|
+
import { createHash as createHash3 } from "crypto";
|
|
1452
|
+
import fs4 from "fs/promises";
|
|
1453
|
+
import path5 from "path";
|
|
1454
|
+
|
|
1455
|
+
// src/cacheStamps.ts
|
|
1236
1456
|
import { createHash as createHash2 } from "crypto";
|
|
1237
|
-
import
|
|
1238
|
-
|
|
1239
|
-
|
|
1457
|
+
import fs3 from "fs/promises";
|
|
1458
|
+
var RECENT_CHANGE_MS = 2e3;
|
|
1459
|
+
function stampMayMissAWrite(stat, statAt) {
|
|
1460
|
+
return Math.max(stat.mtimeMs, stat.ctimeMs) > statAt - RECENT_CHANGE_MS;
|
|
1461
|
+
}
|
|
1462
|
+
async function startRun(files, configPath) {
|
|
1463
|
+
const startedAt = Date.now();
|
|
1464
|
+
const config = configPath === void 0 ? null : await statAtStart(configPath);
|
|
1465
|
+
const stats = await Promise.all(files.map(statAtStart));
|
|
1466
|
+
stats.sort(
|
|
1467
|
+
(a, b) => a.stamp.path < b.stamp.path ? -1 : a.stamp.path > b.stamp.path ? 1 : 0
|
|
1468
|
+
);
|
|
1469
|
+
return {
|
|
1470
|
+
startedAt,
|
|
1471
|
+
config: config?.ctimeMs === null ? null : config,
|
|
1472
|
+
files: stats,
|
|
1473
|
+
hashes: /* @__PURE__ */ new Map()
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
async function statAtStart(filePath) {
|
|
1477
|
+
try {
|
|
1478
|
+
const stat = await fs3.stat(filePath);
|
|
1479
|
+
return {
|
|
1480
|
+
stamp: { path: filePath, mtimeMs: stat.mtimeMs, size: stat.size },
|
|
1481
|
+
ctimeMs: stat.ctimeMs
|
|
1482
|
+
};
|
|
1483
|
+
} catch {
|
|
1484
|
+
return { stamp: { path: filePath, mtimeMs: -1, size: -1 }, ctimeMs: null };
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
async function hashOf(run, filePath) {
|
|
1488
|
+
const known = run.hashes.get(filePath);
|
|
1489
|
+
if (known !== void 0) {
|
|
1490
|
+
return known;
|
|
1491
|
+
}
|
|
1492
|
+
const hash = await hashFile(filePath);
|
|
1493
|
+
run.hashes.set(filePath, hash);
|
|
1494
|
+
return hash;
|
|
1495
|
+
}
|
|
1496
|
+
async function hashRecentChanges(run) {
|
|
1497
|
+
const recent = [...run.config === null ? [] : [run.config], ...run.files].filter(
|
|
1498
|
+
(file) => file.ctimeMs !== null && stampMayMissAWrite(
|
|
1499
|
+
{ mtimeMs: file.stamp.mtimeMs, ctimeMs: file.ctimeMs },
|
|
1500
|
+
run.startedAt
|
|
1501
|
+
)
|
|
1502
|
+
).map((file) => file.stamp.path);
|
|
1503
|
+
await Promise.all(recent.map((filePath) => hashOf(run, filePath)));
|
|
1504
|
+
}
|
|
1505
|
+
async function stillMatches(stored, found, run) {
|
|
1506
|
+
if (!fileStampEquals(stored, found)) {
|
|
1507
|
+
return false;
|
|
1508
|
+
}
|
|
1509
|
+
if (stored === null || stored.verifyHash !== true) {
|
|
1510
|
+
return true;
|
|
1511
|
+
}
|
|
1512
|
+
return await hashOf(run, stored.path) === stored.contentHash;
|
|
1513
|
+
}
|
|
1514
|
+
async function filesStillMatch(stored, run) {
|
|
1515
|
+
if (stored.length !== run.files.length || !stored.every((s, i) => fileStampEquals(s, run.files[i]?.stamp ?? null))) {
|
|
1516
|
+
return false;
|
|
1517
|
+
}
|
|
1518
|
+
const checks = await Promise.all(
|
|
1519
|
+
stored.map((s, i) => stillMatches(s, run.files[i]?.stamp ?? null, run))
|
|
1520
|
+
);
|
|
1521
|
+
return checks.every(Boolean);
|
|
1522
|
+
}
|
|
1523
|
+
async function recordedStamp(start, run, prior) {
|
|
1524
|
+
if (start.ctimeMs === null) {
|
|
1525
|
+
return start.stamp;
|
|
1526
|
+
}
|
|
1527
|
+
const filePath = start.stamp.path;
|
|
1528
|
+
const now = await fs3.stat(filePath).catch(() => null);
|
|
1529
|
+
if (now === null || now.mtimeMs !== start.stamp.mtimeMs || now.size !== start.stamp.size || now.ctimeMs !== start.ctimeMs) {
|
|
1530
|
+
return null;
|
|
1531
|
+
}
|
|
1532
|
+
const atStart = { mtimeMs: start.stamp.mtimeMs, ctimeMs: start.ctimeMs };
|
|
1533
|
+
if (stampMayMissAWrite(atStart, run.startedAt)) {
|
|
1534
|
+
const readBefore = run.hashes.get(filePath);
|
|
1535
|
+
return readBefore === void 0 || readBefore === null ? null : { ...start.stamp, contentHash: readBefore, verifyHash: true };
|
|
1536
|
+
}
|
|
1537
|
+
const hash = run.hashes.get(filePath) ?? reusableHash(prior, start.stamp) ?? await hashFile(filePath);
|
|
1538
|
+
return hash === null ? start.stamp : { ...start.stamp, contentHash: hash };
|
|
1539
|
+
}
|
|
1540
|
+
function reusableHash(prior, stamp) {
|
|
1541
|
+
return prior !== void 0 && prior.verifyHash !== true && fileStampEquals(prior, stamp) ? prior.contentHash : void 0;
|
|
1542
|
+
}
|
|
1543
|
+
async function hashFile(filePath) {
|
|
1544
|
+
try {
|
|
1545
|
+
const content = await fs3.readFile(filePath);
|
|
1546
|
+
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
1547
|
+
} catch {
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
function fileStampEquals(a, b) {
|
|
1552
|
+
if (a === null && b === null) {
|
|
1553
|
+
return true;
|
|
1554
|
+
}
|
|
1555
|
+
if (a === null || b === null) {
|
|
1556
|
+
return false;
|
|
1557
|
+
}
|
|
1558
|
+
return a.path === b.path && a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
// src/cache.ts
|
|
1562
|
+
var SCHEMA_VERSION = "9";
|
|
1240
1563
|
var MAX_ENTRIES = 2;
|
|
1241
1564
|
var ENTRY_PREFIX = "key-";
|
|
1242
1565
|
var ENTRY_DIR_NAME = new RegExp(`^${ENTRY_PREFIX}[0-9a-f]{16}$`);
|
|
@@ -1253,56 +1576,88 @@ function createCacheLayer(cacheDir) {
|
|
|
1253
1576
|
}
|
|
1254
1577
|
};
|
|
1255
1578
|
}
|
|
1579
|
+
const manifests = new ManifestReads();
|
|
1580
|
+
const runs = /* @__PURE__ */ new WeakMap();
|
|
1581
|
+
const runFor = async (input) => runs.get(input) ?? await startRun(input.files, input.configPath);
|
|
1582
|
+
const lookupWith = async (input, run) => {
|
|
1583
|
+
const entryDir = entryDirFor(cacheDir, input);
|
|
1584
|
+
const manifest = await manifests.readAtRunStart(
|
|
1585
|
+
path5.join(entryDir, "manifest.json")
|
|
1586
|
+
);
|
|
1587
|
+
if (manifest === null) {
|
|
1588
|
+
return missDiag(await describeAbsentEntry(cacheDir));
|
|
1589
|
+
}
|
|
1590
|
+
if (!await stillMatches(
|
|
1591
|
+
manifest.configStamp,
|
|
1592
|
+
run.config?.stamp ?? null,
|
|
1593
|
+
run
|
|
1594
|
+
)) {
|
|
1595
|
+
return missDiag("config-changed");
|
|
1596
|
+
}
|
|
1597
|
+
if (!await filesStillMatch(manifest.files, run)) {
|
|
1598
|
+
return missDiag("files-changed");
|
|
1599
|
+
}
|
|
1600
|
+
await markUsed(entryDir);
|
|
1601
|
+
manifests.forget();
|
|
1602
|
+
return {
|
|
1603
|
+
kind: "hit",
|
|
1604
|
+
summaries: manifest.summaries,
|
|
1605
|
+
diagnostic: { kind: "hit" }
|
|
1606
|
+
};
|
|
1607
|
+
};
|
|
1256
1608
|
return {
|
|
1257
1609
|
async tryHit(input) {
|
|
1258
1610
|
const result = await this.lookup(input);
|
|
1259
1611
|
return result.kind === "hit" ? result.summaries : null;
|
|
1260
1612
|
},
|
|
1261
1613
|
async lookup(input) {
|
|
1262
|
-
const
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
)
|
|
1266
|
-
|
|
1267
|
-
return missDiag(await describeAbsentEntry(cacheDir));
|
|
1614
|
+
const run = await startRun(input.files, input.configPath);
|
|
1615
|
+
runs.set(input, run);
|
|
1616
|
+
const result = await lookupWith(input, run);
|
|
1617
|
+
if (result.kind === "miss") {
|
|
1618
|
+
await hashRecentChanges(run);
|
|
1268
1619
|
}
|
|
1269
|
-
|
|
1270
|
-
if (!fileStampEquals(manifest.configStamp, currentConfigStamp)) {
|
|
1271
|
-
return missDiag("config-changed");
|
|
1272
|
-
}
|
|
1273
|
-
const currentFiles = await resolveFileStamps(input);
|
|
1274
|
-
if (!fileStampsEqual(manifest.files, currentFiles)) {
|
|
1275
|
-
return missDiag("files-changed");
|
|
1276
|
-
}
|
|
1277
|
-
await markUsed(entryDir);
|
|
1278
|
-
return {
|
|
1279
|
-
kind: "hit",
|
|
1280
|
-
summaries: manifest.summaries,
|
|
1281
|
-
diagnostic: { kind: "hit" }
|
|
1282
|
-
};
|
|
1620
|
+
return result;
|
|
1283
1621
|
},
|
|
1284
1622
|
async plan(input) {
|
|
1285
1623
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1286
|
-
const manifest = await
|
|
1287
|
-
|
|
1624
|
+
const manifest = await manifests.readAgain(
|
|
1625
|
+
path5.join(entryDir, "manifest.json")
|
|
1288
1626
|
);
|
|
1289
1627
|
if (manifest === null || manifest.roots === void 0 || manifest.rootMeta === void 0 || manifest.owners === void 0) {
|
|
1290
1628
|
return null;
|
|
1291
1629
|
}
|
|
1292
|
-
const
|
|
1293
|
-
if (!
|
|
1630
|
+
const run = await runFor(input);
|
|
1631
|
+
if (!await stillMatches(
|
|
1632
|
+
manifest.configStamp,
|
|
1633
|
+
run.config?.stamp ?? null,
|
|
1634
|
+
run
|
|
1635
|
+
)) {
|
|
1294
1636
|
return null;
|
|
1295
1637
|
}
|
|
1296
1638
|
await markUsed(entryDir);
|
|
1297
|
-
return buildPlan(manifest,
|
|
1639
|
+
return buildPlan(manifest, run);
|
|
1298
1640
|
},
|
|
1299
1641
|
async write(input, summaries, attribution) {
|
|
1300
1642
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1301
|
-
const previous = await
|
|
1302
|
-
|
|
1643
|
+
const previous = await manifests.readAgain(
|
|
1644
|
+
path5.join(entryDir, "manifest.json")
|
|
1303
1645
|
);
|
|
1304
|
-
|
|
1305
|
-
const
|
|
1646
|
+
manifests.forget();
|
|
1647
|
+
const known = runs.get(input);
|
|
1648
|
+
const run = known ?? await runFor(input);
|
|
1649
|
+
if (known === void 0) {
|
|
1650
|
+
await hashRecentChanges(run);
|
|
1651
|
+
}
|
|
1652
|
+
runs.delete(input);
|
|
1653
|
+
const configStamp = run.config === null ? null : await recordedStamp(run.config, run, void 0);
|
|
1654
|
+
const prior = new Map((previous?.files ?? []).map((f) => [f.path, f]));
|
|
1655
|
+
const recorded = await Promise.all(
|
|
1656
|
+
run.files.map(
|
|
1657
|
+
(file) => recordedStamp(file, run, prior.get(file.stamp.path))
|
|
1658
|
+
)
|
|
1659
|
+
);
|
|
1660
|
+
const files = recorded.filter((stamp) => stamp !== null);
|
|
1306
1661
|
const manifest = {
|
|
1307
1662
|
schemaVersion: SCHEMA_VERSION,
|
|
1308
1663
|
adapterPacksDigest: input.adapterPacksDigest,
|
|
@@ -1311,19 +1666,20 @@ function createCacheLayer(cacheDir) {
|
|
|
1311
1666
|
summaries,
|
|
1312
1667
|
...attribution === void 0 ? {} : encodeAttribution(attribution)
|
|
1313
1668
|
};
|
|
1314
|
-
await
|
|
1315
|
-
await
|
|
1316
|
-
|
|
1669
|
+
await fs4.mkdir(entryDir, { recursive: true });
|
|
1670
|
+
await fs4.writeFile(
|
|
1671
|
+
path5.join(entryDir, "manifest.json"),
|
|
1317
1672
|
JSON.stringify(manifest)
|
|
1318
1673
|
);
|
|
1319
1674
|
await evictOldEntries(cacheDir, entryDir);
|
|
1320
1675
|
}
|
|
1321
1676
|
};
|
|
1322
1677
|
}
|
|
1323
|
-
async function buildPlan(manifest,
|
|
1678
|
+
async function buildPlan(manifest, run) {
|
|
1324
1679
|
const stored = new Map(manifest.files.map((f) => [f.path, f]));
|
|
1325
|
-
const current = new Map(
|
|
1680
|
+
const current = new Map(run.files.map((f) => [f.stamp.path, f.stamp]));
|
|
1326
1681
|
const changed = /* @__PURE__ */ new Set();
|
|
1682
|
+
const added = /* @__PURE__ */ new Set();
|
|
1327
1683
|
const removed = /* @__PURE__ */ new Set();
|
|
1328
1684
|
for (const p of stored.keys()) {
|
|
1329
1685
|
if (!current.has(p)) {
|
|
@@ -1335,17 +1691,20 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1335
1691
|
const before = stored.get(p);
|
|
1336
1692
|
if (before === void 0) {
|
|
1337
1693
|
changed.add(p);
|
|
1694
|
+
added.add(p);
|
|
1338
1695
|
} else if (!fileStampEquals(before, stamp)) {
|
|
1339
1696
|
if (before.contentHash === void 0) {
|
|
1340
1697
|
changed.add(p);
|
|
1341
1698
|
} else {
|
|
1342
1699
|
toVerify.push(p);
|
|
1343
1700
|
}
|
|
1701
|
+
} else if (before.verifyHash === true) {
|
|
1702
|
+
toVerify.push(p);
|
|
1344
1703
|
}
|
|
1345
1704
|
}
|
|
1346
1705
|
await Promise.all(
|
|
1347
1706
|
toVerify.map(async (p) => {
|
|
1348
|
-
const hash = await
|
|
1707
|
+
const hash = await hashOf(run, p);
|
|
1349
1708
|
if (hash === null || hash !== stored.get(p)?.contentHash) {
|
|
1350
1709
|
changed.add(p);
|
|
1351
1710
|
}
|
|
@@ -1354,6 +1713,10 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1354
1713
|
const roots = /* @__PURE__ */ new Map();
|
|
1355
1714
|
const rootNames = manifest.roots ?? [];
|
|
1356
1715
|
const depPaths = manifest.depPaths ?? [];
|
|
1716
|
+
const pathsOf = (ids) => ids.flatMap((d) => {
|
|
1717
|
+
const p = depPaths[d];
|
|
1718
|
+
return p === void 0 ? [] : [p];
|
|
1719
|
+
});
|
|
1357
1720
|
let rootsDeclined = 0;
|
|
1358
1721
|
rootNames.forEach((rootPath, i) => {
|
|
1359
1722
|
const meta = manifest.rootMeta?.[i];
|
|
@@ -1366,35 +1729,54 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1366
1729
|
roots.set(rootPath, {
|
|
1367
1730
|
path: rootPath,
|
|
1368
1731
|
cacheable: meta.cacheable,
|
|
1369
|
-
deps: meta.deps
|
|
1370
|
-
const p = depPaths[d];
|
|
1371
|
-
return p === void 0 ? [] : [p];
|
|
1372
|
-
}),
|
|
1732
|
+
deps: pathsOf(meta.deps),
|
|
1373
1733
|
claims: meta.claims,
|
|
1374
1734
|
meta: meta.meta,
|
|
1375
|
-
packs: meta.packs
|
|
1735
|
+
packs: meta.packs,
|
|
1736
|
+
...meta.imports === void 0 ? {} : { imports: pathsOf(meta.imports) }
|
|
1376
1737
|
});
|
|
1377
1738
|
});
|
|
1739
|
+
const unchanged = (filePath, deps) => current.has(filePath) && !changed.has(filePath) && !deps.some((d) => changed.has(d) || removed.has(d));
|
|
1378
1740
|
const validRoots = /* @__PURE__ */ new Set();
|
|
1379
1741
|
for (const [rootPath, record] of roots) {
|
|
1380
|
-
if (
|
|
1381
|
-
|
|
1742
|
+
if (record.cacheable && unchanged(rootPath, record.deps)) {
|
|
1743
|
+
validRoots.add(rootPath);
|
|
1382
1744
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1745
|
+
}
|
|
1746
|
+
const units = (manifest.units ?? []).flatMap((stored2) => {
|
|
1747
|
+
const file = depPaths[stored2.file];
|
|
1748
|
+
return file === void 0 ? [] : [
|
|
1749
|
+
{
|
|
1750
|
+
key: stored2.key,
|
|
1751
|
+
file,
|
|
1752
|
+
deps: pathsOf(stored2.deps),
|
|
1753
|
+
data: stored2.data
|
|
1754
|
+
}
|
|
1755
|
+
];
|
|
1756
|
+
});
|
|
1757
|
+
const validUnits = /* @__PURE__ */ new Map();
|
|
1758
|
+
for (const unit of units) {
|
|
1759
|
+
if (unchanged(unit.file, unit.deps)) {
|
|
1760
|
+
validUnits.set(unit.key, unit);
|
|
1385
1761
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1762
|
+
}
|
|
1763
|
+
const resolvedImports = /* @__PURE__ */ new Map();
|
|
1764
|
+
if (added.size === 0 && removed.size === 0) {
|
|
1765
|
+
for (const [rootPath, record] of roots) {
|
|
1766
|
+
if (record.imports !== void 0 && !changed.has(rootPath)) {
|
|
1767
|
+
resolvedImports.set(rootPath, record.imports);
|
|
1768
|
+
}
|
|
1389
1769
|
}
|
|
1390
1770
|
}
|
|
1391
1771
|
const owners = manifest.owners ?? [];
|
|
1392
1772
|
return {
|
|
1393
1773
|
changed,
|
|
1394
1774
|
removed,
|
|
1775
|
+
resolvedImports,
|
|
1395
1776
|
roots,
|
|
1396
1777
|
validRoots,
|
|
1397
1778
|
rootsDeclined,
|
|
1779
|
+
validUnits,
|
|
1398
1780
|
reuse(valid) {
|
|
1399
1781
|
const summaries = [];
|
|
1400
1782
|
const reusedOwners = [];
|
|
@@ -1421,7 +1803,8 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1421
1803
|
const p = rootNames[o];
|
|
1422
1804
|
return p === void 0 ? [] : [p];
|
|
1423
1805
|
})
|
|
1424
|
-
)
|
|
1806
|
+
),
|
|
1807
|
+
units
|
|
1425
1808
|
};
|
|
1426
1809
|
}
|
|
1427
1810
|
};
|
|
@@ -1446,7 +1829,8 @@ function encodeAttribution(attribution) {
|
|
|
1446
1829
|
deps: r.deps.map(depIdOf),
|
|
1447
1830
|
claims: r.claims,
|
|
1448
1831
|
meta: r.meta,
|
|
1449
|
-
packs: r.packs
|
|
1832
|
+
packs: r.packs,
|
|
1833
|
+
...r.imports === void 0 ? {} : { imports: r.imports.map(depIdOf) }
|
|
1450
1834
|
}));
|
|
1451
1835
|
const owners = attribution.owners.map(
|
|
1452
1836
|
(ownerPaths) => ownerPaths.flatMap((p) => {
|
|
@@ -1454,32 +1838,23 @@ function encodeAttribution(attribution) {
|
|
|
1454
1838
|
return i === void 0 ? [] : [i];
|
|
1455
1839
|
})
|
|
1456
1840
|
);
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
);
|
|
1471
|
-
}
|
|
1472
|
-
async function hashFile(filePath) {
|
|
1473
|
-
try {
|
|
1474
|
-
const content = await fs2.readFile(filePath);
|
|
1475
|
-
return createHash2("sha256").update(content).digest("hex").slice(0, 16);
|
|
1476
|
-
} catch {
|
|
1477
|
-
return null;
|
|
1478
|
-
}
|
|
1841
|
+
const units = attribution.units?.map((unit) => ({
|
|
1842
|
+
key: unit.key,
|
|
1843
|
+
file: depIdOf(unit.file),
|
|
1844
|
+
deps: unit.deps.map(depIdOf),
|
|
1845
|
+
data: unit.data
|
|
1846
|
+
}));
|
|
1847
|
+
return {
|
|
1848
|
+
roots,
|
|
1849
|
+
rootMeta,
|
|
1850
|
+
depPaths,
|
|
1851
|
+
owners,
|
|
1852
|
+
...units === void 0 ? {} : { units }
|
|
1853
|
+
};
|
|
1479
1854
|
}
|
|
1480
1855
|
async function describeAbsentEntry(cacheDir) {
|
|
1481
1856
|
try {
|
|
1482
|
-
const entries = await
|
|
1857
|
+
const entries = await fs4.readdir(cacheDir, { withFileTypes: true });
|
|
1483
1858
|
return entries.some((e) => e.isDirectory() && isEntryDir(e.name)) ? "key-changed" : "no-manifest";
|
|
1484
1859
|
} catch {
|
|
1485
1860
|
return "no-manifest";
|
|
@@ -1491,8 +1866,8 @@ function entryDirFor(cacheDir, input) {
|
|
|
1491
1866
|
input.adapterPacksDigest,
|
|
1492
1867
|
input.configPath ?? ""
|
|
1493
1868
|
].join(" ");
|
|
1494
|
-
const name =
|
|
1495
|
-
return
|
|
1869
|
+
const name = createHash3("sha256").update(key).digest("hex").slice(0, 16);
|
|
1870
|
+
return path5.join(cacheDir, `${ENTRY_PREFIX}${name}`);
|
|
1496
1871
|
}
|
|
1497
1872
|
function isEntryDir(name) {
|
|
1498
1873
|
return ENTRY_DIR_NAME.test(name);
|
|
@@ -1500,24 +1875,24 @@ function isEntryDir(name) {
|
|
|
1500
1875
|
async function markUsed(entryDir) {
|
|
1501
1876
|
const now = /* @__PURE__ */ new Date();
|
|
1502
1877
|
try {
|
|
1503
|
-
await
|
|
1878
|
+
await fs4.utimes(entryDir, now, now);
|
|
1504
1879
|
} catch {
|
|
1505
1880
|
}
|
|
1506
1881
|
}
|
|
1507
1882
|
async function evictOldEntries(cacheDir, keepDir) {
|
|
1508
1883
|
try {
|
|
1509
|
-
await
|
|
1510
|
-
const entries = await
|
|
1884
|
+
await fs4.rm(path5.join(cacheDir, "manifest.json"), { force: true });
|
|
1885
|
+
const entries = await fs4.readdir(cacheDir, { withFileTypes: true });
|
|
1511
1886
|
const dirs = await Promise.all(
|
|
1512
1887
|
entries.filter((e) => e.isDirectory() && isEntryDir(e.name)).map(async (e) => {
|
|
1513
|
-
const dir =
|
|
1514
|
-
const stat = await
|
|
1888
|
+
const dir = path5.join(cacheDir, e.name);
|
|
1889
|
+
const stat = await fs4.stat(dir);
|
|
1515
1890
|
return { dir, mtimeMs: stat.mtimeMs };
|
|
1516
1891
|
})
|
|
1517
1892
|
);
|
|
1518
1893
|
const doomed = dirs.filter((d) => d.dir !== keepDir).sort((a, b) => b.mtimeMs - a.mtimeMs).slice(MAX_ENTRIES - 1);
|
|
1519
1894
|
await Promise.all(
|
|
1520
|
-
doomed.map((d) =>
|
|
1895
|
+
doomed.map((d) => fs4.rm(d.dir, { recursive: true, force: true }))
|
|
1521
1896
|
);
|
|
1522
1897
|
} catch {
|
|
1523
1898
|
}
|
|
@@ -1528,51 +1903,41 @@ function missDiag(reason) {
|
|
|
1528
1903
|
diagnostic: { kind: "miss", missReason: reason }
|
|
1529
1904
|
};
|
|
1530
1905
|
}
|
|
1531
|
-
|
|
1906
|
+
var ManifestReads = class {
|
|
1907
|
+
last = null;
|
|
1908
|
+
async readAtRunStart(manifestPath) {
|
|
1909
|
+
const stamp = await manifestStamp(manifestPath);
|
|
1910
|
+
const manifest = await readManifest(manifestPath);
|
|
1911
|
+
this.last = { path: manifestPath, stamp, manifest };
|
|
1912
|
+
return manifest;
|
|
1913
|
+
}
|
|
1914
|
+
async readAgain(manifestPath) {
|
|
1915
|
+
const last = this.last;
|
|
1916
|
+
if (last !== null && last.path === manifestPath && last.stamp !== null && last.stamp === await manifestStamp(manifestPath)) {
|
|
1917
|
+
return last.manifest;
|
|
1918
|
+
}
|
|
1919
|
+
return await this.readAtRunStart(manifestPath);
|
|
1920
|
+
}
|
|
1921
|
+
forget() {
|
|
1922
|
+
this.last = null;
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
async function manifestStamp(manifestPath) {
|
|
1532
1926
|
try {
|
|
1533
|
-
const
|
|
1534
|
-
return
|
|
1927
|
+
const stat = await fs4.stat(manifestPath);
|
|
1928
|
+
return `${stat.ino}:${stat.mtimeMs}:${stat.size}`;
|
|
1535
1929
|
} catch {
|
|
1536
1930
|
return null;
|
|
1537
1931
|
}
|
|
1538
1932
|
}
|
|
1539
|
-
async function
|
|
1540
|
-
if (configPath === void 0) {
|
|
1541
|
-
return null;
|
|
1542
|
-
}
|
|
1933
|
+
async function readManifest(manifestPath) {
|
|
1543
1934
|
try {
|
|
1544
|
-
const
|
|
1545
|
-
return
|
|
1935
|
+
const raw = await fs4.readFile(manifestPath, "utf-8");
|
|
1936
|
+
return JSON.parse(raw);
|
|
1546
1937
|
} catch {
|
|
1547
1938
|
return null;
|
|
1548
1939
|
}
|
|
1549
1940
|
}
|
|
1550
|
-
async function resolveFileStamps(input) {
|
|
1551
|
-
const stamped = await Promise.all(
|
|
1552
|
-
input.files.map(async (p) => {
|
|
1553
|
-
try {
|
|
1554
|
-
const stat = await fs2.stat(p);
|
|
1555
|
-
return { path: p, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
1556
|
-
} catch {
|
|
1557
|
-
return { path: p, mtimeMs: -1, size: -1 };
|
|
1558
|
-
}
|
|
1559
|
-
})
|
|
1560
|
-
);
|
|
1561
|
-
stamped.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
1562
|
-
return stamped;
|
|
1563
|
-
}
|
|
1564
|
-
function fileStampsEqual(a, b) {
|
|
1565
|
-
return a.length === b.length && a.every((s, i) => fileStampEquals(s, b[i]));
|
|
1566
|
-
}
|
|
1567
|
-
function fileStampEquals(a, b) {
|
|
1568
|
-
if (a === null && b === null) {
|
|
1569
|
-
return true;
|
|
1570
|
-
}
|
|
1571
|
-
if (a === null || b === null) {
|
|
1572
|
-
return false;
|
|
1573
|
-
}
|
|
1574
|
-
return a.path === b.path && a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
1575
|
-
}
|
|
1576
1941
|
|
|
1577
1942
|
// src/extractionReport.ts
|
|
1578
1943
|
import { BOUNDARY_ROLE } from "@suss/behavioral-ir";
|
|
@@ -1681,6 +2046,38 @@ function firstEmptyUngatedStage(packs, filesWalked) {
|
|
|
1681
2046
|
return "assembly";
|
|
1682
2047
|
}
|
|
1683
2048
|
|
|
2049
|
+
// src/keptParses.ts
|
|
2050
|
+
var KeptParses = class {
|
|
2051
|
+
constructor(release = () => {
|
|
2052
|
+
}) {
|
|
2053
|
+
this.release = release;
|
|
2054
|
+
}
|
|
2055
|
+
release;
|
|
2056
|
+
byFile = /* @__PURE__ */ new Map();
|
|
2057
|
+
async parse(file, source, make) {
|
|
2058
|
+
const kept = this.byFile.get(file);
|
|
2059
|
+
if (kept !== void 0 && kept.source === source) {
|
|
2060
|
+
return kept.value;
|
|
2061
|
+
}
|
|
2062
|
+
const value = await make(source);
|
|
2063
|
+
if (kept !== void 0) {
|
|
2064
|
+
this.release(kept.value);
|
|
2065
|
+
}
|
|
2066
|
+
this.byFile.set(file, { source, value });
|
|
2067
|
+
return value;
|
|
2068
|
+
}
|
|
2069
|
+
/** Lets go of every file not in this run. */
|
|
2070
|
+
keepOnly(files) {
|
|
2071
|
+
const wanted = new Set(files);
|
|
2072
|
+
for (const [file, kept] of this.byFile) {
|
|
2073
|
+
if (!wanted.has(file)) {
|
|
2074
|
+
this.release(kept.value);
|
|
2075
|
+
this.byFile.delete(file);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
};
|
|
2080
|
+
|
|
1684
2081
|
// src/packHealth.ts
|
|
1685
2082
|
function stagesOf(funnel) {
|
|
1686
2083
|
const stages = [];
|
|
@@ -1727,8 +2124,8 @@ function funnelDrops(packs) {
|
|
|
1727
2124
|
function recognizersWithNoUnits(packs) {
|
|
1728
2125
|
return packs.filter(
|
|
1729
2126
|
(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
|
|
1730
|
-
// roots, so effects recognized there mean the run worked and
|
|
1731
|
-
// the
|
|
2127
|
+
// roots, so effects recognized there mean the run worked and only
|
|
2128
|
+
// the framework pack's attribution is missing.
|
|
1732
2129
|
funnel.effectsRecognized === 0
|
|
1733
2130
|
).map((funnel) => ({
|
|
1734
2131
|
label: funnel.pack,
|
|
@@ -1970,7 +2367,7 @@ function makeTransitionId(functionName, branch) {
|
|
|
1970
2367
|
const { terminal } = branch;
|
|
1971
2368
|
const statusKey = terminal.statusCode === null ? "none" : terminal.statusCode.type === "literal" ? String(terminal.statusCode.value) : `dyn:${terminal.statusCode.sourceText}`;
|
|
1972
2369
|
const conditionSig = branch.conditions.map((c) => `${c.polarity}:${c.sourceText}`).join(";");
|
|
1973
|
-
const conditionHash =
|
|
2370
|
+
const conditionHash = createHash4("sha1").update(conditionSig).digest("hex").slice(0, 7);
|
|
1974
2371
|
return `${functionName}:${terminal.kind}:${statusKey}:${conditionHash}`;
|
|
1975
2372
|
}
|
|
1976
2373
|
function collapseReading(table, reading) {
|
|
@@ -2040,6 +2437,39 @@ function effectsOfBranch(branch) {
|
|
|
2040
2437
|
];
|
|
2041
2438
|
return foldRepeatedEffects(effects.map(withNormalizedCallee));
|
|
2042
2439
|
}
|
|
2440
|
+
function provenanceOf(raw, effects) {
|
|
2441
|
+
if (raw.length === 0) {
|
|
2442
|
+
return [];
|
|
2443
|
+
}
|
|
2444
|
+
const positionOf = new Map(effects.map((one, at) => [effectKey(one), at]));
|
|
2445
|
+
const bySlot = /* @__PURE__ */ new Map();
|
|
2446
|
+
const said = /* @__PURE__ */ new Map();
|
|
2447
|
+
for (const one of raw) {
|
|
2448
|
+
const effect = positionOf.get(effectKey(withNormalizedCallee(one.effect)));
|
|
2449
|
+
if (effect === void 0) {
|
|
2450
|
+
continue;
|
|
2451
|
+
}
|
|
2452
|
+
const slotKey = `${effect}\0${one.slot}\0${one.name}`;
|
|
2453
|
+
let entry = bySlot.get(slotKey);
|
|
2454
|
+
let seen = said.get(slotKey);
|
|
2455
|
+
if (entry === void 0 || seen === void 0) {
|
|
2456
|
+
entry = { at: { slot: one.slot, effect, name: one.name }, from: [] };
|
|
2457
|
+
seen = /* @__PURE__ */ new Set();
|
|
2458
|
+
bySlot.set(slotKey, entry);
|
|
2459
|
+
said.set(slotKey, seen);
|
|
2460
|
+
}
|
|
2461
|
+
for (const source of one.from) {
|
|
2462
|
+
const spelled = JSON.stringify(source);
|
|
2463
|
+
if (!seen.has(spelled)) {
|
|
2464
|
+
seen.add(spelled);
|
|
2465
|
+
entry.from.push(source);
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
return [...bySlot.values()].sort(
|
|
2470
|
+
(a, b) => a.at.effect - b.at.effect || a.at.slot.localeCompare(b.at.slot) || a.at.name.localeCompare(b.at.name)
|
|
2471
|
+
);
|
|
2472
|
+
}
|
|
2043
2473
|
function withNormalizedCallee(effect) {
|
|
2044
2474
|
if (effect.type !== "invocation" && effect.type !== "interaction") {
|
|
2045
2475
|
return effect;
|
|
@@ -2055,17 +2485,22 @@ function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
|
2055
2485
|
const conditions = branch.conditions.map(
|
|
2056
2486
|
rawConditionToPredicate
|
|
2057
2487
|
);
|
|
2488
|
+
const effects = effectsOfBranch(branch);
|
|
2058
2489
|
const transition = {
|
|
2059
2490
|
id: makeTransitionId(raw.identity.name, branch),
|
|
2060
2491
|
conditions,
|
|
2061
2492
|
output: terminalToOutput(branch.terminal),
|
|
2062
|
-
effects
|
|
2493
|
+
effects,
|
|
2063
2494
|
location: branch.location,
|
|
2064
2495
|
isDefault: branch.isDefault
|
|
2065
2496
|
};
|
|
2066
2497
|
if (branch.expectedInput != null) {
|
|
2067
2498
|
transition.expectedInput = branch.expectedInput;
|
|
2068
2499
|
}
|
|
2500
|
+
const provenance = provenanceOf(branch.provenance ?? [], effects);
|
|
2501
|
+
if (provenance.length > 0) {
|
|
2502
|
+
transition.provenance = provenance;
|
|
2503
|
+
}
|
|
2069
2504
|
return transition;
|
|
2070
2505
|
});
|
|
2071
2506
|
const gaps = detectGaps(raw, transitions, options);
|
|
@@ -2127,6 +2562,9 @@ function buildMetadata(raw) {
|
|
|
2127
2562
|
if (raw.requestSpelling !== void 0) {
|
|
2128
2563
|
metadata = withRequestSpellingMetadata(metadata, raw.requestSpelling);
|
|
2129
2564
|
}
|
|
2565
|
+
if (raw.test !== void 0) {
|
|
2566
|
+
metadata = withTestMetadata(metadata, raw.test);
|
|
2567
|
+
}
|
|
2130
2568
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
2131
2569
|
}
|
|
2132
2570
|
function buildHttpMetadataValue(raw) {
|
|
@@ -2270,18 +2708,27 @@ function bodyToShape(body) {
|
|
|
2270
2708
|
}
|
|
2271
2709
|
return null;
|
|
2272
2710
|
}
|
|
2711
|
+
function statusValueRef(code) {
|
|
2712
|
+
if (code === null) {
|
|
2713
|
+
return null;
|
|
2714
|
+
}
|
|
2715
|
+
return code.type === "literal" ? { type: "literal", value: code.value } : { type: "unresolved", sourceText: code.sourceText };
|
|
2716
|
+
}
|
|
2273
2717
|
var terminalConverters = {
|
|
2274
2718
|
response: (t) => {
|
|
2275
|
-
const statusCode = t.statusCode ? t.statusCode.type === "literal" ? { type: "literal", value: t.statusCode.value } : { type: "unresolved", sourceText: t.statusCode.sourceText } : null;
|
|
2276
2719
|
const body = bodyToShape(t.body);
|
|
2277
|
-
return {
|
|
2720
|
+
return {
|
|
2721
|
+
type: "response",
|
|
2722
|
+
statusCode: statusValueRef(t.statusCode),
|
|
2723
|
+
body,
|
|
2724
|
+
headers: {}
|
|
2725
|
+
};
|
|
2278
2726
|
},
|
|
2279
2727
|
throw: (t) => {
|
|
2280
2728
|
if (t.statusCode && t.producesResponse === true) {
|
|
2281
|
-
const statusCode = t.statusCode.type === "literal" ? { type: "literal", value: t.statusCode.value } : { type: "unresolved", sourceText: t.statusCode.sourceText };
|
|
2282
2729
|
return {
|
|
2283
2730
|
type: "response",
|
|
2284
|
-
statusCode,
|
|
2731
|
+
statusCode: statusValueRef(t.statusCode),
|
|
2285
2732
|
body: bodyToShape(t.body),
|
|
2286
2733
|
headers: {}
|
|
2287
2734
|
};
|
|
@@ -2309,7 +2756,8 @@ var terminalConverters = {
|
|
|
2309
2756
|
type: "return",
|
|
2310
2757
|
value: bodyToShape(t.body)
|
|
2311
2758
|
}),
|
|
2312
|
-
void: (_t) => ({ type: "void" })
|
|
2759
|
+
void: (_t) => ({ type: "void" }),
|
|
2760
|
+
exit: (t) => ({ type: "exit", code: statusValueRef(t.statusCode) })
|
|
2313
2761
|
};
|
|
2314
2762
|
function terminalToOutput(terminal) {
|
|
2315
2763
|
return terminalConverters[terminal.kind](terminal);
|
|
@@ -2352,14 +2800,18 @@ function paramToInput(param) {
|
|
|
2352
2800
|
name: param.name,
|
|
2353
2801
|
position: param.position,
|
|
2354
2802
|
role: param.role,
|
|
2803
|
+
...param.field === void 0 ? {} : { field: param.field },
|
|
2355
2804
|
shape: param.typeText ? { type: "ref", name: param.typeText } : null
|
|
2356
2805
|
};
|
|
2357
2806
|
}
|
|
2358
2807
|
export {
|
|
2808
|
+
EnclosingNodes,
|
|
2359
2809
|
IdMap,
|
|
2360
2810
|
IdSet,
|
|
2811
|
+
KeptParses,
|
|
2361
2812
|
MAX_ENTRIES,
|
|
2362
2813
|
MAX_PATHS,
|
|
2814
|
+
MODULE_SURFACE_RECOGNITION,
|
|
2363
2815
|
PathBudgetExceeded,
|
|
2364
2816
|
SKIP_CHILDREN,
|
|
2365
2817
|
UnmodeledFlow,
|
|
@@ -2384,13 +2836,18 @@ export {
|
|
|
2384
2836
|
enumerateOrDegrade,
|
|
2385
2837
|
enumerateStructuredPaths,
|
|
2386
2838
|
evaluatePackHealth,
|
|
2839
|
+
extractionConfigStamp,
|
|
2387
2840
|
firstWrittenReading,
|
|
2388
2841
|
formatPackHealth,
|
|
2389
2842
|
guardsHoldOn,
|
|
2390
2843
|
httpRouteDiscovery,
|
|
2844
|
+
isListedTestFile,
|
|
2391
2845
|
makeTransitionId,
|
|
2392
2846
|
mapReading,
|
|
2847
|
+
markReturnsAsExitCode,
|
|
2848
|
+
matchesTestFileName,
|
|
2393
2849
|
moduleInitStructure,
|
|
2850
|
+
moduleOfFile,
|
|
2394
2851
|
noopTimer,
|
|
2395
2852
|
packGradients,
|
|
2396
2853
|
paramToInput,
|
|
@@ -2402,8 +2859,12 @@ export {
|
|
|
2402
2859
|
runDigest,
|
|
2403
2860
|
runsBefore,
|
|
2404
2861
|
scopeOption,
|
|
2862
|
+
settleModules,
|
|
2405
2863
|
sharedGatingConditions,
|
|
2864
|
+
sourceRefsOf,
|
|
2865
|
+
stampMayMissAWrite,
|
|
2406
2866
|
stampModuleImports,
|
|
2867
|
+
stampModules,
|
|
2407
2868
|
storageSystemOption,
|
|
2408
2869
|
summaryCountsByPack,
|
|
2409
2870
|
tallyUnit,
|