@suss/extractor 0.33.1 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.cjs +982 -225
- package/dist/index.d.cts +1335 -936
- package/dist/index.d.ts +1335 -936
- package/dist/index.js +952 -212
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -30,10 +30,14 @@ 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,
|
|
38
|
+
MAX_HELPER_PATHS: () => MAX_HELPER_PATHS,
|
|
36
39
|
MAX_PATHS: () => MAX_PATHS,
|
|
40
|
+
MODULE_SURFACE_RECOGNITION: () => MODULE_SURFACE_RECOGNITION,
|
|
37
41
|
PathBudgetExceeded: () => PathBudgetExceeded,
|
|
38
42
|
SKIP_CHILDREN: () => SKIP_CHILDREN,
|
|
39
43
|
UnmodeledFlow: () => UnmodeledFlow,
|
|
@@ -58,30 +62,45 @@ __export(index_exports, {
|
|
|
58
62
|
enumerateOrDegrade: () => enumerateOrDegrade,
|
|
59
63
|
enumerateStructuredPaths: () => enumerateStructuredPaths,
|
|
60
64
|
evaluatePackHealth: () => evaluatePackHealth,
|
|
65
|
+
extractionConfigStamp: () => extractionConfigStamp,
|
|
61
66
|
firstWrittenReading: () => firstWrittenReading,
|
|
62
67
|
formatPackHealth: () => formatPackHealth,
|
|
63
68
|
guardsHoldOn: () => guardsHoldOn,
|
|
69
|
+
helperPathsOnVariables: () => helperPathsOnVariables,
|
|
64
70
|
httpRouteDiscovery: () => httpRouteDiscovery,
|
|
71
|
+
isListedTestFile: () => isListedTestFile,
|
|
72
|
+
makeIgnoredDirectory: () => makeIgnoredDirectory,
|
|
65
73
|
makeTransitionId: () => makeTransitionId,
|
|
66
74
|
mapReading: () => mapReading,
|
|
75
|
+
markReturnsAsExitCode: () => markReturnsAsExitCode,
|
|
76
|
+
matchesTestFileName: () => matchesTestFileName,
|
|
77
|
+
mergeReadShapes: () => mergeReadShapes,
|
|
67
78
|
moduleInitStructure: () => moduleInitStructure,
|
|
79
|
+
moduleOfFile: () => moduleOfFile,
|
|
68
80
|
noopTimer: () => noopTimer,
|
|
69
81
|
packGradients: () => packGradients,
|
|
70
82
|
paramToInput: () => paramToInput,
|
|
71
83
|
projectFileStamp: () => projectFileStamp,
|
|
72
84
|
rawConditionToPredicate: () => rawConditionToPredicate,
|
|
73
85
|
recordPackFailure: () => recordPackFailure,
|
|
86
|
+
redirectDeliveryWhenSet: () => redirectDeliveryWhenSet,
|
|
74
87
|
registrationHelperDiscovery: () => registrationHelperDiscovery,
|
|
75
88
|
routeHelperIndex: () => routeHelperIndex,
|
|
76
89
|
runDigest: () => runDigest,
|
|
77
90
|
runsBefore: () => runsBefore,
|
|
78
91
|
scopeOption: () => scopeOption,
|
|
92
|
+
settleModules: () => settleModules,
|
|
79
93
|
sharedGatingConditions: () => sharedGatingConditions,
|
|
94
|
+
sourceRefsOf: () => sourceRefsOf,
|
|
95
|
+
splitAtHandOffs: () => splitAtHandOffs,
|
|
96
|
+
stampMayMissAWrite: () => stampMayMissAWrite,
|
|
80
97
|
stampModuleImports: () => stampModuleImports,
|
|
98
|
+
stampModules: () => stampModules,
|
|
81
99
|
storageSystemOption: () => storageSystemOption,
|
|
82
100
|
summaryCountsByPack: () => summaryCountsByPack,
|
|
83
101
|
tallyUnit: () => tallyUnit,
|
|
84
102
|
terminalToOutput: () => terminalToOutput,
|
|
103
|
+
throughHelper: () => throughHelper,
|
|
85
104
|
unreadableReading: () => unreadableReading,
|
|
86
105
|
unwrapJsonStringify: () => unwrapJsonStringify,
|
|
87
106
|
valueToReadFurtherFrom: () => valueToReadFurtherFrom,
|
|
@@ -90,8 +109,8 @@ __export(index_exports, {
|
|
|
90
109
|
writtenReading: () => writtenReading
|
|
91
110
|
});
|
|
92
111
|
module.exports = __toCommonJS(index_exports);
|
|
93
|
-
var
|
|
94
|
-
var
|
|
112
|
+
var import_node_crypto4 = require("crypto");
|
|
113
|
+
var import_behavioral_ir7 = require("@suss/behavioral-ir");
|
|
95
114
|
|
|
96
115
|
// src/contractStatusGaps.ts
|
|
97
116
|
var import_behavioral_ir = require("@suss/behavioral-ir");
|
|
@@ -270,29 +289,82 @@ function composeOne(summary, chain, keepGaps) {
|
|
|
270
289
|
if (wrappers.length === 0) {
|
|
271
290
|
return narrowed;
|
|
272
291
|
}
|
|
273
|
-
const responses = respondedInstead(wrappers);
|
|
274
|
-
const
|
|
275
|
-
const
|
|
292
|
+
const responses = settledUncaught(respondedInstead(wrappers), wrappers);
|
|
293
|
+
const unitOwn = settledUncaught(summary.transitions, wrappers);
|
|
294
|
+
const own = [...responses, ...unitOwn];
|
|
295
|
+
const handled = handledThrows(wrappers, thrownBy(own));
|
|
296
|
+
const transitions = beside(summary, unitOwn, responses, handled);
|
|
276
297
|
if (!keepGaps) {
|
|
277
298
|
return transitions === summary.transitions ? narrowed : { ...narrowed, transitions };
|
|
278
299
|
}
|
|
279
300
|
const gaps = withContractStatusGaps(
|
|
280
301
|
summary,
|
|
281
|
-
|
|
282
|
-
|
|
302
|
+
own,
|
|
303
|
+
everyHandlerOutcome(wrappers)
|
|
283
304
|
);
|
|
284
305
|
if (transitions === summary.transitions && gaps === summary.gaps) {
|
|
285
306
|
return narrowed;
|
|
286
307
|
}
|
|
287
308
|
return { ...narrowed, transitions, gaps };
|
|
288
309
|
}
|
|
289
|
-
function beside(summary, responses, handled) {
|
|
290
|
-
|
|
291
|
-
const onThrow = throws ? handled : [];
|
|
292
|
-
if (responses.length === 0 && onThrow.length === 0) {
|
|
310
|
+
function beside(summary, unitOwn, responses, handled) {
|
|
311
|
+
if (responses.length === 0 && handled.length === 0 && unitOwn === summary.transitions) {
|
|
293
312
|
return summary.transitions;
|
|
294
313
|
}
|
|
295
|
-
return withDistinctIds([...responses, ...
|
|
314
|
+
return withDistinctIds([...responses, ...unitOwn, ...handled]);
|
|
315
|
+
}
|
|
316
|
+
function settledUncaught(transitions, wrappers) {
|
|
317
|
+
const handlers = wrappers.filter(
|
|
318
|
+
(wrapper) => wrapper.reference.onThrow === true
|
|
319
|
+
);
|
|
320
|
+
let changed = false;
|
|
321
|
+
const settled = transitions.flatMap((transition) => {
|
|
322
|
+
const { output } = transition;
|
|
323
|
+
if (output.type !== "throw") {
|
|
324
|
+
return [transition];
|
|
325
|
+
}
|
|
326
|
+
const caught = caughtOnRoute(handlers, output);
|
|
327
|
+
if (caught === "sure") {
|
|
328
|
+
changed = true;
|
|
329
|
+
return [markedCaught(transition)];
|
|
330
|
+
}
|
|
331
|
+
if (output.statusWhenUncaught === void 0) {
|
|
332
|
+
return [transition];
|
|
333
|
+
}
|
|
334
|
+
changed = true;
|
|
335
|
+
const response = {
|
|
336
|
+
...transition,
|
|
337
|
+
output: {
|
|
338
|
+
type: "response",
|
|
339
|
+
statusCode: { type: "literal", value: output.statusWhenUncaught },
|
|
340
|
+
body: null,
|
|
341
|
+
headers: {}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
return caught === "uncertain" ? [transition, response] : [response];
|
|
345
|
+
});
|
|
346
|
+
return changed ? settled : transitions;
|
|
347
|
+
}
|
|
348
|
+
function markedCaught(transition) {
|
|
349
|
+
return {
|
|
350
|
+
...transition,
|
|
351
|
+
metadata: (0, import_behavioral_ir2.withWrapperMetadata)(transition.metadata, {
|
|
352
|
+
...(0, import_behavioral_ir2.readWrapperMetadata)(transition),
|
|
353
|
+
caught: true
|
|
354
|
+
})
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function caughtOnRoute(handlers, thrown) {
|
|
358
|
+
if (handlers.some((handler) => handler.reference.catches === void 0)) {
|
|
359
|
+
return "sure";
|
|
360
|
+
}
|
|
361
|
+
const matches = handlers.map(
|
|
362
|
+
(handler) => catchMatch(handler.reference, thrown)
|
|
363
|
+
);
|
|
364
|
+
if (matches.includes("yes")) {
|
|
365
|
+
return "sure";
|
|
366
|
+
}
|
|
367
|
+
return matches.includes("maybe") ? "uncertain" : "no";
|
|
296
368
|
}
|
|
297
369
|
function respondedInstead(wrappers) {
|
|
298
370
|
return wrappers.flatMap(
|
|
@@ -304,11 +376,91 @@ function respondedInstead(wrappers) {
|
|
|
304
376
|
)
|
|
305
377
|
);
|
|
306
378
|
}
|
|
307
|
-
function
|
|
379
|
+
function thrownBy(transitions) {
|
|
380
|
+
return transitions.flatMap(
|
|
381
|
+
(t) => t.output.type === "throw" ? [t.output] : []
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
function everyHandlerOutcome(wrappers) {
|
|
308
385
|
return wrappers.flatMap(
|
|
309
386
|
(wrapper) => wrapper.reference.onThrow === true ? attribute(wrapper.summary.transitions, wrapper.reference) : []
|
|
310
387
|
);
|
|
311
388
|
}
|
|
389
|
+
function handledThrows(wrappers, thrown) {
|
|
390
|
+
const caught = catchesAny(wrappers, thrown);
|
|
391
|
+
return [...oncePerHandler(wrappers, caught)].flatMap(
|
|
392
|
+
([wrapper, how]) => attribute(
|
|
393
|
+
wrapper.summary.transitions,
|
|
394
|
+
wrapper.reference,
|
|
395
|
+
how === "uncertain"
|
|
396
|
+
)
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
function oncePerHandler(wrappers, caught) {
|
|
400
|
+
const byHandler = /* @__PURE__ */ new Map();
|
|
401
|
+
for (const wrapper of wrappers) {
|
|
402
|
+
const how = caught.get(wrapper);
|
|
403
|
+
if (how === void 0) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
const earlier = byHandler.get(wrapper.summary);
|
|
407
|
+
if (earlier === void 0 || earlier[1] === "uncertain" && how === "sure") {
|
|
408
|
+
byHandler.set(wrapper.summary, [wrapper, how]);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return new Map(byHandler.values());
|
|
412
|
+
}
|
|
413
|
+
function catchesAny(wrappers, thrown) {
|
|
414
|
+
const caught = /* @__PURE__ */ new Map();
|
|
415
|
+
if (thrown.length === 0) {
|
|
416
|
+
return caught;
|
|
417
|
+
}
|
|
418
|
+
const handlers = wrappers.filter(
|
|
419
|
+
(wrapper) => wrapper.reference.onThrow === true
|
|
420
|
+
);
|
|
421
|
+
for (const handler of handlers) {
|
|
422
|
+
if (handler.reference.catches === void 0) {
|
|
423
|
+
caught.set(handler, "sure");
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const listing = handlers.filter(
|
|
427
|
+
(handler) => handler.reference.catches !== void 0
|
|
428
|
+
);
|
|
429
|
+
for (const one of thrown) {
|
|
430
|
+
for (const [handler, how] of catchersOf(listing, one)) {
|
|
431
|
+
if (caught.get(handler) !== "sure") {
|
|
432
|
+
caught.set(handler, how);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return caught;
|
|
437
|
+
}
|
|
438
|
+
function catchersOf(handlers, thrown) {
|
|
439
|
+
const found = [];
|
|
440
|
+
for (const handler of handlers) {
|
|
441
|
+
const match = catchMatch(handler.reference, thrown);
|
|
442
|
+
if (match === "yes") {
|
|
443
|
+
found.push([handler, found.length === 0 ? "sure" : "uncertain"]);
|
|
444
|
+
return found;
|
|
445
|
+
}
|
|
446
|
+
if (match === "maybe") {
|
|
447
|
+
found.push([handler, "uncertain"]);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return found;
|
|
451
|
+
}
|
|
452
|
+
function catchMatch(reference, thrown) {
|
|
453
|
+
const ancestors = thrown.exceptionAncestors;
|
|
454
|
+
if (thrown.exceptionType === null || ancestors === void 0) {
|
|
455
|
+
return "maybe";
|
|
456
|
+
}
|
|
457
|
+
const classes = /* @__PURE__ */ new Set([thrown.exceptionType, ...ancestors]);
|
|
458
|
+
if ((reference.catches ?? []).some((name) => classes.has(name))) {
|
|
459
|
+
return "yes";
|
|
460
|
+
}
|
|
461
|
+
const unread = thrown.ancestryIncomplete === true && reference.mayCatchUnreadClasses === true;
|
|
462
|
+
return unread || reference.mayCatchAny === true ? "maybe" : "no";
|
|
463
|
+
}
|
|
312
464
|
function withContractStatusGaps(summary, composed, handled) {
|
|
313
465
|
const contract = (0, import_behavioral_ir2.readHttpMetadata)(summary)?.declaredContract;
|
|
314
466
|
const binding = summary.identity.boundaryBinding;
|
|
@@ -339,10 +491,13 @@ function coversUnit(reference, summary) {
|
|
|
339
491
|
const binding = summary.identity.boundaryBinding;
|
|
340
492
|
return binding !== null && (0, import_behavioral_ir2.withinScope)(binding, reference.scope);
|
|
341
493
|
}
|
|
342
|
-
function attribute(transitions, reference) {
|
|
494
|
+
function attribute(transitions, reference, catchUncertain = false) {
|
|
343
495
|
return transitions.map((transition) => ({
|
|
344
496
|
...transition,
|
|
345
|
-
metadata: (0, import_behavioral_ir2.withWrapperMetadata)(transition.metadata, {
|
|
497
|
+
metadata: (0, import_behavioral_ir2.withWrapperMetadata)(transition.metadata, {
|
|
498
|
+
from: reference,
|
|
499
|
+
...catchUncertain ? { catchUncertain } : {}
|
|
500
|
+
})
|
|
346
501
|
}));
|
|
347
502
|
}
|
|
348
503
|
function withDistinctIds(transitions) {
|
|
@@ -354,6 +509,56 @@ function withDistinctIds(transitions) {
|
|
|
354
509
|
});
|
|
355
510
|
}
|
|
356
511
|
|
|
512
|
+
// src/declaredModules.ts
|
|
513
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
514
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
515
|
+
var MODULE_SURFACE_RECOGNITION = "modules";
|
|
516
|
+
function settleModules(modules, candidates) {
|
|
517
|
+
return (modules ?? []).map((module2) => ({
|
|
518
|
+
...module2,
|
|
519
|
+
public: module2.public ?? candidates.map(
|
|
520
|
+
(one) => import_node_path.default.join(module2.root, one.replace("{name}", module2.name))
|
|
521
|
+
).filter((file) => import_node_fs.default.existsSync(file))
|
|
522
|
+
}));
|
|
523
|
+
}
|
|
524
|
+
function isInside(file, root) {
|
|
525
|
+
const relative = import_node_path.default.relative(root, file);
|
|
526
|
+
return relative !== "" && !relative.startsWith("..") && !import_node_path.default.isAbsolute(relative);
|
|
527
|
+
}
|
|
528
|
+
function moduleOfFile(modules, file) {
|
|
529
|
+
const byPublicFile = modules.find((module2) => module2.public.includes(file));
|
|
530
|
+
if (byPublicFile !== void 0) {
|
|
531
|
+
return byPublicFile;
|
|
532
|
+
}
|
|
533
|
+
let deepest;
|
|
534
|
+
for (const module2 of modules) {
|
|
535
|
+
if (isInside(file, module2.root) && (deepest === void 0 || module2.root.length > deepest.root.length)) {
|
|
536
|
+
deepest = module2;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return deepest;
|
|
540
|
+
}
|
|
541
|
+
function stampModules(summaries, modules, root) {
|
|
542
|
+
if (modules.length === 0) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
for (const summary of summaries) {
|
|
546
|
+
const file = import_node_path.default.resolve(root ?? "", summary.location.file);
|
|
547
|
+
const module2 = moduleOfFile(modules, file);
|
|
548
|
+
if (module2 !== void 0) {
|
|
549
|
+
summary.location.module = module2.name;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
function modulesStamp(modules) {
|
|
554
|
+
if (modules === void 0 || modules.length === 0) {
|
|
555
|
+
return void 0;
|
|
556
|
+
}
|
|
557
|
+
return JSON.stringify(
|
|
558
|
+
modules.map((module2) => [module2.name, module2.root, [...module2.public]])
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
|
|
357
562
|
// src/effectGuards.ts
|
|
358
563
|
var keyOf = (condition) => `${condition.polarity}:${condition.sourceText}`;
|
|
359
564
|
var opposite = (condition) => `${condition.polarity === "positive" ? "negative" : "positive"}:${condition.sourceText}`;
|
|
@@ -370,6 +575,139 @@ function runsBefore(effectLine, terminalEndLine) {
|
|
|
370
575
|
return effectLine <= terminalEndLine;
|
|
371
576
|
}
|
|
372
577
|
|
|
578
|
+
// src/exitCode.ts
|
|
579
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
580
|
+
var import_behavioral_ir3 = require("@suss/behavioral-ir");
|
|
581
|
+
function markReturnsAsExitCode(summaries, returnsTheCode, workspaceRoot) {
|
|
582
|
+
for (const summary of summaries) {
|
|
583
|
+
const span = summary.location.span;
|
|
584
|
+
const file = workspaceRoot === void 0 ? summary.location.file : import_node_path2.default.resolve(workspaceRoot, summary.location.file);
|
|
585
|
+
markExitCodeFrom(
|
|
586
|
+
summary,
|
|
587
|
+
span !== void 0 && returnsTheCode.has((0, import_behavioral_ir3.declarationKey)(file, span))
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function markExitCodeFrom(summary, marked) {
|
|
592
|
+
const process2 = summary.metadata?.process;
|
|
593
|
+
if (marked) {
|
|
594
|
+
summary.metadata = {
|
|
595
|
+
...summary.metadata ?? {},
|
|
596
|
+
process: { ...process2 ?? {}, exitCodeFrom: "return" }
|
|
597
|
+
};
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (process2 === void 0 || !("exitCodeFrom" in process2)) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
const { exitCodeFrom: _dropped, ...rest } = process2;
|
|
604
|
+
const { process: _process, ...others } = summary.metadata ?? {};
|
|
605
|
+
const left = Object.keys(rest).length === 0 ? others : { ...others, process: rest };
|
|
606
|
+
if (Object.keys(left).length === 0) {
|
|
607
|
+
Reflect.deleteProperty(summary, "metadata");
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
summary.metadata = left;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/helperHandOff.ts
|
|
614
|
+
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
615
|
+
var MAX_HELPER_PATHS = 16;
|
|
616
|
+
function throughHelper(branch, at, helperBranches) {
|
|
617
|
+
return helperBranches.map((helper) => {
|
|
618
|
+
const conditions = [...branch.conditions, ...helper.conditions];
|
|
619
|
+
const expectedInput = mergeReadShapes(
|
|
620
|
+
branch.expectedInput ?? null,
|
|
621
|
+
helper.expectedInput ?? null
|
|
622
|
+
);
|
|
623
|
+
const reads = expectedInput === null ? {} : { expectedInput };
|
|
624
|
+
if (helper.terminal.kind !== "throw" && helper.terminal.kind !== "exit") {
|
|
625
|
+
return {
|
|
626
|
+
...branch,
|
|
627
|
+
...reads,
|
|
628
|
+
conditions,
|
|
629
|
+
isDefault: branch.isDefault && helper.isDefault
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
return {
|
|
633
|
+
...branch,
|
|
634
|
+
...reads,
|
|
635
|
+
conditions,
|
|
636
|
+
terminal: { ...helper.terminal, location: at },
|
|
637
|
+
location: at,
|
|
638
|
+
isDefault: false
|
|
639
|
+
};
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
function mergeReadShapes(a, b) {
|
|
643
|
+
if (a === null || b === null) {
|
|
644
|
+
return a ?? b;
|
|
645
|
+
}
|
|
646
|
+
if (a.type !== "record" || b.type !== "record") {
|
|
647
|
+
return a.type === "record" ? a : b;
|
|
648
|
+
}
|
|
649
|
+
const properties = { ...a.properties };
|
|
650
|
+
for (const [name, shape] of Object.entries(b.properties)) {
|
|
651
|
+
const known = properties[name];
|
|
652
|
+
properties[name] = known === void 0 ? shape : mergeReadShapes(known, shape) ?? shape;
|
|
653
|
+
}
|
|
654
|
+
return { ...a, properties };
|
|
655
|
+
}
|
|
656
|
+
function splitAtHandOffs(branch, sites, from = 0) {
|
|
657
|
+
for (let index = from; index < sites.length; index++) {
|
|
658
|
+
const site = sites[index];
|
|
659
|
+
const reached = site.alwaysRuns === true || runsBefore(site.line, branch.terminal.location.end);
|
|
660
|
+
if (!reached || !guardsHoldOn(site.preconditions, branch.conditions)) {
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
return throughHelper(branch, site.at, site.helper).flatMap(
|
|
664
|
+
(path7) => path7.terminal === branch.terminal ? splitAtHandOffs(path7, sites, index + 1) : [path7]
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
return [branch];
|
|
668
|
+
}
|
|
669
|
+
function helperPathsOnVariables(helperBranches, passed) {
|
|
670
|
+
const renamed = helperBranches.map((branch) => ({
|
|
671
|
+
...branch,
|
|
672
|
+
conditions: branch.conditions.map((condition) => ({
|
|
673
|
+
...condition,
|
|
674
|
+
structured: condition.structured === null ? null : onCallerVariables(condition.structured, passed)
|
|
675
|
+
}))
|
|
676
|
+
}));
|
|
677
|
+
const variables = new Set(passed.values());
|
|
678
|
+
const testsWhatItGot = renamed.some(
|
|
679
|
+
(branch) => branch.conditions.some(
|
|
680
|
+
(condition) => condition.structured !== null && (0, import_behavioral_ir4.predicateRefs)(condition.structured).some(
|
|
681
|
+
(ref) => variables.has(rootName(ref) ?? "")
|
|
682
|
+
)
|
|
683
|
+
)
|
|
684
|
+
);
|
|
685
|
+
return testsWhatItGot && renamed.length <= MAX_HELPER_PATHS ? renamed : null;
|
|
686
|
+
}
|
|
687
|
+
function onCallerVariables(predicate, passed) {
|
|
688
|
+
const rename = (ref) => {
|
|
689
|
+
if (ref.type === "derived") {
|
|
690
|
+
return { ...ref, from: rename(ref.from) };
|
|
691
|
+
}
|
|
692
|
+
if (ref.type === "input") {
|
|
693
|
+
const name = passed.get(ref.inputRef);
|
|
694
|
+
return name === void 0 ? ref : { type: "dependency", name, accessChain: ref.path };
|
|
695
|
+
}
|
|
696
|
+
if (ref.type === "dependency") {
|
|
697
|
+
const name = passed.get(ref.name);
|
|
698
|
+
return name === void 0 ? ref : { ...ref, name };
|
|
699
|
+
}
|
|
700
|
+
return ref;
|
|
701
|
+
};
|
|
702
|
+
return (0, import_behavioral_ir4.replacePredicateRefs)(predicate, rename);
|
|
703
|
+
}
|
|
704
|
+
function rootName(ref) {
|
|
705
|
+
if (ref.type === "derived") {
|
|
706
|
+
return rootName(ref.from);
|
|
707
|
+
}
|
|
708
|
+
return ref.type === "dependency" ? ref.name : null;
|
|
709
|
+
}
|
|
710
|
+
|
|
373
711
|
// src/moduleImports.ts
|
|
374
712
|
function stampModuleImports(summaries, importsOf) {
|
|
375
713
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -446,8 +784,8 @@ function httpRouteDiscovery(opts) {
|
|
|
446
784
|
registrationChain: [...opts.methods]
|
|
447
785
|
},
|
|
448
786
|
bindingExtraction: {
|
|
449
|
-
// `.all` registers every method, so it records "*", which
|
|
450
|
-
//
|
|
787
|
+
// `.all` registers every method, so it records "*", which pairs with
|
|
788
|
+
// any method.
|
|
451
789
|
method: {
|
|
452
790
|
type: "fromRegistration",
|
|
453
791
|
position: "methodName",
|
|
@@ -463,10 +801,9 @@ function httpRouteDiscovery(opts) {
|
|
|
463
801
|
}
|
|
464
802
|
return [
|
|
465
803
|
...calls,
|
|
466
|
-
// Routes registered in a loop over an array of specs,
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
// never touches this library's routable is left alone.
|
|
804
|
+
// Routes registered in a loop over an array of specs, which the calls
|
|
805
|
+
// above cannot see. The receiver must come from the same import, so a
|
|
806
|
+
// loop that never touches this library's routable is left alone.
|
|
470
807
|
{
|
|
471
808
|
kind,
|
|
472
809
|
match: {
|
|
@@ -613,7 +950,7 @@ var configuredCallOption = import_zod.z.object({
|
|
|
613
950
|
receiver: import_zod.z.string(),
|
|
614
951
|
/** Method that performs the send. */
|
|
615
952
|
method: import_zod.z.string(),
|
|
616
|
-
/**
|
|
953
|
+
/** Index of the argument that is the subject. */
|
|
617
954
|
subjectArg: import_zod.z.number(),
|
|
618
955
|
/**
|
|
619
956
|
* Which argument the message body is. Left out when the method has no
|
|
@@ -624,7 +961,7 @@ var configuredCallOption = import_zod.z.object({
|
|
|
624
961
|
}).strict();
|
|
625
962
|
|
|
626
963
|
// src/paths/enumeratePaths.ts
|
|
627
|
-
var
|
|
964
|
+
var import_behavioral_ir5 = require("@suss/behavioral-ir");
|
|
628
965
|
var MAX_PATHS = 256;
|
|
629
966
|
var UnmodeledFlow = class extends Error {
|
|
630
967
|
};
|
|
@@ -668,12 +1005,12 @@ var loopCompletedCond = (headerText, exit) => fixedCond(
|
|
|
668
1005
|
exit === "throw" ? "earlyThrow" : "earlyReturn"
|
|
669
1006
|
);
|
|
670
1007
|
var catchEntryCond = () => fixedCond(
|
|
671
|
-
{ sourceText:
|
|
1008
|
+
{ sourceText: import_behavioral_ir5.CATCH_ENTRY_TEXT, expression: null },
|
|
672
1009
|
"positive",
|
|
673
1010
|
"catchBlock"
|
|
674
1011
|
);
|
|
675
|
-
function classify(
|
|
676
|
-
return
|
|
1012
|
+
function classify(path7, home, isAncestorOrSelf) {
|
|
1013
|
+
return path7.map((cond) => {
|
|
677
1014
|
if (cond.branchStmt === null) {
|
|
678
1015
|
return cond.info;
|
|
679
1016
|
}
|
|
@@ -738,9 +1075,16 @@ function chargeBudget(state) {
|
|
|
738
1075
|
);
|
|
739
1076
|
}
|
|
740
1077
|
}
|
|
741
|
-
function
|
|
1078
|
+
function limitOpenPaths(paths) {
|
|
1079
|
+
if (paths.length > MAX_PATHS) {
|
|
1080
|
+
throw new PathBudgetExceeded(
|
|
1081
|
+
`path budget exceeded, more than ${MAX_PATHS} paths`
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
function recordTerminal(ctx, terminal, home, path7) {
|
|
742
1086
|
chargeBudget(ctx.state);
|
|
743
|
-
const info = classify(
|
|
1087
|
+
const info = classify(path7, home, ctx.isAncestorOrSelf);
|
|
744
1088
|
const existing = ctx.state.byTerminal.get(terminal) ?? [];
|
|
745
1089
|
existing.push(info);
|
|
746
1090
|
ctx.state.byTerminal.set(terminal, existing);
|
|
@@ -751,15 +1095,15 @@ function containsTerminal(ctx, stmt) {
|
|
|
751
1095
|
}
|
|
752
1096
|
return childrenOf(stmt).some((child) => containsTerminal(ctx, child));
|
|
753
1097
|
}
|
|
754
|
-
function stepIf(stmt,
|
|
1098
|
+
function stepIf(stmt, path7, ctx) {
|
|
755
1099
|
const thenExit = exitKindOfList(stmt.thenBody);
|
|
756
1100
|
const elseExit = stmt.elseBody === null ? null : exitKindOfList(stmt.elseBody);
|
|
757
1101
|
const thenPath = [
|
|
758
|
-
...
|
|
1102
|
+
...path7,
|
|
759
1103
|
branchCond(stmt, stmt.condition, "positive", elseExit)
|
|
760
1104
|
];
|
|
761
1105
|
const elsePath = [
|
|
762
|
-
...
|
|
1106
|
+
...path7,
|
|
763
1107
|
branchCond(
|
|
764
1108
|
stmt,
|
|
765
1109
|
stmt.condition,
|
|
@@ -776,7 +1120,7 @@ function stepIf(stmt, path4, ctx) {
|
|
|
776
1120
|
}
|
|
777
1121
|
return out;
|
|
778
1122
|
}
|
|
779
|
-
function stepSwitch(stmt,
|
|
1123
|
+
function stepSwitch(stmt, path7, ctx) {
|
|
780
1124
|
const out = [];
|
|
781
1125
|
const negations = [];
|
|
782
1126
|
let defaultRanBody = false;
|
|
@@ -786,7 +1130,7 @@ function stepSwitch(stmt, path4, ctx) {
|
|
|
786
1130
|
if (hasStrayBreak(group.body)) {
|
|
787
1131
|
throw new UnmodeledFlow("non-trailing break in switch clause");
|
|
788
1132
|
}
|
|
789
|
-
const groupPath = group.condition === null ? [...
|
|
1133
|
+
const groupPath = group.condition === null ? [...path7, ...negations] : [...path7, fixedCond(group.condition, "positive", "explicit")];
|
|
790
1134
|
const conts = enumerate(ctx, group.body, groupPath);
|
|
791
1135
|
if (conts.length > 0) {
|
|
792
1136
|
if (!group.hasTrailingBreak && !fallthroughSafe) {
|
|
@@ -803,24 +1147,24 @@ function stepSwitch(stmt, path4, ctx) {
|
|
|
803
1147
|
}
|
|
804
1148
|
}
|
|
805
1149
|
if (!defaultRanBody) {
|
|
806
|
-
out.push([...
|
|
1150
|
+
out.push([...path7, ...negations]);
|
|
807
1151
|
}
|
|
808
1152
|
return out;
|
|
809
1153
|
}
|
|
810
|
-
function stepLoop(stmt,
|
|
1154
|
+
function stepLoop(stmt, path7, ctx) {
|
|
811
1155
|
const bodyExit = exitKindOfList(stmt.body);
|
|
812
1156
|
if (containsTerminal(ctx, stmt)) {
|
|
813
1157
|
enumerate(ctx, stmt.body, [
|
|
814
|
-
...
|
|
1158
|
+
...path7,
|
|
815
1159
|
loopIterationCond(stmt.condition.sourceText)
|
|
816
1160
|
]);
|
|
817
1161
|
}
|
|
818
1162
|
if (bodyExit !== null) {
|
|
819
|
-
return [[...
|
|
1163
|
+
return [[...path7, loopCompletedCond(stmt.condition.sourceText, bodyExit)]];
|
|
820
1164
|
}
|
|
821
|
-
return [
|
|
1165
|
+
return [path7];
|
|
822
1166
|
}
|
|
823
|
-
function stepTry(stmt,
|
|
1167
|
+
function stepTry(stmt, path7, ctx) {
|
|
824
1168
|
if (stmt.finallyBody !== null) {
|
|
825
1169
|
const finallyHasTerminal = stmt.finallyBody.some(
|
|
826
1170
|
(s) => containsTerminal(ctx, s)
|
|
@@ -830,22 +1174,22 @@ function stepTry(stmt, path4, ctx) {
|
|
|
830
1174
|
}
|
|
831
1175
|
}
|
|
832
1176
|
const out = [];
|
|
833
|
-
out.push(...enumerate(ctx, stmt.tryBody,
|
|
1177
|
+
out.push(...enumerate(ctx, stmt.tryBody, path7));
|
|
834
1178
|
if (stmt.catchBody !== null) {
|
|
835
|
-
const catchPath = [...
|
|
1179
|
+
const catchPath = [...path7, catchEntryCond()];
|
|
836
1180
|
out.push(...enumerate(ctx, stmt.catchBody, catchPath));
|
|
837
1181
|
}
|
|
838
1182
|
return out;
|
|
839
1183
|
}
|
|
840
|
-
function stepExit(stmt,
|
|
1184
|
+
function stepExit(stmt, path7, ctx) {
|
|
841
1185
|
const collector = ctx.state.callbackExits[ctx.state.callbackExits.length - 1];
|
|
842
1186
|
if (collector !== void 0 && (stmt.exit === "return" || stmt.exit === "throw")) {
|
|
843
|
-
collector.push(
|
|
1187
|
+
collector.push(path7);
|
|
844
1188
|
}
|
|
845
1189
|
return [];
|
|
846
1190
|
}
|
|
847
|
-
function stepOpaque(_stmt,
|
|
848
|
-
return [
|
|
1191
|
+
function stepOpaque(_stmt, path7, _ctx) {
|
|
1192
|
+
return [path7];
|
|
849
1193
|
}
|
|
850
1194
|
var stepHandlers = {
|
|
851
1195
|
if: stepIf,
|
|
@@ -855,22 +1199,23 @@ var stepHandlers = {
|
|
|
855
1199
|
exit: stepExit,
|
|
856
1200
|
opaque: stepOpaque
|
|
857
1201
|
};
|
|
858
|
-
function stepCallback(ctx, body,
|
|
1202
|
+
function stepCallback(ctx, body, path7) {
|
|
859
1203
|
const exits = [];
|
|
860
1204
|
ctx.state.callbackExits.push(exits);
|
|
861
1205
|
let fellThrough;
|
|
862
1206
|
try {
|
|
863
|
-
fellThrough = enumerate(ctx, body,
|
|
1207
|
+
fellThrough = enumerate(ctx, body, path7);
|
|
864
1208
|
} finally {
|
|
865
1209
|
ctx.state.callbackExits.pop();
|
|
866
1210
|
}
|
|
867
1211
|
const out = [...fellThrough, ...exits];
|
|
868
|
-
return out.length === 0 ? [
|
|
1212
|
+
return out.length === 0 ? [path7] : out;
|
|
869
1213
|
}
|
|
870
|
-
function stepStatement(ctx, stmt,
|
|
871
|
-
let paths = [
|
|
1214
|
+
function stepStatement(ctx, stmt, path7) {
|
|
1215
|
+
let paths = [path7];
|
|
872
1216
|
for (const body of stmt.callbacks ?? []) {
|
|
873
1217
|
paths = paths.flatMap((each) => stepCallback(ctx, body, each));
|
|
1218
|
+
limitOpenPaths(paths);
|
|
874
1219
|
}
|
|
875
1220
|
const ownTerminals = ctx.terminalsByStmt.get(stmt) ?? [];
|
|
876
1221
|
for (const each of withRejoined(paths)) {
|
|
@@ -887,7 +1232,7 @@ function stepStatement(ctx, stmt, path4) {
|
|
|
887
1232
|
)
|
|
888
1233
|
);
|
|
889
1234
|
}
|
|
890
|
-
function soleDisagreement(left, right) {
|
|
1235
|
+
function soleDisagreement(left, right, keepsArms) {
|
|
891
1236
|
if (left.length !== right.length) {
|
|
892
1237
|
return null;
|
|
893
1238
|
}
|
|
@@ -906,9 +1251,10 @@ function soleDisagreement(left, right) {
|
|
|
906
1251
|
}
|
|
907
1252
|
found = at;
|
|
908
1253
|
}
|
|
909
|
-
|
|
1254
|
+
const test = found === null ? null : left[found]?.info.expression ?? null;
|
|
1255
|
+
return test !== null && keepsArms(test) ? null : found;
|
|
910
1256
|
}
|
|
911
|
-
function mergeRejoined(paths) {
|
|
1257
|
+
function mergeRejoined(paths, keepsArms = KEEPS_NO_ARMS) {
|
|
912
1258
|
let current = paths;
|
|
913
1259
|
for (let round = 0; round < current.length; round++) {
|
|
914
1260
|
const out = [];
|
|
@@ -923,7 +1269,11 @@ function mergeRejoined(paths) {
|
|
|
923
1269
|
if (taken.has(j)) {
|
|
924
1270
|
continue;
|
|
925
1271
|
}
|
|
926
|
-
const at = soleDisagreement(
|
|
1272
|
+
const at = soleDisagreement(
|
|
1273
|
+
combined,
|
|
1274
|
+
current[j],
|
|
1275
|
+
keepsArms
|
|
1276
|
+
);
|
|
927
1277
|
if (at === null) {
|
|
928
1278
|
continue;
|
|
929
1279
|
}
|
|
@@ -949,21 +1299,18 @@ function enumerate(ctx, stmts, prefix) {
|
|
|
949
1299
|
let frontiers = [[...prefix]];
|
|
950
1300
|
for (const stmt of stmts) {
|
|
951
1301
|
const nextFrontiers = [];
|
|
952
|
-
for (const
|
|
953
|
-
nextFrontiers.push(...stepStatement(ctx, stmt,
|
|
1302
|
+
for (const path7 of mergeRejoined(frontiers, ctx.keepsArms)) {
|
|
1303
|
+
nextFrontiers.push(...stepStatement(ctx, stmt, path7));
|
|
954
1304
|
}
|
|
955
1305
|
frontiers = nextFrontiers;
|
|
956
|
-
|
|
957
|
-
throw new PathBudgetExceeded(
|
|
958
|
-
`path budget exceeded, more than ${MAX_PATHS} paths`
|
|
959
|
-
);
|
|
960
|
-
}
|
|
1306
|
+
limitOpenPaths(frontiers);
|
|
961
1307
|
if (frontiers.length === 0) {
|
|
962
1308
|
break;
|
|
963
1309
|
}
|
|
964
1310
|
}
|
|
965
1311
|
return frontiers;
|
|
966
1312
|
}
|
|
1313
|
+
var KEEPS_NO_ARMS = () => false;
|
|
967
1314
|
function buildParentMap(statements) {
|
|
968
1315
|
const parentOf = /* @__PURE__ */ new Map();
|
|
969
1316
|
const visit = (stmt, parent) => {
|
|
@@ -997,13 +1344,14 @@ function enumerateStructuredPaths(input) {
|
|
|
997
1344
|
};
|
|
998
1345
|
const ctx = {
|
|
999
1346
|
terminalsByStmt: input.terminalsByStmt,
|
|
1347
|
+
keepsArms: input.keepsArms ?? KEEPS_NO_ARMS,
|
|
1000
1348
|
state,
|
|
1001
1349
|
isAncestorOrSelf
|
|
1002
1350
|
};
|
|
1003
1351
|
const continuations = withRejoined(enumerate(ctx, input.statements, []));
|
|
1004
|
-
for (const
|
|
1352
|
+
for (const path7 of continuations) {
|
|
1005
1353
|
chargeBudget(state);
|
|
1006
|
-
state.fallthrough.push(classify(
|
|
1354
|
+
state.fallthrough.push(classify(path7, null, isAncestorOrSelf));
|
|
1007
1355
|
}
|
|
1008
1356
|
return { byTerminal: state.byTerminal, fallthrough: state.fallthrough };
|
|
1009
1357
|
}
|
|
@@ -1046,8 +1394,8 @@ function sharedGatingConditions(paths, readPredicate) {
|
|
|
1046
1394
|
return [];
|
|
1047
1395
|
}
|
|
1048
1396
|
const shared = new Set(first.map(keyOf2));
|
|
1049
|
-
for (const
|
|
1050
|
-
const here = new Set(
|
|
1397
|
+
for (const path7 of rest) {
|
|
1398
|
+
const here = new Set(path7.map(keyOf2));
|
|
1051
1399
|
for (const value of shared) {
|
|
1052
1400
|
if (!here.has(value)) {
|
|
1053
1401
|
shared.delete(value);
|
|
@@ -1077,7 +1425,7 @@ var IdSet = class {
|
|
|
1077
1425
|
has(node) {
|
|
1078
1426
|
return this.byKey.has(node.id);
|
|
1079
1427
|
}
|
|
1080
|
-
/** The
|
|
1428
|
+
/** The wrapper that was added, which may be a different object from `node`. */
|
|
1081
1429
|
get(node) {
|
|
1082
1430
|
return this.byKey.get(node.id);
|
|
1083
1431
|
}
|
|
@@ -1108,39 +1456,81 @@ var IdMap = class {
|
|
|
1108
1456
|
}
|
|
1109
1457
|
};
|
|
1110
1458
|
|
|
1459
|
+
// src/paths/nodeReads.ts
|
|
1460
|
+
var EnclosingNodes = class {
|
|
1461
|
+
constructor(types) {
|
|
1462
|
+
this.types = types;
|
|
1463
|
+
}
|
|
1464
|
+
types;
|
|
1465
|
+
byTree = /* @__PURE__ */ new WeakMap();
|
|
1466
|
+
/**
|
|
1467
|
+
* The nearest ancestor of one of the types, or null when there is none.
|
|
1468
|
+
* Every node passed on the way up has the same result, so each one is
|
|
1469
|
+
* kept, and a later read from a sibling stops one step up.
|
|
1470
|
+
*/
|
|
1471
|
+
of(node) {
|
|
1472
|
+
const kept = this.keptFor(node.tree);
|
|
1473
|
+
const known = kept.get(node.id);
|
|
1474
|
+
if (known !== void 0) {
|
|
1475
|
+
return known;
|
|
1476
|
+
}
|
|
1477
|
+
const passed = [node.id];
|
|
1478
|
+
let current = node.parent;
|
|
1479
|
+
while (current !== null && !this.types.has(current.type)) {
|
|
1480
|
+
const above = kept.get(current.id);
|
|
1481
|
+
if (above !== void 0) {
|
|
1482
|
+
current = above;
|
|
1483
|
+
break;
|
|
1484
|
+
}
|
|
1485
|
+
passed.push(current.id);
|
|
1486
|
+
current = current.parent;
|
|
1487
|
+
}
|
|
1488
|
+
for (const id of passed) {
|
|
1489
|
+
kept.set(id, current);
|
|
1490
|
+
}
|
|
1491
|
+
return current;
|
|
1492
|
+
}
|
|
1493
|
+
keptFor(tree) {
|
|
1494
|
+
const known = this.byTree.get(tree);
|
|
1495
|
+
if (known !== void 0) {
|
|
1496
|
+
return known;
|
|
1497
|
+
}
|
|
1498
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
1499
|
+
this.byTree.set(tree, fresh);
|
|
1500
|
+
return fresh;
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
|
|
1111
1504
|
// src/paths/nodeWalk.ts
|
|
1112
1505
|
var SKIP_CHILDREN = /* @__PURE__ */ Symbol("skipChildren");
|
|
1113
|
-
function walkDescendants(root, carried, visitor) {
|
|
1114
|
-
for (const child of root
|
|
1115
|
-
if (child === null) {
|
|
1116
|
-
continue;
|
|
1117
|
-
}
|
|
1506
|
+
function walkDescendants(root, carried, childrenOf2, visitor) {
|
|
1507
|
+
for (const child of childrenOf2(root)) {
|
|
1118
1508
|
visitor.at(child, carried);
|
|
1119
1509
|
const inner = visitor.into(child, carried);
|
|
1120
1510
|
if (inner !== SKIP_CHILDREN) {
|
|
1121
|
-
walkDescendants(child, inner, visitor);
|
|
1511
|
+
walkDescendants(child, inner, childrenOf2, visitor);
|
|
1122
1512
|
}
|
|
1123
1513
|
}
|
|
1124
1514
|
}
|
|
1125
1515
|
|
|
1126
1516
|
// src/projectRoot.ts
|
|
1127
|
-
var
|
|
1517
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
1128
1518
|
function commonDirectoryOf(files) {
|
|
1129
|
-
const absolute = files.filter((f) =>
|
|
1519
|
+
const absolute = files.filter((f) => import_node_path3.default.isAbsolute(f));
|
|
1130
1520
|
const first = absolute[0];
|
|
1131
1521
|
if (first === void 0) {
|
|
1132
1522
|
return void 0;
|
|
1133
1523
|
}
|
|
1134
|
-
let shared =
|
|
1524
|
+
let shared = import_node_path3.default.dirname(first).split(import_node_path3.default.sep);
|
|
1135
1525
|
for (const file of absolute.slice(1)) {
|
|
1136
|
-
const parts =
|
|
1526
|
+
const parts = import_node_path3.default.dirname(file).split(import_node_path3.default.sep);
|
|
1137
1527
|
let i = 0;
|
|
1138
1528
|
while (i < shared.length && i < parts.length && shared[i] === parts[i]) {
|
|
1139
1529
|
i += 1;
|
|
1140
1530
|
}
|
|
1141
1531
|
shared = shared.slice(0, i);
|
|
1142
1532
|
}
|
|
1143
|
-
const joined = shared.join(
|
|
1533
|
+
const joined = shared.join(import_node_path3.default.sep);
|
|
1144
1534
|
return joined.length > 1 ? joined : void 0;
|
|
1145
1535
|
}
|
|
1146
1536
|
|
|
@@ -1197,11 +1587,84 @@ function valueToReadFurtherFrom(reading) {
|
|
|
1197
1587
|
return reading.kind === "written" ? reading.value : null;
|
|
1198
1588
|
}
|
|
1199
1589
|
|
|
1590
|
+
// src/redirectOption.ts
|
|
1591
|
+
function redirectDeliveryWhenSet(option, value) {
|
|
1592
|
+
return option.handsBack.includes(value) ? "response" : "followed";
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// src/testFiles.ts
|
|
1596
|
+
function isListedTestFile(file, listed) {
|
|
1597
|
+
if (listed === void 0) {
|
|
1598
|
+
return true;
|
|
1599
|
+
}
|
|
1600
|
+
const whole = withForwardSlashes(file);
|
|
1601
|
+
return listed.some((entry) => {
|
|
1602
|
+
const tail = withForwardSlashes(entry).replace(/^\.\//, "");
|
|
1603
|
+
return whole === tail || whole.endsWith(`/${tail}`);
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
function matchesTestFileName(file, patterns) {
|
|
1607
|
+
const base = withForwardSlashes(file).split("/").pop() ?? "";
|
|
1608
|
+
return patterns.some((pattern) => globToRegExp(pattern).test(base));
|
|
1609
|
+
}
|
|
1610
|
+
function globToRegExp(pattern) {
|
|
1611
|
+
const escaped = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
1612
|
+
return new RegExp(`^${escaped}$`);
|
|
1613
|
+
}
|
|
1614
|
+
function withForwardSlashes(file) {
|
|
1615
|
+
return file.replace(/\\/g, "/");
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// src/valueSources.ts
|
|
1619
|
+
var QUOTED_LENGTH = 80;
|
|
1620
|
+
function sourceRefsOf(leaves, spelling) {
|
|
1621
|
+
const refs = [];
|
|
1622
|
+
const said = /* @__PURE__ */ new Set();
|
|
1623
|
+
for (const leaf of leaves) {
|
|
1624
|
+
const ref = convertedFrom(refOf(leaf, spelling), leaf.conversions);
|
|
1625
|
+
const spelled = JSON.stringify(ref);
|
|
1626
|
+
if (!said.has(spelled)) {
|
|
1627
|
+
said.add(spelled);
|
|
1628
|
+
refs.push(ref);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
return refs;
|
|
1632
|
+
}
|
|
1633
|
+
function convertedFrom(ref, conversions) {
|
|
1634
|
+
return conversions.reduceRight(
|
|
1635
|
+
(from, method) => ({
|
|
1636
|
+
type: "derived",
|
|
1637
|
+
from,
|
|
1638
|
+
derivation: { type: "methodCall", method, args: [] }
|
|
1639
|
+
}),
|
|
1640
|
+
ref
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1643
|
+
function refOf(leaf, spelling) {
|
|
1644
|
+
const whole = leaf.computedAt === null;
|
|
1645
|
+
const input = whole ? spelling.inputOf(leaf) : null;
|
|
1646
|
+
if (input !== null) {
|
|
1647
|
+
return input;
|
|
1648
|
+
}
|
|
1649
|
+
if (whole && leaf.end.is === "written" && leaf.path.length === 0) {
|
|
1650
|
+
const literal = spelling.literalAt(leaf.key);
|
|
1651
|
+
if (literal !== void 0) {
|
|
1652
|
+
return { type: "literal", value: literal };
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
const at = leaf.computedAt ?? leaf.key;
|
|
1656
|
+
return { type: "unresolved", sourceText: quoted(spelling.textAt(at), at) };
|
|
1657
|
+
}
|
|
1658
|
+
function quoted(text, key) {
|
|
1659
|
+
const written = (text ?? key.slice(key.lastIndexOf("#") + 1)).replace(/\s+/g, " ").trim();
|
|
1660
|
+
return written.length <= QUOTED_LENGTH ? written : `${written.slice(0, QUOTED_LENGTH - 3)}...`;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1200
1663
|
// src/adapterStamp.ts
|
|
1201
1664
|
var import_node_crypto = require("crypto");
|
|
1202
|
-
var
|
|
1665
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
1203
1666
|
var import_node_module = require("module");
|
|
1204
|
-
var
|
|
1667
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
1205
1668
|
var import_node_url = require("url");
|
|
1206
1669
|
var import_meta = {};
|
|
1207
1670
|
var ANALYSIS_PACKAGES = [
|
|
@@ -1244,16 +1707,16 @@ function createAdapterStamp(config) {
|
|
|
1244
1707
|
function readAdapterCodeStamp(moduleUrl) {
|
|
1245
1708
|
try {
|
|
1246
1709
|
const selfPath = (0, import_node_url.fileURLToPath)(moduleUrl);
|
|
1247
|
-
const hash = computeDistHashFrom(
|
|
1710
|
+
const hash = computeDistHashFrom(import_node_path4.default.dirname(selfPath));
|
|
1248
1711
|
return hash.length > 0 ? { kind: "bundle", hash } : SOURCE_STAMP;
|
|
1249
1712
|
} catch {
|
|
1250
1713
|
return SOURCE_STAMP;
|
|
1251
1714
|
}
|
|
1252
1715
|
}
|
|
1253
1716
|
function computeDistHashFrom(dir) {
|
|
1254
|
-
const candidates = [
|
|
1717
|
+
const candidates = [import_node_path4.default.join(dir, "index.js"), import_node_path4.default.join(dir, "index.cjs")];
|
|
1255
1718
|
for (const candidate of candidates) {
|
|
1256
|
-
if (!
|
|
1719
|
+
if (!import_node_fs2.default.existsSync(candidate)) {
|
|
1257
1720
|
continue;
|
|
1258
1721
|
}
|
|
1259
1722
|
return computeContentHash([candidate, ...analysisBundles()]);
|
|
@@ -1267,7 +1730,7 @@ function computeContentHash(paths) {
|
|
|
1267
1730
|
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
1268
1731
|
for (const file of paths) {
|
|
1269
1732
|
try {
|
|
1270
|
-
hash.update(
|
|
1733
|
+
hash.update(import_node_fs2.default.readFileSync(file));
|
|
1271
1734
|
} catch {
|
|
1272
1735
|
return "";
|
|
1273
1736
|
}
|
|
@@ -1283,13 +1746,30 @@ function projectFileStamp(paths) {
|
|
|
1283
1746
|
hash.update(file);
|
|
1284
1747
|
hash.update("\0");
|
|
1285
1748
|
try {
|
|
1286
|
-
hash.update(
|
|
1749
|
+
hash.update(import_node_fs2.default.readFileSync(file));
|
|
1287
1750
|
} catch {
|
|
1288
1751
|
hash.update("absent");
|
|
1289
1752
|
}
|
|
1290
1753
|
}
|
|
1291
1754
|
return hash.digest("hex").slice(0, 16);
|
|
1292
1755
|
}
|
|
1756
|
+
function extractionConfigStamp(config) {
|
|
1757
|
+
const parts = [
|
|
1758
|
+
["gapHandling", config.gapHandling ?? "permissive"],
|
|
1759
|
+
["includeReachable", optionalText(config.includeReachable)],
|
|
1760
|
+
["workspaceRoot", config.workspaceRoot],
|
|
1761
|
+
["projectRoot", config.projectRoot],
|
|
1762
|
+
["importRoots", config.importRoots?.join(import_node_path4.default.delimiter)],
|
|
1763
|
+
["modules", modulesStamp(config.modules)],
|
|
1764
|
+
["walkedDirectory", config.walkedDirectory]
|
|
1765
|
+
];
|
|
1766
|
+
return parts.flatMap(
|
|
1767
|
+
([name, value]) => value === void 0 ? [] : [`${name}=${value}`]
|
|
1768
|
+
).join(",");
|
|
1769
|
+
}
|
|
1770
|
+
function optionalText(value) {
|
|
1771
|
+
return value === void 0 ? void 0 : String(value);
|
|
1772
|
+
}
|
|
1293
1773
|
function runDigest(packsDigest, packs, files) {
|
|
1294
1774
|
const inputs = packs.flatMap((pack) => pack.discoveryInputs?.(files) ?? []);
|
|
1295
1775
|
return `${packsDigest}|reads:${projectFileStamp(inputs)}`;
|
|
@@ -1307,10 +1787,130 @@ function analysisBundles() {
|
|
|
1307
1787
|
}
|
|
1308
1788
|
|
|
1309
1789
|
// src/cache.ts
|
|
1790
|
+
var import_node_crypto3 = require("crypto");
|
|
1791
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
1792
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
1793
|
+
var import_files = require("@suss/behavioral-ir/files");
|
|
1794
|
+
|
|
1795
|
+
// src/cacheStamps.ts
|
|
1310
1796
|
var import_node_crypto2 = require("crypto");
|
|
1311
1797
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
1312
|
-
var
|
|
1313
|
-
|
|
1798
|
+
var RECENT_CHANGE_MS = 2e3;
|
|
1799
|
+
function stampMayMissAWrite(stat, statAt) {
|
|
1800
|
+
return Math.max(stat.mtimeMs, stat.ctimeMs) > statAt - RECENT_CHANGE_MS;
|
|
1801
|
+
}
|
|
1802
|
+
async function startRun(files, configPath) {
|
|
1803
|
+
const startedAt = Date.now();
|
|
1804
|
+
const config = configPath === void 0 ? null : await statAtStart(configPath);
|
|
1805
|
+
const stats = await Promise.all(files.map(statAtStart));
|
|
1806
|
+
stats.sort(
|
|
1807
|
+
(a, b) => a.stamp.path < b.stamp.path ? -1 : a.stamp.path > b.stamp.path ? 1 : 0
|
|
1808
|
+
);
|
|
1809
|
+
return {
|
|
1810
|
+
startedAt,
|
|
1811
|
+
config: config?.ctimeMs === null ? null : config,
|
|
1812
|
+
files: stats,
|
|
1813
|
+
hashes: /* @__PURE__ */ new Map()
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
async function statAtStart(filePath) {
|
|
1817
|
+
try {
|
|
1818
|
+
const stat = await import_promises.default.stat(filePath);
|
|
1819
|
+
return {
|
|
1820
|
+
stamp: { path: filePath, mtimeMs: stat.mtimeMs, size: stat.size },
|
|
1821
|
+
ctimeMs: stat.ctimeMs
|
|
1822
|
+
};
|
|
1823
|
+
} catch {
|
|
1824
|
+
return { stamp: { path: filePath, mtimeMs: -1, size: -1 }, ctimeMs: null };
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
async function hashOf(run, filePath) {
|
|
1828
|
+
const known = run.hashes.get(filePath);
|
|
1829
|
+
if (known !== void 0) {
|
|
1830
|
+
return known;
|
|
1831
|
+
}
|
|
1832
|
+
const hash = await hashFile(filePath);
|
|
1833
|
+
run.hashes.set(filePath, hash);
|
|
1834
|
+
return hash;
|
|
1835
|
+
}
|
|
1836
|
+
async function hashRecentChanges(run) {
|
|
1837
|
+
const recent = [...run.config === null ? [] : [run.config], ...run.files].filter(
|
|
1838
|
+
(file) => file.ctimeMs !== null && stampMayMissAWrite(
|
|
1839
|
+
{ mtimeMs: file.stamp.mtimeMs, ctimeMs: file.ctimeMs },
|
|
1840
|
+
run.startedAt
|
|
1841
|
+
)
|
|
1842
|
+
).map((file) => file.stamp.path);
|
|
1843
|
+
await Promise.all(recent.map((filePath) => hashOf(run, filePath)));
|
|
1844
|
+
}
|
|
1845
|
+
async function stillMatches(stored, found, run) {
|
|
1846
|
+
if (!fileStampEquals(stored, found)) {
|
|
1847
|
+
return false;
|
|
1848
|
+
}
|
|
1849
|
+
if (stored === null || stored.verifyHash !== true) {
|
|
1850
|
+
return true;
|
|
1851
|
+
}
|
|
1852
|
+
return await hashOf(run, stored.path) === stored.contentHash;
|
|
1853
|
+
}
|
|
1854
|
+
async function filesStillMatch(stored, run) {
|
|
1855
|
+
if (stored.length !== run.files.length || !stored.every((s, i) => fileStampEquals(s, run.files[i]?.stamp ?? null))) {
|
|
1856
|
+
return false;
|
|
1857
|
+
}
|
|
1858
|
+
const checks = await Promise.all(
|
|
1859
|
+
stored.map((s, i) => stillMatches(s, run.files[i]?.stamp ?? null, run))
|
|
1860
|
+
);
|
|
1861
|
+
return checks.every(Boolean);
|
|
1862
|
+
}
|
|
1863
|
+
async function recordedStamp(start, run, prior) {
|
|
1864
|
+
if (start.ctimeMs === null) {
|
|
1865
|
+
return start.stamp;
|
|
1866
|
+
}
|
|
1867
|
+
const filePath = start.stamp.path;
|
|
1868
|
+
const now = await import_promises.default.stat(filePath).catch(() => null);
|
|
1869
|
+
if (now === null || now.mtimeMs !== start.stamp.mtimeMs || now.size !== start.stamp.size || now.ctimeMs !== start.ctimeMs) {
|
|
1870
|
+
return null;
|
|
1871
|
+
}
|
|
1872
|
+
const atStart = { mtimeMs: start.stamp.mtimeMs, ctimeMs: start.ctimeMs };
|
|
1873
|
+
if (stampMayMissAWrite(atStart, run.startedAt)) {
|
|
1874
|
+
const readBefore = run.hashes.get(filePath);
|
|
1875
|
+
return readBefore === void 0 || readBefore === null ? null : { ...start.stamp, contentHash: readBefore, verifyHash: true };
|
|
1876
|
+
}
|
|
1877
|
+
const hash = run.hashes.get(filePath) ?? reusableHash(prior, start.stamp) ?? await hashFile(filePath);
|
|
1878
|
+
return hash === null ? start.stamp : { ...start.stamp, contentHash: hash };
|
|
1879
|
+
}
|
|
1880
|
+
function reusableHash(prior, stamp) {
|
|
1881
|
+
return prior !== void 0 && prior.verifyHash !== true && fileStampEquals(prior, stamp) ? prior.contentHash : void 0;
|
|
1882
|
+
}
|
|
1883
|
+
async function hashFile(filePath) {
|
|
1884
|
+
try {
|
|
1885
|
+
const content = await import_promises.default.readFile(filePath);
|
|
1886
|
+
return (0, import_node_crypto2.createHash)("sha256").update(content).digest("hex").slice(0, 16);
|
|
1887
|
+
} catch {
|
|
1888
|
+
return null;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
function fileStampEquals(a, b) {
|
|
1892
|
+
if (a === null && b === null) {
|
|
1893
|
+
return true;
|
|
1894
|
+
}
|
|
1895
|
+
if (a === null || b === null) {
|
|
1896
|
+
return false;
|
|
1897
|
+
}
|
|
1898
|
+
return a.path === b.path && a.mtimeMs === b.mtimeMs && a.size === b.size;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
// src/ignoredDirectory.ts
|
|
1902
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
1903
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
1904
|
+
function makeIgnoredDirectory(dir) {
|
|
1905
|
+
import_node_fs3.default.mkdirSync(dir, { recursive: true });
|
|
1906
|
+
const ignore = import_node_path5.default.join(dir, ".gitignore");
|
|
1907
|
+
if (!import_node_fs3.default.existsSync(ignore)) {
|
|
1908
|
+
import_node_fs3.default.writeFileSync(ignore, "*\n");
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
// src/cache.ts
|
|
1913
|
+
var SCHEMA_VERSION = "9";
|
|
1314
1914
|
var MAX_ENTRIES = 2;
|
|
1315
1915
|
var ENTRY_PREFIX = "key-";
|
|
1316
1916
|
var ENTRY_DIR_NAME = new RegExp(`^${ENTRY_PREFIX}[0-9a-f]{16}$`);
|
|
@@ -1327,56 +1927,88 @@ function createCacheLayer(cacheDir) {
|
|
|
1327
1927
|
}
|
|
1328
1928
|
};
|
|
1329
1929
|
}
|
|
1930
|
+
const manifests = new ManifestReads();
|
|
1931
|
+
const runs = /* @__PURE__ */ new WeakMap();
|
|
1932
|
+
const runFor = async (input) => runs.get(input) ?? await startRun(input.files, input.configPath);
|
|
1933
|
+
const lookupWith = async (input, run) => {
|
|
1934
|
+
const entryDir = entryDirFor(cacheDir, input);
|
|
1935
|
+
const manifest = await manifests.readAtRunStart(
|
|
1936
|
+
import_node_path6.default.join(entryDir, "manifest.json")
|
|
1937
|
+
);
|
|
1938
|
+
if (manifest === null) {
|
|
1939
|
+
return missDiag(await describeAbsentEntry(cacheDir));
|
|
1940
|
+
}
|
|
1941
|
+
if (!await stillMatches(
|
|
1942
|
+
manifest.configStamp,
|
|
1943
|
+
run.config?.stamp ?? null,
|
|
1944
|
+
run
|
|
1945
|
+
)) {
|
|
1946
|
+
return missDiag("config-changed");
|
|
1947
|
+
}
|
|
1948
|
+
if (!await filesStillMatch(manifest.files, run)) {
|
|
1949
|
+
return missDiag("files-changed");
|
|
1950
|
+
}
|
|
1951
|
+
await markUsed(entryDir);
|
|
1952
|
+
manifests.forget();
|
|
1953
|
+
return {
|
|
1954
|
+
kind: "hit",
|
|
1955
|
+
summaries: manifest.summaries,
|
|
1956
|
+
diagnostic: { kind: "hit" }
|
|
1957
|
+
};
|
|
1958
|
+
};
|
|
1330
1959
|
return {
|
|
1331
1960
|
async tryHit(input) {
|
|
1332
1961
|
const result = await this.lookup(input);
|
|
1333
1962
|
return result.kind === "hit" ? result.summaries : null;
|
|
1334
1963
|
},
|
|
1335
1964
|
async lookup(input) {
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
)
|
|
1340
|
-
|
|
1341
|
-
return missDiag(await describeAbsentEntry(cacheDir));
|
|
1965
|
+
const run = await startRun(input.files, input.configPath);
|
|
1966
|
+
runs.set(input, run);
|
|
1967
|
+
const result = await lookupWith(input, run);
|
|
1968
|
+
if (result.kind === "miss") {
|
|
1969
|
+
await hashRecentChanges(run);
|
|
1342
1970
|
}
|
|
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
|
-
};
|
|
1971
|
+
return result;
|
|
1357
1972
|
},
|
|
1358
1973
|
async plan(input) {
|
|
1359
1974
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1360
|
-
const manifest = await
|
|
1361
|
-
|
|
1975
|
+
const manifest = await manifests.readAgain(
|
|
1976
|
+
import_node_path6.default.join(entryDir, "manifest.json")
|
|
1362
1977
|
);
|
|
1363
1978
|
if (manifest === null || manifest.roots === void 0 || manifest.rootMeta === void 0 || manifest.owners === void 0) {
|
|
1364
1979
|
return null;
|
|
1365
1980
|
}
|
|
1366
|
-
const
|
|
1367
|
-
if (!
|
|
1981
|
+
const run = await runFor(input);
|
|
1982
|
+
if (!await stillMatches(
|
|
1983
|
+
manifest.configStamp,
|
|
1984
|
+
run.config?.stamp ?? null,
|
|
1985
|
+
run
|
|
1986
|
+
)) {
|
|
1368
1987
|
return null;
|
|
1369
1988
|
}
|
|
1370
1989
|
await markUsed(entryDir);
|
|
1371
|
-
return buildPlan(manifest,
|
|
1990
|
+
return buildPlan(manifest, run);
|
|
1372
1991
|
},
|
|
1373
1992
|
async write(input, summaries, attribution) {
|
|
1374
1993
|
const entryDir = entryDirFor(cacheDir, input);
|
|
1375
|
-
const previous = await
|
|
1376
|
-
|
|
1994
|
+
const previous = await manifests.readAgain(
|
|
1995
|
+
import_node_path6.default.join(entryDir, "manifest.json")
|
|
1377
1996
|
);
|
|
1378
|
-
|
|
1379
|
-
const
|
|
1997
|
+
manifests.forget();
|
|
1998
|
+
const known = runs.get(input);
|
|
1999
|
+
const run = known ?? await runFor(input);
|
|
2000
|
+
if (known === void 0) {
|
|
2001
|
+
await hashRecentChanges(run);
|
|
2002
|
+
}
|
|
2003
|
+
runs.delete(input);
|
|
2004
|
+
const configStamp = run.config === null ? null : await recordedStamp(run.config, run, void 0);
|
|
2005
|
+
const prior = new Map((previous?.files ?? []).map((f) => [f.path, f]));
|
|
2006
|
+
const recorded = await Promise.all(
|
|
2007
|
+
run.files.map(
|
|
2008
|
+
(file) => recordedStamp(file, run, prior.get(file.stamp.path))
|
|
2009
|
+
)
|
|
2010
|
+
);
|
|
2011
|
+
const files = recorded.filter((stamp) => stamp !== null);
|
|
1380
2012
|
const manifest = {
|
|
1381
2013
|
schemaVersion: SCHEMA_VERSION,
|
|
1382
2014
|
adapterPacksDigest: input.adapterPacksDigest,
|
|
@@ -1385,19 +2017,17 @@ function createCacheLayer(cacheDir) {
|
|
|
1385
2017
|
summaries,
|
|
1386
2018
|
...attribution === void 0 ? {} : encodeAttribution(attribution)
|
|
1387
2019
|
};
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
import_node_path3.default.join(entryDir, "manifest.json"),
|
|
1391
|
-
JSON.stringify(manifest)
|
|
1392
|
-
);
|
|
2020
|
+
makeIgnoredDirectory(cacheDir);
|
|
2021
|
+
(0, import_files.writeDocumentFile)(import_node_path6.default.join(entryDir, "manifest.json"), manifest);
|
|
1393
2022
|
await evictOldEntries(cacheDir, entryDir);
|
|
1394
2023
|
}
|
|
1395
2024
|
};
|
|
1396
2025
|
}
|
|
1397
|
-
async function buildPlan(manifest,
|
|
2026
|
+
async function buildPlan(manifest, run) {
|
|
1398
2027
|
const stored = new Map(manifest.files.map((f) => [f.path, f]));
|
|
1399
|
-
const current = new Map(
|
|
2028
|
+
const current = new Map(run.files.map((f) => [f.stamp.path, f.stamp]));
|
|
1400
2029
|
const changed = /* @__PURE__ */ new Set();
|
|
2030
|
+
const added = /* @__PURE__ */ new Set();
|
|
1401
2031
|
const removed = /* @__PURE__ */ new Set();
|
|
1402
2032
|
for (const p of stored.keys()) {
|
|
1403
2033
|
if (!current.has(p)) {
|
|
@@ -1409,17 +2039,20 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1409
2039
|
const before = stored.get(p);
|
|
1410
2040
|
if (before === void 0) {
|
|
1411
2041
|
changed.add(p);
|
|
2042
|
+
added.add(p);
|
|
1412
2043
|
} else if (!fileStampEquals(before, stamp)) {
|
|
1413
2044
|
if (before.contentHash === void 0) {
|
|
1414
2045
|
changed.add(p);
|
|
1415
2046
|
} else {
|
|
1416
2047
|
toVerify.push(p);
|
|
1417
2048
|
}
|
|
2049
|
+
} else if (before.verifyHash === true) {
|
|
2050
|
+
toVerify.push(p);
|
|
1418
2051
|
}
|
|
1419
2052
|
}
|
|
1420
2053
|
await Promise.all(
|
|
1421
2054
|
toVerify.map(async (p) => {
|
|
1422
|
-
const hash = await
|
|
2055
|
+
const hash = await hashOf(run, p);
|
|
1423
2056
|
if (hash === null || hash !== stored.get(p)?.contentHash) {
|
|
1424
2057
|
changed.add(p);
|
|
1425
2058
|
}
|
|
@@ -1428,6 +2061,10 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1428
2061
|
const roots = /* @__PURE__ */ new Map();
|
|
1429
2062
|
const rootNames = manifest.roots ?? [];
|
|
1430
2063
|
const depPaths = manifest.depPaths ?? [];
|
|
2064
|
+
const pathsOf = (ids) => ids.flatMap((d) => {
|
|
2065
|
+
const p = depPaths[d];
|
|
2066
|
+
return p === void 0 ? [] : [p];
|
|
2067
|
+
});
|
|
1431
2068
|
let rootsDeclined = 0;
|
|
1432
2069
|
rootNames.forEach((rootPath, i) => {
|
|
1433
2070
|
const meta = manifest.rootMeta?.[i];
|
|
@@ -1440,35 +2077,54 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1440
2077
|
roots.set(rootPath, {
|
|
1441
2078
|
path: rootPath,
|
|
1442
2079
|
cacheable: meta.cacheable,
|
|
1443
|
-
deps: meta.deps
|
|
1444
|
-
const p = depPaths[d];
|
|
1445
|
-
return p === void 0 ? [] : [p];
|
|
1446
|
-
}),
|
|
2080
|
+
deps: pathsOf(meta.deps),
|
|
1447
2081
|
claims: meta.claims,
|
|
1448
2082
|
meta: meta.meta,
|
|
1449
|
-
packs: meta.packs
|
|
2083
|
+
packs: meta.packs,
|
|
2084
|
+
...meta.imports === void 0 ? {} : { imports: pathsOf(meta.imports) }
|
|
1450
2085
|
});
|
|
1451
2086
|
});
|
|
2087
|
+
const unchanged = (filePath, deps) => current.has(filePath) && !changed.has(filePath) && !deps.some((d) => changed.has(d) || removed.has(d));
|
|
1452
2088
|
const validRoots = /* @__PURE__ */ new Set();
|
|
1453
2089
|
for (const [rootPath, record] of roots) {
|
|
1454
|
-
if (
|
|
1455
|
-
|
|
2090
|
+
if (record.cacheable && unchanged(rootPath, record.deps)) {
|
|
2091
|
+
validRoots.add(rootPath);
|
|
1456
2092
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
2093
|
+
}
|
|
2094
|
+
const units = (manifest.units ?? []).flatMap((stored2) => {
|
|
2095
|
+
const file = depPaths[stored2.file];
|
|
2096
|
+
return file === void 0 ? [] : [
|
|
2097
|
+
{
|
|
2098
|
+
key: stored2.key,
|
|
2099
|
+
file,
|
|
2100
|
+
deps: pathsOf(stored2.deps),
|
|
2101
|
+
data: stored2.data
|
|
2102
|
+
}
|
|
2103
|
+
];
|
|
2104
|
+
});
|
|
2105
|
+
const validUnits = /* @__PURE__ */ new Map();
|
|
2106
|
+
for (const unit of units) {
|
|
2107
|
+
if (unchanged(unit.file, unit.deps)) {
|
|
2108
|
+
validUnits.set(unit.key, unit);
|
|
1459
2109
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
2110
|
+
}
|
|
2111
|
+
const resolvedImports = /* @__PURE__ */ new Map();
|
|
2112
|
+
if (added.size === 0 && removed.size === 0) {
|
|
2113
|
+
for (const [rootPath, record] of roots) {
|
|
2114
|
+
if (record.imports !== void 0 && !changed.has(rootPath)) {
|
|
2115
|
+
resolvedImports.set(rootPath, record.imports);
|
|
2116
|
+
}
|
|
1463
2117
|
}
|
|
1464
2118
|
}
|
|
1465
2119
|
const owners = manifest.owners ?? [];
|
|
1466
2120
|
return {
|
|
1467
2121
|
changed,
|
|
1468
2122
|
removed,
|
|
2123
|
+
resolvedImports,
|
|
1469
2124
|
roots,
|
|
1470
2125
|
validRoots,
|
|
1471
2126
|
rootsDeclined,
|
|
2127
|
+
validUnits,
|
|
1472
2128
|
reuse(valid) {
|
|
1473
2129
|
const summaries = [];
|
|
1474
2130
|
const reusedOwners = [];
|
|
@@ -1495,7 +2151,8 @@ async function buildPlan(manifest, currentStamps) {
|
|
|
1495
2151
|
const p = rootNames[o];
|
|
1496
2152
|
return p === void 0 ? [] : [p];
|
|
1497
2153
|
})
|
|
1498
|
-
)
|
|
2154
|
+
),
|
|
2155
|
+
units
|
|
1499
2156
|
};
|
|
1500
2157
|
}
|
|
1501
2158
|
};
|
|
@@ -1520,7 +2177,8 @@ function encodeAttribution(attribution) {
|
|
|
1520
2177
|
deps: r.deps.map(depIdOf),
|
|
1521
2178
|
claims: r.claims,
|
|
1522
2179
|
meta: r.meta,
|
|
1523
|
-
packs: r.packs
|
|
2180
|
+
packs: r.packs,
|
|
2181
|
+
...r.imports === void 0 ? {} : { imports: r.imports.map(depIdOf) }
|
|
1524
2182
|
}));
|
|
1525
2183
|
const owners = attribution.owners.map(
|
|
1526
2184
|
(ownerPaths) => ownerPaths.flatMap((p) => {
|
|
@@ -1528,32 +2186,23 @@ function encodeAttribution(attribution) {
|
|
|
1528
2186
|
return i === void 0 ? [] : [i];
|
|
1529
2187
|
})
|
|
1530
2188
|
);
|
|
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
|
-
}
|
|
2189
|
+
const units = attribution.units?.map((unit) => ({
|
|
2190
|
+
key: unit.key,
|
|
2191
|
+
file: depIdOf(unit.file),
|
|
2192
|
+
deps: unit.deps.map(depIdOf),
|
|
2193
|
+
data: unit.data
|
|
2194
|
+
}));
|
|
2195
|
+
return {
|
|
2196
|
+
roots,
|
|
2197
|
+
rootMeta,
|
|
2198
|
+
depPaths,
|
|
2199
|
+
owners,
|
|
2200
|
+
...units === void 0 ? {} : { units }
|
|
2201
|
+
};
|
|
1553
2202
|
}
|
|
1554
2203
|
async function describeAbsentEntry(cacheDir) {
|
|
1555
2204
|
try {
|
|
1556
|
-
const entries = await
|
|
2205
|
+
const entries = await import_promises2.default.readdir(cacheDir, { withFileTypes: true });
|
|
1557
2206
|
return entries.some((e) => e.isDirectory() && isEntryDir(e.name)) ? "key-changed" : "no-manifest";
|
|
1558
2207
|
} catch {
|
|
1559
2208
|
return "no-manifest";
|
|
@@ -1565,8 +2214,8 @@ function entryDirFor(cacheDir, input) {
|
|
|
1565
2214
|
input.adapterPacksDigest,
|
|
1566
2215
|
input.configPath ?? ""
|
|
1567
2216
|
].join(" ");
|
|
1568
|
-
const name = (0,
|
|
1569
|
-
return
|
|
2217
|
+
const name = (0, import_node_crypto3.createHash)("sha256").update(key).digest("hex").slice(0, 16);
|
|
2218
|
+
return import_node_path6.default.join(cacheDir, `${ENTRY_PREFIX}${name}`);
|
|
1570
2219
|
}
|
|
1571
2220
|
function isEntryDir(name) {
|
|
1572
2221
|
return ENTRY_DIR_NAME.test(name);
|
|
@@ -1574,24 +2223,24 @@ function isEntryDir(name) {
|
|
|
1574
2223
|
async function markUsed(entryDir) {
|
|
1575
2224
|
const now = /* @__PURE__ */ new Date();
|
|
1576
2225
|
try {
|
|
1577
|
-
await
|
|
2226
|
+
await import_promises2.default.utimes(entryDir, now, now);
|
|
1578
2227
|
} catch {
|
|
1579
2228
|
}
|
|
1580
2229
|
}
|
|
1581
2230
|
async function evictOldEntries(cacheDir, keepDir) {
|
|
1582
2231
|
try {
|
|
1583
|
-
await
|
|
1584
|
-
const entries = await
|
|
2232
|
+
await import_promises2.default.rm(import_node_path6.default.join(cacheDir, "manifest.json"), { force: true });
|
|
2233
|
+
const entries = await import_promises2.default.readdir(cacheDir, { withFileTypes: true });
|
|
1585
2234
|
const dirs = await Promise.all(
|
|
1586
2235
|
entries.filter((e) => e.isDirectory() && isEntryDir(e.name)).map(async (e) => {
|
|
1587
|
-
const dir =
|
|
1588
|
-
const stat = await
|
|
2236
|
+
const dir = import_node_path6.default.join(cacheDir, e.name);
|
|
2237
|
+
const stat = await import_promises2.default.stat(dir);
|
|
1589
2238
|
return { dir, mtimeMs: stat.mtimeMs };
|
|
1590
2239
|
})
|
|
1591
2240
|
);
|
|
1592
2241
|
const doomed = dirs.filter((d) => d.dir !== keepDir).sort((a, b) => b.mtimeMs - a.mtimeMs).slice(MAX_ENTRIES - 1);
|
|
1593
2242
|
await Promise.all(
|
|
1594
|
-
doomed.map((d) =>
|
|
2243
|
+
doomed.map((d) => import_promises2.default.rm(d.dir, { recursive: true, force: true }))
|
|
1595
2244
|
);
|
|
1596
2245
|
} catch {
|
|
1597
2246
|
}
|
|
@@ -1602,54 +2251,43 @@ function missDiag(reason) {
|
|
|
1602
2251
|
diagnostic: { kind: "miss", missReason: reason }
|
|
1603
2252
|
};
|
|
1604
2253
|
}
|
|
1605
|
-
|
|
2254
|
+
var ManifestReads = class {
|
|
2255
|
+
last = null;
|
|
2256
|
+
async readAtRunStart(manifestPath) {
|
|
2257
|
+
const stamp = await manifestStamp(manifestPath);
|
|
2258
|
+
const manifest = await readManifest(manifestPath);
|
|
2259
|
+
this.last = { path: manifestPath, stamp, manifest };
|
|
2260
|
+
return manifest;
|
|
2261
|
+
}
|
|
2262
|
+
async readAgain(manifestPath) {
|
|
2263
|
+
const last = this.last;
|
|
2264
|
+
if (last !== null && last.path === manifestPath && last.stamp !== null && last.stamp === await manifestStamp(manifestPath)) {
|
|
2265
|
+
return last.manifest;
|
|
2266
|
+
}
|
|
2267
|
+
return await this.readAtRunStart(manifestPath);
|
|
2268
|
+
}
|
|
2269
|
+
forget() {
|
|
2270
|
+
this.last = null;
|
|
2271
|
+
}
|
|
2272
|
+
};
|
|
2273
|
+
async function manifestStamp(manifestPath) {
|
|
1606
2274
|
try {
|
|
1607
|
-
const
|
|
1608
|
-
return
|
|
2275
|
+
const stat = await import_promises2.default.stat(manifestPath);
|
|
2276
|
+
return `${stat.ino}:${stat.mtimeMs}:${stat.size}`;
|
|
1609
2277
|
} catch {
|
|
1610
2278
|
return null;
|
|
1611
2279
|
}
|
|
1612
2280
|
}
|
|
1613
|
-
async function
|
|
1614
|
-
if (configPath === void 0) {
|
|
1615
|
-
return null;
|
|
1616
|
-
}
|
|
2281
|
+
async function readManifest(manifestPath) {
|
|
1617
2282
|
try {
|
|
1618
|
-
|
|
1619
|
-
return { path: configPath, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
2283
|
+
return (0, import_files.readJsonFile)(manifestPath);
|
|
1620
2284
|
} catch {
|
|
1621
2285
|
return null;
|
|
1622
2286
|
}
|
|
1623
2287
|
}
|
|
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
2288
|
|
|
1651
2289
|
// src/extractionReport.ts
|
|
1652
|
-
var
|
|
2290
|
+
var import_behavioral_ir6 = require("@suss/behavioral-ir");
|
|
1653
2291
|
var emptyTally = () => ({
|
|
1654
2292
|
candidateFiles: 0,
|
|
1655
2293
|
unitsDiscovered: 0,
|
|
@@ -1699,7 +2337,7 @@ function summaryCountsByPack(summaries) {
|
|
|
1699
2337
|
}
|
|
1700
2338
|
const entry = counts.get(recognition) ?? emptyCounts();
|
|
1701
2339
|
entry.bound += 1;
|
|
1702
|
-
if (
|
|
2340
|
+
if (import_behavioral_ir6.BOUNDARY_ROLE[summary.kind] === "provider") {
|
|
1703
2341
|
entry.providers += 1;
|
|
1704
2342
|
}
|
|
1705
2343
|
if (summary.transitions.length > 0) {
|
|
@@ -1755,6 +2393,38 @@ function firstEmptyUngatedStage(packs, filesWalked) {
|
|
|
1755
2393
|
return "assembly";
|
|
1756
2394
|
}
|
|
1757
2395
|
|
|
2396
|
+
// src/keptParses.ts
|
|
2397
|
+
var KeptParses = class {
|
|
2398
|
+
constructor(release = () => {
|
|
2399
|
+
}) {
|
|
2400
|
+
this.release = release;
|
|
2401
|
+
}
|
|
2402
|
+
release;
|
|
2403
|
+
byFile = /* @__PURE__ */ new Map();
|
|
2404
|
+
async parse(file, source, make) {
|
|
2405
|
+
const kept = this.byFile.get(file);
|
|
2406
|
+
if (kept !== void 0 && kept.source === source) {
|
|
2407
|
+
return kept.value;
|
|
2408
|
+
}
|
|
2409
|
+
const value = await make(source);
|
|
2410
|
+
if (kept !== void 0) {
|
|
2411
|
+
this.release(kept.value);
|
|
2412
|
+
}
|
|
2413
|
+
this.byFile.set(file, { source, value });
|
|
2414
|
+
return value;
|
|
2415
|
+
}
|
|
2416
|
+
/** Lets go of every file not in this run. */
|
|
2417
|
+
keepOnly(files) {
|
|
2418
|
+
const wanted = new Set(files);
|
|
2419
|
+
for (const [file, kept] of this.byFile) {
|
|
2420
|
+
if (!wanted.has(file)) {
|
|
2421
|
+
this.release(kept.value);
|
|
2422
|
+
this.byFile.delete(file);
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
|
|
1758
2428
|
// src/packHealth.ts
|
|
1759
2429
|
function stagesOf(funnel) {
|
|
1760
2430
|
const stages = [];
|
|
@@ -1801,8 +2471,8 @@ function funnelDrops(packs) {
|
|
|
1801
2471
|
function recognizersWithNoUnits(packs) {
|
|
1802
2472
|
return packs.filter(
|
|
1803
2473
|
(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
|
|
2474
|
+
// roots, so effects recognized there mean the run worked and only
|
|
2475
|
+
// the framework pack's attribution is missing.
|
|
1806
2476
|
funnel.effectsRecognized === 0
|
|
1807
2477
|
).map((funnel) => ({
|
|
1808
2478
|
label: funnel.pack,
|
|
@@ -2044,7 +2714,7 @@ function makeTransitionId(functionName, branch) {
|
|
|
2044
2714
|
const { terminal } = branch;
|
|
2045
2715
|
const statusKey = terminal.statusCode === null ? "none" : terminal.statusCode.type === "literal" ? String(terminal.statusCode.value) : `dyn:${terminal.statusCode.sourceText}`;
|
|
2046
2716
|
const conditionSig = branch.conditions.map((c) => `${c.polarity}:${c.sourceText}`).join(";");
|
|
2047
|
-
const conditionHash = (0,
|
|
2717
|
+
const conditionHash = (0, import_node_crypto4.createHash)("sha1").update(conditionSig).digest("hex").slice(0, 7);
|
|
2048
2718
|
return `${functionName}:${terminal.kind}:${statusKey}:${conditionHash}`;
|
|
2049
2719
|
}
|
|
2050
2720
|
function collapseReading(table, reading) {
|
|
@@ -2103,6 +2773,7 @@ function unreadSentences(raw) {
|
|
|
2103
2773
|
...raw.branches.flatMap(readingsOfBranch)
|
|
2104
2774
|
];
|
|
2105
2775
|
return [
|
|
2776
|
+
...raw.readFailure !== void 0 ? [raw.readFailure] : [],
|
|
2106
2777
|
...raw.unreadBinding !== void 0 ? [raw.unreadBinding] : [],
|
|
2107
2778
|
...handedOver.map(unreadReasonOf).filter((reason) => reason !== null)
|
|
2108
2779
|
];
|
|
@@ -2112,7 +2783,40 @@ function effectsOfBranch(branch) {
|
|
|
2112
2783
|
...branch.effects.map(effectToIR),
|
|
2113
2784
|
...branch.extraEffects ?? []
|
|
2114
2785
|
];
|
|
2115
|
-
return (0,
|
|
2786
|
+
return (0, import_behavioral_ir7.foldRepeatedEffects)(effects.map(withNormalizedCallee));
|
|
2787
|
+
}
|
|
2788
|
+
function provenanceOf(raw, effects) {
|
|
2789
|
+
if (raw.length === 0) {
|
|
2790
|
+
return [];
|
|
2791
|
+
}
|
|
2792
|
+
const positionOf = new Map(effects.map((one, at) => [(0, import_behavioral_ir7.effectKey)(one), at]));
|
|
2793
|
+
const bySlot = /* @__PURE__ */ new Map();
|
|
2794
|
+
const said = /* @__PURE__ */ new Map();
|
|
2795
|
+
for (const one of raw) {
|
|
2796
|
+
const effect = positionOf.get((0, import_behavioral_ir7.effectKey)(withNormalizedCallee(one.effect)));
|
|
2797
|
+
if (effect === void 0) {
|
|
2798
|
+
continue;
|
|
2799
|
+
}
|
|
2800
|
+
const slotKey = `${effect}\0${one.slot}\0${one.name}`;
|
|
2801
|
+
let entry = bySlot.get(slotKey);
|
|
2802
|
+
let seen = said.get(slotKey);
|
|
2803
|
+
if (entry === void 0 || seen === void 0) {
|
|
2804
|
+
entry = { at: { slot: one.slot, effect, name: one.name }, from: [] };
|
|
2805
|
+
seen = /* @__PURE__ */ new Set();
|
|
2806
|
+
bySlot.set(slotKey, entry);
|
|
2807
|
+
said.set(slotKey, seen);
|
|
2808
|
+
}
|
|
2809
|
+
for (const source of one.from) {
|
|
2810
|
+
const spelled = JSON.stringify(source);
|
|
2811
|
+
if (!seen.has(spelled)) {
|
|
2812
|
+
seen.add(spelled);
|
|
2813
|
+
entry.from.push(source);
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
return [...bySlot.values()].sort(
|
|
2818
|
+
(a, b) => a.at.effect - b.at.effect || a.at.slot.localeCompare(b.at.slot) || a.at.name.localeCompare(b.at.name)
|
|
2819
|
+
);
|
|
2116
2820
|
}
|
|
2117
2821
|
function withNormalizedCallee(effect) {
|
|
2118
2822
|
if (effect.type !== "invocation" && effect.type !== "interaction") {
|
|
@@ -2121,7 +2825,7 @@ function withNormalizedCallee(effect) {
|
|
|
2121
2825
|
if (effect.callee === void 0) {
|
|
2122
2826
|
return effect;
|
|
2123
2827
|
}
|
|
2124
|
-
return { ...effect, callee: (0,
|
|
2828
|
+
return { ...effect, callee: (0, import_behavioral_ir7.normalizeCalleeText)(effect.callee) };
|
|
2125
2829
|
}
|
|
2126
2830
|
function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
2127
2831
|
const transitions = raw.branches.map((rawBranch) => {
|
|
@@ -2129,17 +2833,22 @@ function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
|
2129
2833
|
const conditions = branch.conditions.map(
|
|
2130
2834
|
rawConditionToPredicate
|
|
2131
2835
|
);
|
|
2836
|
+
const effects = effectsOfBranch(branch);
|
|
2132
2837
|
const transition = {
|
|
2133
2838
|
id: makeTransitionId(raw.identity.name, branch),
|
|
2134
2839
|
conditions,
|
|
2135
2840
|
output: terminalToOutput(branch.terminal),
|
|
2136
|
-
effects
|
|
2841
|
+
effects,
|
|
2137
2842
|
location: branch.location,
|
|
2138
2843
|
isDefault: branch.isDefault
|
|
2139
2844
|
};
|
|
2140
2845
|
if (branch.expectedInput != null) {
|
|
2141
2846
|
transition.expectedInput = branch.expectedInput;
|
|
2142
2847
|
}
|
|
2848
|
+
const provenance = provenanceOf(branch.provenance ?? [], effects);
|
|
2849
|
+
if (provenance.length > 0) {
|
|
2850
|
+
transition.provenance = provenance;
|
|
2851
|
+
}
|
|
2143
2852
|
return transition;
|
|
2144
2853
|
});
|
|
2145
2854
|
const gaps = detectGaps(raw, transitions, options);
|
|
@@ -2181,25 +2890,28 @@ function buildMetadata(raw) {
|
|
|
2181
2890
|
let metadata = {};
|
|
2182
2891
|
const http = buildHttpMetadataValue(raw);
|
|
2183
2892
|
if (http !== null) {
|
|
2184
|
-
metadata = (0,
|
|
2893
|
+
metadata = (0, import_behavioral_ir7.withHttpMetadata)(metadata, http);
|
|
2185
2894
|
}
|
|
2186
2895
|
const graphql = buildGraphqlMetadataValue(raw);
|
|
2187
2896
|
if (graphql !== null) {
|
|
2188
|
-
metadata = (0,
|
|
2897
|
+
metadata = (0, import_behavioral_ir7.withGraphqlMetadata)(metadata, graphql);
|
|
2189
2898
|
}
|
|
2190
2899
|
if (raw.sourceDocumentLabel !== void 0) {
|
|
2191
|
-
metadata = (0,
|
|
2900
|
+
metadata = (0, import_behavioral_ir7.withSourceDocumentMetadata)(metadata, {
|
|
2192
2901
|
label: raw.sourceDocumentLabel
|
|
2193
2902
|
});
|
|
2194
2903
|
}
|
|
2195
2904
|
if (raw.mount !== void 0) {
|
|
2196
|
-
metadata = (0,
|
|
2905
|
+
metadata = (0, import_behavioral_ir7.withMountMetadata)(metadata, raw.mount);
|
|
2197
2906
|
}
|
|
2198
2907
|
if (raw.wrappers !== void 0 && raw.wrappers.length > 0) {
|
|
2199
|
-
metadata = (0,
|
|
2908
|
+
metadata = (0, import_behavioral_ir7.withWrapperMetadata)(metadata, { applied: raw.wrappers });
|
|
2200
2909
|
}
|
|
2201
2910
|
if (raw.requestSpelling !== void 0) {
|
|
2202
|
-
metadata = (0,
|
|
2911
|
+
metadata = (0, import_behavioral_ir7.withRequestSpellingMetadata)(metadata, raw.requestSpelling);
|
|
2912
|
+
}
|
|
2913
|
+
if (raw.test !== void 0) {
|
|
2914
|
+
metadata = (0, import_behavioral_ir7.withTestMetadata)(metadata, raw.test);
|
|
2203
2915
|
}
|
|
2204
2916
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
2205
2917
|
}
|
|
@@ -2224,6 +2936,12 @@ function buildHttpMetadataValue(raw) {
|
|
|
2224
2936
|
if (raw.failureDelivery !== void 0) {
|
|
2225
2937
|
http.failureDelivery = raw.failureDelivery;
|
|
2226
2938
|
}
|
|
2939
|
+
if (raw.redirectDelivery !== void 0) {
|
|
2940
|
+
http.redirectDelivery = raw.redirectDelivery;
|
|
2941
|
+
}
|
|
2942
|
+
if (raw.declaredStatuses !== void 0 && raw.declaredStatuses.length > 0) {
|
|
2943
|
+
http.declaredStatuses = raw.declaredStatuses;
|
|
2944
|
+
}
|
|
2227
2945
|
return Object.keys(http).length > 0 ? http : null;
|
|
2228
2946
|
}
|
|
2229
2947
|
function buildGraphqlMetadataValue(raw) {
|
|
@@ -2252,7 +2970,7 @@ function answersWithHttpResponses(raw) {
|
|
|
2252
2970
|
if (raw.boundaryBinding === null || raw.boundaryBinding === void 0) {
|
|
2253
2971
|
return true;
|
|
2254
2972
|
}
|
|
2255
|
-
return (0,
|
|
2973
|
+
return (0, import_behavioral_ir7.exchangesHttpResponses)(raw.boundaryBinding);
|
|
2256
2974
|
}
|
|
2257
2975
|
function detectGaps(raw, transitions, options) {
|
|
2258
2976
|
if (options.gapHandling === "silent") {
|
|
@@ -2291,13 +3009,16 @@ function detectGaps(raw, transitions, options) {
|
|
|
2291
3009
|
return gaps;
|
|
2292
3010
|
}
|
|
2293
3011
|
function bodyWentUnread(raw) {
|
|
3012
|
+
if (raw.readFailure !== void 0) {
|
|
3013
|
+
return true;
|
|
3014
|
+
}
|
|
2294
3015
|
if (raw.bodyContent === "absent" || raw.bodyContent === "elsewhere") {
|
|
2295
3016
|
return true;
|
|
2296
3017
|
}
|
|
2297
3018
|
return raw.bodyContent === "statements" && raw.branches.length === 0;
|
|
2298
3019
|
}
|
|
2299
3020
|
function describeUnreadBody(raw) {
|
|
2300
|
-
if (!bodyWentUnread(raw)) {
|
|
3021
|
+
if (!bodyWentUnread(raw) || raw.readFailure !== void 0) {
|
|
2301
3022
|
return null;
|
|
2302
3023
|
}
|
|
2303
3024
|
if (raw.bodyContent === "absent") {
|
|
@@ -2344,26 +3065,41 @@ function bodyToShape(body) {
|
|
|
2344
3065
|
}
|
|
2345
3066
|
return null;
|
|
2346
3067
|
}
|
|
3068
|
+
function statusValueRef(code) {
|
|
3069
|
+
if (code === null) {
|
|
3070
|
+
return null;
|
|
3071
|
+
}
|
|
3072
|
+
return code.type === "literal" ? { type: "literal", value: code.value } : { type: "unresolved", sourceText: code.sourceText };
|
|
3073
|
+
}
|
|
2347
3074
|
var terminalConverters = {
|
|
2348
3075
|
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
3076
|
const body = bodyToShape(t.body);
|
|
2351
|
-
return {
|
|
3077
|
+
return {
|
|
3078
|
+
type: "response",
|
|
3079
|
+
statusCode: statusValueRef(t.statusCode),
|
|
3080
|
+
body,
|
|
3081
|
+
headers: {}
|
|
3082
|
+
};
|
|
2352
3083
|
},
|
|
2353
3084
|
throw: (t) => {
|
|
2354
3085
|
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
3086
|
return {
|
|
2357
3087
|
type: "response",
|
|
2358
|
-
statusCode,
|
|
3088
|
+
statusCode: statusValueRef(t.statusCode),
|
|
2359
3089
|
body: bodyToShape(t.body),
|
|
2360
3090
|
headers: {}
|
|
2361
3091
|
};
|
|
2362
3092
|
}
|
|
3093
|
+
const ancestry = t.exceptionAncestry;
|
|
2363
3094
|
return {
|
|
2364
3095
|
type: "throw",
|
|
2365
3096
|
exceptionType: t.exceptionType,
|
|
2366
|
-
message: t.message
|
|
3097
|
+
message: t.message,
|
|
3098
|
+
...ancestry === void 0 ? {} : {
|
|
3099
|
+
exceptionAncestors: ancestry.ancestors,
|
|
3100
|
+
...ancestry.incomplete ? { ancestryIncomplete: true } : {}
|
|
3101
|
+
},
|
|
3102
|
+
...t.statusWhenUncaught === void 0 ? {} : { statusWhenUncaught: t.statusWhenUncaught }
|
|
2367
3103
|
};
|
|
2368
3104
|
},
|
|
2369
3105
|
render: (t) => ({
|
|
@@ -2383,7 +3119,8 @@ var terminalConverters = {
|
|
|
2383
3119
|
type: "return",
|
|
2384
3120
|
value: bodyToShape(t.body)
|
|
2385
3121
|
}),
|
|
2386
|
-
void: (_t) => ({ type: "void" })
|
|
3122
|
+
void: (_t) => ({ type: "void" }),
|
|
3123
|
+
exit: (t) => ({ type: "exit", code: statusValueRef(t.statusCode) })
|
|
2387
3124
|
};
|
|
2388
3125
|
function terminalToOutput(terminal) {
|
|
2389
3126
|
return terminalConverters[terminal.kind](terminal);
|
|
@@ -2426,15 +3163,20 @@ function paramToInput(param) {
|
|
|
2426
3163
|
name: param.name,
|
|
2427
3164
|
position: param.position,
|
|
2428
3165
|
role: param.role,
|
|
3166
|
+
...param.field === void 0 ? {} : { field: param.field },
|
|
2429
3167
|
shape: param.typeText ? { type: "ref", name: param.typeText } : null
|
|
2430
3168
|
};
|
|
2431
3169
|
}
|
|
2432
3170
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2433
3171
|
0 && (module.exports = {
|
|
3172
|
+
EnclosingNodes,
|
|
2434
3173
|
IdMap,
|
|
2435
3174
|
IdSet,
|
|
3175
|
+
KeptParses,
|
|
2436
3176
|
MAX_ENTRIES,
|
|
3177
|
+
MAX_HELPER_PATHS,
|
|
2437
3178
|
MAX_PATHS,
|
|
3179
|
+
MODULE_SURFACE_RECOGNITION,
|
|
2438
3180
|
PathBudgetExceeded,
|
|
2439
3181
|
SKIP_CHILDREN,
|
|
2440
3182
|
UnmodeledFlow,
|
|
@@ -2459,30 +3201,45 @@ function paramToInput(param) {
|
|
|
2459
3201
|
enumerateOrDegrade,
|
|
2460
3202
|
enumerateStructuredPaths,
|
|
2461
3203
|
evaluatePackHealth,
|
|
3204
|
+
extractionConfigStamp,
|
|
2462
3205
|
firstWrittenReading,
|
|
2463
3206
|
formatPackHealth,
|
|
2464
3207
|
guardsHoldOn,
|
|
3208
|
+
helperPathsOnVariables,
|
|
2465
3209
|
httpRouteDiscovery,
|
|
3210
|
+
isListedTestFile,
|
|
3211
|
+
makeIgnoredDirectory,
|
|
2466
3212
|
makeTransitionId,
|
|
2467
3213
|
mapReading,
|
|
3214
|
+
markReturnsAsExitCode,
|
|
3215
|
+
matchesTestFileName,
|
|
3216
|
+
mergeReadShapes,
|
|
2468
3217
|
moduleInitStructure,
|
|
3218
|
+
moduleOfFile,
|
|
2469
3219
|
noopTimer,
|
|
2470
3220
|
packGradients,
|
|
2471
3221
|
paramToInput,
|
|
2472
3222
|
projectFileStamp,
|
|
2473
3223
|
rawConditionToPredicate,
|
|
2474
3224
|
recordPackFailure,
|
|
3225
|
+
redirectDeliveryWhenSet,
|
|
2475
3226
|
registrationHelperDiscovery,
|
|
2476
3227
|
routeHelperIndex,
|
|
2477
3228
|
runDigest,
|
|
2478
3229
|
runsBefore,
|
|
2479
3230
|
scopeOption,
|
|
3231
|
+
settleModules,
|
|
2480
3232
|
sharedGatingConditions,
|
|
3233
|
+
sourceRefsOf,
|
|
3234
|
+
splitAtHandOffs,
|
|
3235
|
+
stampMayMissAWrite,
|
|
2481
3236
|
stampModuleImports,
|
|
3237
|
+
stampModules,
|
|
2482
3238
|
storageSystemOption,
|
|
2483
3239
|
summaryCountsByPack,
|
|
2484
3240
|
tallyUnit,
|
|
2485
3241
|
terminalToOutput,
|
|
3242
|
+
throughHelper,
|
|
2486
3243
|
unreadableReading,
|
|
2487
3244
|
unwrapJsonStringify,
|
|
2488
3245
|
valueToReadFurtherFrom,
|