@suss/extractor 0.19.0 → 0.21.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 +47 -0
- package/dist/index.cjs +406 -83
- package/dist/index.d.cts +429 -15
- package/dist/index.d.ts +429 -15
- package/dist/index.js +396 -79
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
exchangesHttpResponses,
|
|
5
5
|
withGraphqlMetadata,
|
|
6
6
|
withHttpMetadata,
|
|
7
|
-
|
|
7
|
+
withMountMetadata,
|
|
8
|
+
withSourceDocumentMetadata,
|
|
9
|
+
withWrapperMetadata as withWrapperMetadata2
|
|
8
10
|
} from "@suss/behavioral-ir";
|
|
9
11
|
|
|
10
12
|
// src/inputReads.ts
|
|
@@ -97,80 +99,12 @@ function mergeInputReads(derived, syntactic) {
|
|
|
97
99
|
return [...found.values()];
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
// src/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
type: "registrationCall",
|
|
107
|
-
importModule: opts.importModule,
|
|
108
|
-
importName,
|
|
109
|
-
registrationChain: [...opts.methods]
|
|
110
|
-
},
|
|
111
|
-
bindingExtraction: {
|
|
112
|
-
// `.all` registers every method, so it records "*", which the pairing
|
|
113
|
-
// engine treats as agreeing with any method at all.
|
|
114
|
-
method: {
|
|
115
|
-
type: "fromRegistration",
|
|
116
|
-
position: "methodName",
|
|
117
|
-
nameMap: { all: "*" }
|
|
118
|
-
},
|
|
119
|
-
path: { type: "fromArgument", position: 0 }
|
|
120
|
-
},
|
|
121
|
-
...opts.mount !== void 0 ? { mount: opts.mount } : {},
|
|
122
|
-
requiresImport: [opts.importModule]
|
|
123
|
-
}));
|
|
124
|
-
if (opts.importNames.length === 0) {
|
|
125
|
-
return calls;
|
|
126
|
-
}
|
|
127
|
-
return [
|
|
128
|
-
...calls,
|
|
129
|
-
// Routes registered in a loop over an array of specs, a shape
|
|
130
|
-
// registration-call discovery cannot see. The receiver comes from
|
|
131
|
-
// the same import declaration as the calls above, so a loop that
|
|
132
|
-
// never touches this library's routable is left alone.
|
|
133
|
-
{
|
|
134
|
-
kind,
|
|
135
|
-
match: {
|
|
136
|
-
type: "registrationLoop",
|
|
137
|
-
elementShape: LOOP_ELEMENT_SHAPE,
|
|
138
|
-
receiver: {
|
|
139
|
-
importModule: opts.importModule,
|
|
140
|
-
importNames: [...opts.importNames]
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
requiresImport: [opts.importModule]
|
|
144
|
-
}
|
|
145
|
-
];
|
|
146
|
-
}
|
|
147
|
-
var LOOP_ELEMENT_SHAPE = {
|
|
148
|
-
methodKey: "method",
|
|
149
|
-
pathKey: "path",
|
|
150
|
-
handlerKey: "handler"
|
|
151
|
-
};
|
|
152
|
-
function registrationHelperDiscovery(helpers, kind = "handler") {
|
|
153
|
-
return helpers.map((helper) => ({
|
|
154
|
-
kind,
|
|
155
|
-
match: {
|
|
156
|
-
type: "registrationTemplate",
|
|
157
|
-
helperName: helper.helperName,
|
|
158
|
-
...helper.importModule !== void 0 ? { importModule: helper.importModule } : {},
|
|
159
|
-
registrations: helper.registrations.map((one) => ({ ...one }))
|
|
160
|
-
}
|
|
161
|
-
}));
|
|
162
|
-
}
|
|
163
|
-
function unwrapJsonStringify(body) {
|
|
164
|
-
if (body === null || typeof body !== "object") {
|
|
165
|
-
return body;
|
|
166
|
-
}
|
|
167
|
-
const candidate = body;
|
|
168
|
-
if (candidate.kind !== "call" || candidate.callee !== "JSON.stringify") {
|
|
169
|
-
return body;
|
|
170
|
-
}
|
|
171
|
-
const inner = candidate.args?.[0];
|
|
172
|
-
return inner ?? body;
|
|
173
|
-
}
|
|
102
|
+
// src/composeWrappers.ts
|
|
103
|
+
import {
|
|
104
|
+
readWrapperMetadata,
|
|
105
|
+
withinScope,
|
|
106
|
+
withWrapperMetadata
|
|
107
|
+
} from "@suss/behavioral-ir";
|
|
174
108
|
|
|
175
109
|
// src/paths/enumeratePaths.ts
|
|
176
110
|
import { CATCH_ENTRY_TEXT } from "@suss/behavioral-ir";
|
|
@@ -587,23 +521,372 @@ function reasonToDegrade(error) {
|
|
|
587
521
|
return null;
|
|
588
522
|
}
|
|
589
523
|
|
|
590
|
-
// src/
|
|
524
|
+
// src/composeWrappers.ts
|
|
525
|
+
var BUDGET_GAP = {
|
|
526
|
+
type: "unreadOutcome",
|
|
527
|
+
conditions: [],
|
|
528
|
+
consequence: "unknown",
|
|
529
|
+
description: `Composing the wrappers registered around this unit would have gone past the path budget of ${MAX_PATHS}, so what each of them produces is reported beside this unit's own outcomes rather than under the conditions that reach it`
|
|
530
|
+
};
|
|
531
|
+
function composeWrappers(summaries) {
|
|
532
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
533
|
+
for (const summary of summaries) {
|
|
534
|
+
const key = summaryKey(summary.location.file, summary.identity.name);
|
|
535
|
+
if (!byKey.has(key)) {
|
|
536
|
+
byKey.set(key, summary);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return summaries.map((summary) => composeOne(summary, byKey));
|
|
540
|
+
}
|
|
541
|
+
function summaryKey(file, name) {
|
|
542
|
+
return `${file}::${name}`;
|
|
543
|
+
}
|
|
544
|
+
function composeOne(summary, byKey) {
|
|
545
|
+
const recorded = readWrapperMetadata(summary);
|
|
546
|
+
const applied = recorded?.applied ?? [];
|
|
547
|
+
const covering = applied.filter(
|
|
548
|
+
(reference) => coversUnit(reference, summary)
|
|
549
|
+
);
|
|
550
|
+
const narrowed = covering.length === applied.length ? summary : {
|
|
551
|
+
...summary,
|
|
552
|
+
metadata: withWrapperMetadata(summary.metadata, {
|
|
553
|
+
applied: covering
|
|
554
|
+
})
|
|
555
|
+
};
|
|
556
|
+
const wrappers = covering.flatMap((reference) => {
|
|
557
|
+
const found = byKey.get(summaryKey(reference.file, reference.name));
|
|
558
|
+
return found === void 0 ? [] : [{ reference, summary: found }];
|
|
559
|
+
});
|
|
560
|
+
if (wrappers.length === 0) {
|
|
561
|
+
return narrowed;
|
|
562
|
+
}
|
|
563
|
+
let composition = {
|
|
564
|
+
transitions: summary.transitions,
|
|
565
|
+
degraded: false
|
|
566
|
+
};
|
|
567
|
+
for (const wrapper of [...wrappers].reverse()) {
|
|
568
|
+
if (wrapper.reference.onThrow === true) {
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
composition = merge(composition, applyWrapper(wrapper, composition));
|
|
572
|
+
}
|
|
573
|
+
for (const wrapper of wrappers) {
|
|
574
|
+
if (wrapper.reference.onThrow !== true) {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
composition = merge(composition, applyThrowWrapper(wrapper, composition));
|
|
578
|
+
}
|
|
579
|
+
if (composition.transitions === summary.transitions) {
|
|
580
|
+
return narrowed;
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
...narrowed,
|
|
584
|
+
transitions: withDistinctIds(composition.transitions),
|
|
585
|
+
gaps: composition.degraded ? [...summary.gaps, BUDGET_GAP] : summary.gaps
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
function merge(before, step) {
|
|
589
|
+
return {
|
|
590
|
+
transitions: step.transitions,
|
|
591
|
+
degraded: before.degraded || step.degraded
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
function coversUnit(reference, summary) {
|
|
595
|
+
if (reference.scope === void 0) {
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
const binding = summary.identity.boundaryBinding;
|
|
599
|
+
return binding !== null && withinScope(binding, reference.scope);
|
|
600
|
+
}
|
|
601
|
+
function applyWrapper(wrapper, inner) {
|
|
602
|
+
const shortCircuits = attribute(
|
|
603
|
+
wrapper.summary.transitions.filter((t) => t.output.type !== "delegate"),
|
|
604
|
+
wrapper.reference
|
|
605
|
+
);
|
|
606
|
+
const passThroughs = wrapper.summary.transitions.filter(
|
|
607
|
+
(t) => t.output.type === "delegate"
|
|
608
|
+
);
|
|
609
|
+
if (passThroughs.length === 0 || shortCircuits.length + passThroughs.length * inner.transitions.length > MAX_PATHS) {
|
|
610
|
+
return {
|
|
611
|
+
transitions: [...shortCircuits, ...inner.transitions],
|
|
612
|
+
degraded: passThroughs.length > 0
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
const continued = passThroughs.flatMap(
|
|
616
|
+
(passThrough) => inner.transitions.map((transition) => splice(passThrough, transition))
|
|
617
|
+
);
|
|
618
|
+
return { transitions: [...shortCircuits, ...continued], degraded: false };
|
|
619
|
+
}
|
|
620
|
+
function applyThrowWrapper(wrapper, inner) {
|
|
621
|
+
const thrown = inner.transitions.filter((t) => t.output.type === "throw");
|
|
622
|
+
if (thrown.length === 0) {
|
|
623
|
+
return inner;
|
|
624
|
+
}
|
|
625
|
+
const rest = inner.transitions.filter((t) => t.output.type !== "throw");
|
|
626
|
+
const handled = wrapper.summary.transitions;
|
|
627
|
+
if (rest.length + thrown.length * handled.length > MAX_PATHS) {
|
|
628
|
+
return {
|
|
629
|
+
transitions: [
|
|
630
|
+
...inner.transitions,
|
|
631
|
+
...attribute(handled, wrapper.reference)
|
|
632
|
+
],
|
|
633
|
+
degraded: true
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
const composed = thrown.flatMap(
|
|
637
|
+
(transition) => attribute(
|
|
638
|
+
handled.map((handler) => splice(transition, handler)),
|
|
639
|
+
wrapper.reference
|
|
640
|
+
)
|
|
641
|
+
);
|
|
642
|
+
return { transitions: [...rest, ...composed], degraded: false };
|
|
643
|
+
}
|
|
644
|
+
function splice(outer, inner) {
|
|
645
|
+
return {
|
|
646
|
+
...inner,
|
|
647
|
+
id: `${inner.id}:via:${outer.id}`,
|
|
648
|
+
conditions: [...outer.conditions, ...inner.conditions],
|
|
649
|
+
effects: [...outer.effects, ...inner.effects],
|
|
650
|
+
isDefault: outer.isDefault && inner.isDefault
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function attribute(transitions, reference) {
|
|
654
|
+
return transitions.map((transition) => ({
|
|
655
|
+
...transition,
|
|
656
|
+
metadata: withWrapperMetadata(transition.metadata, { from: reference })
|
|
657
|
+
}));
|
|
658
|
+
}
|
|
659
|
+
function withDistinctIds(transitions) {
|
|
660
|
+
const seen = /* @__PURE__ */ new Map();
|
|
661
|
+
return transitions.map((transition) => {
|
|
662
|
+
const taken = seen.get(transition.id);
|
|
663
|
+
seen.set(transition.id, (taken ?? 0) + 1);
|
|
664
|
+
return taken === void 0 ? transition : { ...transition, id: `${transition.id}#${taken + 1}` };
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/effectGuards.ts
|
|
591
669
|
var keyOf = (condition) => `${condition.polarity}:${condition.sourceText}`;
|
|
670
|
+
var opposite = (condition) => `${condition.polarity === "positive" ? "negative" : "positive"}:${condition.sourceText}`;
|
|
671
|
+
function guardsHoldOn(preconditions, conditions) {
|
|
672
|
+
if (preconditions === void 0 || preconditions.length === 0) {
|
|
673
|
+
return true;
|
|
674
|
+
}
|
|
675
|
+
const onBranch = new Set(conditions.map(keyOf));
|
|
676
|
+
return preconditions.every(
|
|
677
|
+
(precondition) => !onBranch.has(opposite(precondition))
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
function runsBefore(effectLine, terminalEndLine) {
|
|
681
|
+
return effectLine <= terminalEndLine;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// src/packHelpers.ts
|
|
685
|
+
function httpRouteDiscovery(opts) {
|
|
686
|
+
const kind = opts.kind ?? "handler";
|
|
687
|
+
const calls = opts.importNames.map((importName) => ({
|
|
688
|
+
kind,
|
|
689
|
+
match: {
|
|
690
|
+
type: "registrationCall",
|
|
691
|
+
importModule: opts.importModule,
|
|
692
|
+
importName,
|
|
693
|
+
registrationChain: [...opts.methods]
|
|
694
|
+
},
|
|
695
|
+
bindingExtraction: {
|
|
696
|
+
// `.all` registers every method, so it records "*", which the pairing
|
|
697
|
+
// engine treats as agreeing with any method at all.
|
|
698
|
+
method: {
|
|
699
|
+
type: "fromRegistration",
|
|
700
|
+
position: "methodName",
|
|
701
|
+
nameMap: { all: "*" }
|
|
702
|
+
},
|
|
703
|
+
path: { type: "fromArgument", position: 0 }
|
|
704
|
+
},
|
|
705
|
+
...opts.mount !== void 0 ? { mount: opts.mount } : {},
|
|
706
|
+
requiresImport: [opts.importModule]
|
|
707
|
+
}));
|
|
708
|
+
if (opts.importNames.length === 0) {
|
|
709
|
+
return calls;
|
|
710
|
+
}
|
|
711
|
+
return [
|
|
712
|
+
...calls,
|
|
713
|
+
// Routes registered in a loop over an array of specs, a shape
|
|
714
|
+
// registration-call discovery cannot see. The receiver comes from
|
|
715
|
+
// the same import declaration as the calls above, so a loop that
|
|
716
|
+
// never touches this library's routable is left alone.
|
|
717
|
+
{
|
|
718
|
+
kind,
|
|
719
|
+
match: {
|
|
720
|
+
type: "registrationLoop",
|
|
721
|
+
elementShape: LOOP_ELEMENT_SHAPE,
|
|
722
|
+
receiver: {
|
|
723
|
+
importModule: opts.importModule,
|
|
724
|
+
importNames: [...opts.importNames]
|
|
725
|
+
}
|
|
726
|
+
},
|
|
727
|
+
requiresImport: [opts.importModule]
|
|
728
|
+
}
|
|
729
|
+
];
|
|
730
|
+
}
|
|
731
|
+
function wrapperDiscovery(opts) {
|
|
732
|
+
return opts.importNames.flatMap(
|
|
733
|
+
(importName) => opts.wraps.map((wraps) => ({
|
|
734
|
+
kind: opts.kind ?? "middleware",
|
|
735
|
+
match: {
|
|
736
|
+
type: "registrationCall",
|
|
737
|
+
importModule: opts.importModule,
|
|
738
|
+
importName,
|
|
739
|
+
registrationChain: []
|
|
740
|
+
},
|
|
741
|
+
wraps: { ...wraps },
|
|
742
|
+
requiresImport: [opts.importModule]
|
|
743
|
+
}))
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
var LOOP_ELEMENT_SHAPE = {
|
|
747
|
+
methodKey: "method",
|
|
748
|
+
pathKey: "path",
|
|
749
|
+
handlerKey: "handler"
|
|
750
|
+
};
|
|
751
|
+
function registrationHelperDiscovery(helpers, kind = "handler") {
|
|
752
|
+
return helpers.map((helper) => ({
|
|
753
|
+
kind,
|
|
754
|
+
match: {
|
|
755
|
+
type: "registrationTemplate",
|
|
756
|
+
helperName: helper.helperName,
|
|
757
|
+
...helper.importModule !== void 0 ? { importModule: helper.importModule } : {},
|
|
758
|
+
...helper.subject !== void 0 ? { subject: helper.subject } : {},
|
|
759
|
+
registrations: helper.registrations.map((one) => ({ ...one }))
|
|
760
|
+
}
|
|
761
|
+
}));
|
|
762
|
+
}
|
|
763
|
+
function routeHelperIndex(opts) {
|
|
764
|
+
const methods = new Set(
|
|
765
|
+
opts.methods.map(
|
|
766
|
+
(method) => method.startsWith(".") ? method.slice(1) : method
|
|
767
|
+
)
|
|
768
|
+
);
|
|
769
|
+
return {
|
|
770
|
+
find: { by: "subject" },
|
|
771
|
+
declare: (helpers) => ({
|
|
772
|
+
discovery: registrationHelperDiscovery(
|
|
773
|
+
helpers.flatMap((helper) => routesRegisteredBy(helper, methods, opts)),
|
|
774
|
+
opts.kind ?? "handler"
|
|
775
|
+
)
|
|
776
|
+
})
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
function routesRegisteredBy(helper, methods, opts) {
|
|
780
|
+
const registrations = [];
|
|
781
|
+
let subjectArgument;
|
|
782
|
+
for (const sink of helper.sinks) {
|
|
783
|
+
const registration = routeRegisteredBy(helper, sink, methods);
|
|
784
|
+
if (registration === null) {
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
registrations.push(registration);
|
|
788
|
+
if (sink.receiver.as === "parameter") {
|
|
789
|
+
subjectArgument = sink.receiver.position;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (registrations.length === 0 || subjectArgument === void 0) {
|
|
793
|
+
return [];
|
|
794
|
+
}
|
|
795
|
+
return [
|
|
796
|
+
{
|
|
797
|
+
helperName: helper.name,
|
|
798
|
+
importModule: helper.file,
|
|
799
|
+
subject: {
|
|
800
|
+
argument: subjectArgument,
|
|
801
|
+
importModule: opts.importModule,
|
|
802
|
+
importNames: [...opts.importNames]
|
|
803
|
+
},
|
|
804
|
+
registrations
|
|
805
|
+
}
|
|
806
|
+
];
|
|
807
|
+
}
|
|
808
|
+
function routeRegisteredBy(helper, sink, methods) {
|
|
809
|
+
if (sink.method === null || !methods.has(sink.method)) {
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
const { receiver } = sink;
|
|
813
|
+
if (receiver.as !== "parameter" || receiver.property !== void 0 || !helper.subjectParameters.includes(receiver.position)) {
|
|
814
|
+
return null;
|
|
815
|
+
}
|
|
816
|
+
const pathTemplate = sink.arguments[0];
|
|
817
|
+
const handler = sink.arguments[sink.arguments.length - 1];
|
|
818
|
+
if (sink.arguments.length < 2 || pathTemplate === void 0 || pathTemplate.as !== "text" || handler === void 0) {
|
|
819
|
+
return null;
|
|
820
|
+
}
|
|
821
|
+
const handlerArg = handlerSlot(handler);
|
|
822
|
+
return handlerArg === null ? null : {
|
|
823
|
+
// `.all` registers every method, which the pairing engine
|
|
824
|
+
// spells as a wildcard.
|
|
825
|
+
method: sink.method === "all" ? "*" : sink.method.toUpperCase(),
|
|
826
|
+
pathTemplate: pathTemplate.text,
|
|
827
|
+
handlerArg
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
function handlerSlot(value) {
|
|
831
|
+
if (value.as !== "parameter") {
|
|
832
|
+
return null;
|
|
833
|
+
}
|
|
834
|
+
return value.property === void 0 ? `{${value.position}}` : `{${value.position}}.${value.property}`;
|
|
835
|
+
}
|
|
836
|
+
function unwrapJsonStringify(body) {
|
|
837
|
+
if (body === null || typeof body !== "object") {
|
|
838
|
+
return body;
|
|
839
|
+
}
|
|
840
|
+
const candidate = body;
|
|
841
|
+
if (candidate.kind !== "call" || candidate.callee !== "JSON.stringify") {
|
|
842
|
+
return body;
|
|
843
|
+
}
|
|
844
|
+
const inner = candidate.args?.[0];
|
|
845
|
+
return inner ?? body;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// src/packOptions.ts
|
|
849
|
+
import { z } from "zod";
|
|
850
|
+
var storageSystemOption = z.enum([
|
|
851
|
+
"postgresql",
|
|
852
|
+
"mysql",
|
|
853
|
+
"sqlite"
|
|
854
|
+
]);
|
|
855
|
+
var scopeOption = z.string();
|
|
856
|
+
var configuredCallOption = z.object({
|
|
857
|
+
/** Module that declares the receiver's type. */
|
|
858
|
+
module: z.string(),
|
|
859
|
+
/** Type name of the receiver, as exported from that module. */
|
|
860
|
+
receiver: z.string(),
|
|
861
|
+
/** Method that performs the send. */
|
|
862
|
+
method: z.string(),
|
|
863
|
+
/** Argument index carrying the subject. */
|
|
864
|
+
subjectArg: z.number(),
|
|
865
|
+
/**
|
|
866
|
+
* Which argument the message body is. Left out when the method has no
|
|
867
|
+
* single body argument, as a batch method taking a list of entries
|
|
868
|
+
* does, and then no body is reported.
|
|
869
|
+
*/
|
|
870
|
+
bodyArg: z.number().optional()
|
|
871
|
+
}).strict();
|
|
872
|
+
|
|
873
|
+
// src/paths/gatingConditions.ts
|
|
874
|
+
var keyOf2 = (condition) => `${condition.polarity}:${condition.sourceText}`;
|
|
592
875
|
function sharedGatingConditions(paths, readPredicate) {
|
|
593
876
|
const [first, ...rest] = paths ?? [];
|
|
594
877
|
if (first === void 0) {
|
|
595
878
|
return [];
|
|
596
879
|
}
|
|
597
|
-
const shared = new Set(first.map(
|
|
880
|
+
const shared = new Set(first.map(keyOf2));
|
|
598
881
|
for (const path of rest) {
|
|
599
|
-
const here = new Set(path.map(
|
|
882
|
+
const here = new Set(path.map(keyOf2));
|
|
600
883
|
for (const value of shared) {
|
|
601
884
|
if (!here.has(value)) {
|
|
602
885
|
shared.delete(value);
|
|
603
886
|
}
|
|
604
887
|
}
|
|
605
888
|
}
|
|
606
|
-
return first.filter((condition) => shared.has(
|
|
889
|
+
return first.filter((condition) => shared.has(keyOf2(condition))).map((condition) => ({
|
|
607
890
|
sourceText: condition.sourceText,
|
|
608
891
|
structured: readPredicate === void 0 || condition.expression === null ? null : readPredicate(condition.expression),
|
|
609
892
|
polarity: condition.polarity,
|
|
@@ -657,6 +940,21 @@ var IdMap = class {
|
|
|
657
940
|
}
|
|
658
941
|
};
|
|
659
942
|
|
|
943
|
+
// src/paths/nodeWalk.ts
|
|
944
|
+
var SKIP_CHILDREN = /* @__PURE__ */ Symbol("skipChildren");
|
|
945
|
+
function walkDescendants(root, carried, visitor) {
|
|
946
|
+
for (const child of root.namedChildren) {
|
|
947
|
+
if (child === null) {
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
visitor.at(child, carried);
|
|
951
|
+
const inner = visitor.into(child, carried);
|
|
952
|
+
if (inner !== SKIP_CHILDREN) {
|
|
953
|
+
walkDescendants(child, inner, visitor);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
660
958
|
// src/reading.ts
|
|
661
959
|
function writtenReading(value, range) {
|
|
662
960
|
return { kind: "written", value, range };
|
|
@@ -823,6 +1121,7 @@ function assembleSummary(raw, options = DEFAULT_OPTIONS) {
|
|
|
823
1121
|
location: {
|
|
824
1122
|
file: raw.identity.file,
|
|
825
1123
|
range: raw.identity.range,
|
|
1124
|
+
...raw.identity.span !== void 0 ? { span: raw.identity.span } : {},
|
|
826
1125
|
exportName: raw.identity.exportName
|
|
827
1126
|
},
|
|
828
1127
|
identity: {
|
|
@@ -856,6 +1155,12 @@ function buildMetadata(raw) {
|
|
|
856
1155
|
label: raw.sourceDocumentLabel
|
|
857
1156
|
});
|
|
858
1157
|
}
|
|
1158
|
+
if (raw.mount !== void 0) {
|
|
1159
|
+
metadata = withMountMetadata(metadata, raw.mount);
|
|
1160
|
+
}
|
|
1161
|
+
if (raw.wrappers !== void 0 && raw.wrappers.length > 0) {
|
|
1162
|
+
metadata = withWrapperMetadata2(metadata, { applied: raw.wrappers });
|
|
1163
|
+
}
|
|
859
1164
|
return Object.keys(metadata).length > 0 ? metadata : null;
|
|
860
1165
|
}
|
|
861
1166
|
function buildHttpMetadataValue(raw) {
|
|
@@ -1118,27 +1423,39 @@ function paramToInput(param) {
|
|
|
1118
1423
|
export {
|
|
1119
1424
|
IdMap,
|
|
1120
1425
|
IdSet,
|
|
1426
|
+
MAX_PATHS,
|
|
1121
1427
|
PathBudgetExceeded,
|
|
1428
|
+
SKIP_CHILDREN,
|
|
1122
1429
|
UnmodeledFlow,
|
|
1123
1430
|
absentReading,
|
|
1124
1431
|
ambiguousReading,
|
|
1125
1432
|
andThenReading,
|
|
1126
1433
|
assembleSummary,
|
|
1127
1434
|
assessConfidence,
|
|
1435
|
+
composeWrappers,
|
|
1436
|
+
configuredCallOption,
|
|
1128
1437
|
detectGaps,
|
|
1129
1438
|
effectToIR,
|
|
1130
1439
|
enumerateOrDegrade,
|
|
1131
1440
|
enumerateStructuredPaths,
|
|
1132
1441
|
firstWrittenReading,
|
|
1442
|
+
guardsHoldOn,
|
|
1133
1443
|
httpRouteDiscovery,
|
|
1134
1444
|
makeTransitionId,
|
|
1135
1445
|
mapReading,
|
|
1136
1446
|
paramToInput,
|
|
1447
|
+
rawConditionToPredicate,
|
|
1137
1448
|
registrationHelperDiscovery,
|
|
1449
|
+
routeHelperIndex,
|
|
1450
|
+
runsBefore,
|
|
1451
|
+
scopeOption,
|
|
1138
1452
|
sharedGatingConditions,
|
|
1453
|
+
storageSystemOption,
|
|
1139
1454
|
terminalToOutput,
|
|
1140
1455
|
unreadableReading,
|
|
1141
1456
|
unwrapJsonStringify,
|
|
1142
1457
|
valueToReadFurtherFrom,
|
|
1458
|
+
walkDescendants,
|
|
1459
|
+
wrapperDiscovery,
|
|
1143
1460
|
writtenReading
|
|
1144
1461
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/extractor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Framework-agnostic extraction pipeline that turns raw extractions into suss behavioral summaries.",
|
|
6
6
|
"keywords": [
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
"typecheck": "tsc --noEmit"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@suss/behavioral-ir": "0.
|
|
48
|
+
"@suss/behavioral-ir": "0.21.0",
|
|
49
|
+
"zod": "^4.0.0"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"tsup": "*",
|