@suss/adapter-ruby 0.34.0 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1442 -365
- package/dist/index.d.cts +86 -13
- package/dist/index.d.ts +86 -13
- package/dist/index.js +1345 -261
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
bindEvaluator: () => bindEvaluator,
|
|
37
37
|
bodyStatements: () => bodyStatements,
|
|
38
38
|
booleanLiteralValue: () => booleanLiteralValue,
|
|
39
|
+
children: () => children,
|
|
39
40
|
collectFileConstants: () => collectFileConstants,
|
|
40
41
|
createConstantFileCache: () => createConstantFileCache,
|
|
41
42
|
createFileCache: () => createFileCache,
|
|
@@ -97,7 +98,29 @@ function field(node, name) {
|
|
|
97
98
|
return node.childForFieldName(name);
|
|
98
99
|
}
|
|
99
100
|
function children(node) {
|
|
100
|
-
|
|
101
|
+
if (node === null || node === void 0) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
const found = [];
|
|
105
|
+
const count = node.namedChildCount;
|
|
106
|
+
for (let index = 0; index < count; index++) {
|
|
107
|
+
const child = node.namedChild(index);
|
|
108
|
+
if (child !== null) {
|
|
109
|
+
found.push(child);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return found;
|
|
113
|
+
}
|
|
114
|
+
function allChildren(node) {
|
|
115
|
+
const found = [];
|
|
116
|
+
const count = node.childCount;
|
|
117
|
+
for (let index = 0; index < count; index++) {
|
|
118
|
+
const child = node.child(index);
|
|
119
|
+
if (child !== null) {
|
|
120
|
+
found.push(child);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return found;
|
|
101
124
|
}
|
|
102
125
|
function bodyStatements(body) {
|
|
103
126
|
return children(body);
|
|
@@ -159,6 +182,13 @@ var MODULE_SCOPE_STOPS = /* @__PURE__ */ new Set([
|
|
|
159
182
|
var NESTING_TYPES = /* @__PURE__ */ new Set(["class", "module"]);
|
|
160
183
|
var METHOD_TYPES = /* @__PURE__ */ new Set(["method", "singleton_method"]);
|
|
161
184
|
var LAMBDA_TYPE = "lambda";
|
|
185
|
+
var RAISING_METHODS = /* @__PURE__ */ new Set(["raise", "fail"]);
|
|
186
|
+
function isRaiseCall(node) {
|
|
187
|
+
if (node.type === "identifier") {
|
|
188
|
+
return RAISING_METHODS.has(node.text);
|
|
189
|
+
}
|
|
190
|
+
return node.type === "call" && field(node, "receiver") === null && RAISING_METHODS.has(field(node, "method")?.text ?? "");
|
|
191
|
+
}
|
|
162
192
|
function enclosingDefinition(node) {
|
|
163
193
|
return definitionsAround.of(node);
|
|
164
194
|
}
|
|
@@ -234,7 +264,7 @@ function runStatements(body, blockConfigures = () => false) {
|
|
|
234
264
|
}
|
|
235
265
|
return !(node.type === "call" && blockConfigures(node));
|
|
236
266
|
};
|
|
237
|
-
(0, import_extractor.walkDescendants)(body, null, {
|
|
267
|
+
(0, import_extractor.walkDescendants)(body, null, children, {
|
|
238
268
|
at: (node) => {
|
|
239
269
|
found.push(node);
|
|
240
270
|
},
|
|
@@ -521,6 +551,51 @@ function readCallArgs(argumentList) {
|
|
|
521
551
|
}
|
|
522
552
|
return { positional, keyword };
|
|
523
553
|
}
|
|
554
|
+
var CONTROL_OPERATORS = /* @__PURE__ */ new Set([
|
|
555
|
+
"and",
|
|
556
|
+
"or",
|
|
557
|
+
"&&",
|
|
558
|
+
"||"
|
|
559
|
+
]);
|
|
560
|
+
var HANDS_ON = /* @__PURE__ */ new Set(["return", "next", "break"]);
|
|
561
|
+
var isChild = (fieldName) => (parent, child) => field(parent, fieldName)?.id === child.id;
|
|
562
|
+
var always = () => true;
|
|
563
|
+
var asCondition = isChild("condition");
|
|
564
|
+
var VALUE_USED_UNDER = {
|
|
565
|
+
assignment: isChild("right"),
|
|
566
|
+
operator_assignment: isChild("right"),
|
|
567
|
+
call: isChild("receiver"),
|
|
568
|
+
element_reference: always,
|
|
569
|
+
argument_list: (parent) => !HANDS_ON.has(parent.parent?.type ?? ""),
|
|
570
|
+
pair: always,
|
|
571
|
+
array: always,
|
|
572
|
+
hash: always,
|
|
573
|
+
interpolation: always,
|
|
574
|
+
unary: always,
|
|
575
|
+
binary: (parent) => !CONTROL_OPERATORS.has(field(parent, "operator")?.text ?? ""),
|
|
576
|
+
if: asCondition,
|
|
577
|
+
unless: asCondition,
|
|
578
|
+
while: asCondition,
|
|
579
|
+
until: asCondition,
|
|
580
|
+
if_modifier: asCondition,
|
|
581
|
+
unless_modifier: asCondition,
|
|
582
|
+
while_modifier: asCondition,
|
|
583
|
+
until_modifier: asCondition,
|
|
584
|
+
conditional: asCondition,
|
|
585
|
+
case: isChild("value")
|
|
586
|
+
};
|
|
587
|
+
function resultUsedAsValue(node) {
|
|
588
|
+
let child = node;
|
|
589
|
+
let parent = node.parent;
|
|
590
|
+
while (parent !== null && parent.type === "parenthesized_statements" && parent.namedChildCount === 1) {
|
|
591
|
+
child = parent;
|
|
592
|
+
parent = parent.parent;
|
|
593
|
+
}
|
|
594
|
+
if (parent === null) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
return VALUE_USED_UNDER[parent.type]?.(parent, child) ?? false;
|
|
598
|
+
}
|
|
524
599
|
var NodeSet = class extends import_extractor.IdSet {
|
|
525
600
|
};
|
|
526
601
|
var NodeMap = class extends import_extractor.IdMap {
|
|
@@ -555,19 +630,23 @@ var PATH_CONVENTIONS = {
|
|
|
555
630
|
function createConstantFileCache() {
|
|
556
631
|
return { autoloadDirectories: /* @__PURE__ */ new Map(), resolved: /* @__PURE__ */ new Map() };
|
|
557
632
|
}
|
|
558
|
-
function resolveConstantFile(root, qualifiedName, convention, acronyms = [], cache = createConstantFileCache()) {
|
|
633
|
+
function resolveConstantFile(root, qualifiedName, convention, acronyms = [], cache = createConstantFileCache(), autoloadRoots = []) {
|
|
559
634
|
const relative = `${PATH_CONVENTIONS[convention](qualifiedName, acronyms)}.rb`;
|
|
560
|
-
const key =
|
|
635
|
+
const key = [root, ...autoloadRoots, relative].join("\0");
|
|
561
636
|
const known = cache.resolved.get(key);
|
|
562
637
|
if (known !== void 0) {
|
|
563
638
|
return known;
|
|
564
639
|
}
|
|
565
|
-
const found = firstExisting(root, relative, cache);
|
|
640
|
+
const found = firstExisting(root, relative, cache, autoloadRoots);
|
|
566
641
|
cache.resolved.set(key, found);
|
|
567
642
|
return found;
|
|
568
643
|
}
|
|
569
|
-
function firstExisting(root, relative, cache) {
|
|
570
|
-
for (const candidate of [
|
|
644
|
+
function firstExisting(root, relative, cache, autoloadRoots) {
|
|
645
|
+
for (const candidate of [
|
|
646
|
+
root,
|
|
647
|
+
...autoloadDirectoriesOf(root, cache),
|
|
648
|
+
...autoloadRoots
|
|
649
|
+
]) {
|
|
571
650
|
const file = import_node_path.default.join(candidate, relative);
|
|
572
651
|
if (import_node_fs.default.existsSync(file)) {
|
|
573
652
|
return file;
|
|
@@ -614,6 +693,7 @@ var import_resolution5 = require("@suss/resolution");
|
|
|
614
693
|
var import_values2 = require("@suss/values");
|
|
615
694
|
|
|
616
695
|
// src/facts/resolve.ts
|
|
696
|
+
var import_behavioral_ir = require("@suss/behavioral-ir");
|
|
617
697
|
var import_datalog = require("@suss/datalog");
|
|
618
698
|
var import_resolution = require("@suss/resolution");
|
|
619
699
|
|
|
@@ -630,6 +710,71 @@ var CONVERTING_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
|
630
710
|
"String",
|
|
631
711
|
"Float"
|
|
632
712
|
]);
|
|
713
|
+
var OBJECT_METHODS = /* @__PURE__ */ new Set([
|
|
714
|
+
"Array",
|
|
715
|
+
"Float",
|
|
716
|
+
"Hash",
|
|
717
|
+
"Integer",
|
|
718
|
+
"String",
|
|
719
|
+
"abort",
|
|
720
|
+
"binding",
|
|
721
|
+
"block_given?",
|
|
722
|
+
"caller",
|
|
723
|
+
"catch",
|
|
724
|
+
"class",
|
|
725
|
+
"clone",
|
|
726
|
+
"define_singleton_method",
|
|
727
|
+
"dup",
|
|
728
|
+
"eql?",
|
|
729
|
+
"equal?",
|
|
730
|
+
"eval",
|
|
731
|
+
"exit",
|
|
732
|
+
"extend",
|
|
733
|
+
"fail",
|
|
734
|
+
"format",
|
|
735
|
+
"freeze",
|
|
736
|
+
"frozen?",
|
|
737
|
+
"hash",
|
|
738
|
+
"inspect",
|
|
739
|
+
"instance_of?",
|
|
740
|
+
"instance_variable_defined?",
|
|
741
|
+
"instance_variable_get",
|
|
742
|
+
"instance_variable_set",
|
|
743
|
+
"instance_variables",
|
|
744
|
+
"is_a?",
|
|
745
|
+
"itself",
|
|
746
|
+
"kind_of?",
|
|
747
|
+
"lambda",
|
|
748
|
+
"loop",
|
|
749
|
+
"method",
|
|
750
|
+
"methods",
|
|
751
|
+
"nil?",
|
|
752
|
+
"object_id",
|
|
753
|
+
"p",
|
|
754
|
+
"pp",
|
|
755
|
+
"print",
|
|
756
|
+
"printf",
|
|
757
|
+
"proc",
|
|
758
|
+
"public_send",
|
|
759
|
+
"puts",
|
|
760
|
+
"raise",
|
|
761
|
+
"rand",
|
|
762
|
+
"require",
|
|
763
|
+
"require_relative",
|
|
764
|
+
"respond_to?",
|
|
765
|
+
"send",
|
|
766
|
+
"singleton_class",
|
|
767
|
+
"sleep",
|
|
768
|
+
"sprintf",
|
|
769
|
+
"srand",
|
|
770
|
+
"system",
|
|
771
|
+
"tap",
|
|
772
|
+
"then",
|
|
773
|
+
"throw",
|
|
774
|
+
"to_s",
|
|
775
|
+
"warn",
|
|
776
|
+
"yield_self"
|
|
777
|
+
]);
|
|
633
778
|
var CONSTRUCTOR = "new";
|
|
634
779
|
|
|
635
780
|
// src/facts/resolve.ts
|
|
@@ -677,7 +822,13 @@ function resolveEnvObjects(db, objects) {
|
|
|
677
822
|
}
|
|
678
823
|
function writtenValueOf(db, key) {
|
|
679
824
|
resolveValues(db, [key]);
|
|
680
|
-
return (0, import_resolution.writtenValueOf)(
|
|
825
|
+
return (0, import_resolution.writtenValueOf)(
|
|
826
|
+
db,
|
|
827
|
+
key,
|
|
828
|
+
(keys) => resolveValues(db, keys),
|
|
829
|
+
void 0,
|
|
830
|
+
(0, import_resolution.answersFromTestsLeftOut)(key, import_behavioral_ir.isTestFile)
|
|
831
|
+
);
|
|
681
832
|
}
|
|
682
833
|
function writtenValueUnder(db, key, site) {
|
|
683
834
|
const program = (0, import_resolution.resolutionUnderProgram)(RUBY_RULES);
|
|
@@ -709,7 +860,7 @@ function isFieldOf(parent, node, name) {
|
|
|
709
860
|
function namedAt(parent, node) {
|
|
710
861
|
return isFieldOf(parent, node, "name");
|
|
711
862
|
}
|
|
712
|
-
function
|
|
863
|
+
function always2() {
|
|
713
864
|
return true;
|
|
714
865
|
}
|
|
715
866
|
var SPELLS_A_NAME = {
|
|
@@ -724,14 +875,14 @@ var SPELLS_A_NAME = {
|
|
|
724
875
|
hash_splat_parameter: namedAt,
|
|
725
876
|
keyword_parameter: namedAt,
|
|
726
877
|
block_parameter: namedAt,
|
|
727
|
-
destructured_parameter:
|
|
728
|
-
left_assignment_list:
|
|
729
|
-
rest_assignment:
|
|
730
|
-
destructured_left_assignment:
|
|
731
|
-
exception_variable:
|
|
732
|
-
undef:
|
|
733
|
-
alias:
|
|
734
|
-
...Object.fromEntries(PARAMETER_LIST_TYPES.map((type) => [type,
|
|
878
|
+
destructured_parameter: always2,
|
|
879
|
+
left_assignment_list: always2,
|
|
880
|
+
rest_assignment: always2,
|
|
881
|
+
destructured_left_assignment: always2,
|
|
882
|
+
exception_variable: always2,
|
|
883
|
+
undef: always2,
|
|
884
|
+
alias: always2,
|
|
885
|
+
...Object.fromEntries(PARAMETER_LIST_TYPES.map((type) => [type, always2]))
|
|
735
886
|
};
|
|
736
887
|
function addNamesUnder(node, names) {
|
|
737
888
|
if (node === null) {
|
|
@@ -1550,9 +1701,7 @@ function emitKeyedElement(emitter, node, parent) {
|
|
|
1550
1701
|
if (object === null || isWriteTarget(node, parent)) {
|
|
1551
1702
|
return;
|
|
1552
1703
|
}
|
|
1553
|
-
const index = node.
|
|
1554
|
-
(child) => child !== null && child.id !== object.id
|
|
1555
|
-
);
|
|
1704
|
+
const index = children(node).find((child) => child.id !== object.id);
|
|
1556
1705
|
if (index !== void 0) {
|
|
1557
1706
|
emitKeyedRead(emitter, node, object, index, node);
|
|
1558
1707
|
emitWrittenKeyRead(emitter, node, object, index);
|
|
@@ -1593,17 +1742,17 @@ function fallbackBranchesOf(node, type, enclosing) {
|
|
|
1593
1742
|
}
|
|
1594
1743
|
return [left, right].filter((side) => !raises(side, enclosing));
|
|
1595
1744
|
}
|
|
1596
|
-
var
|
|
1745
|
+
var RAISING_METHODS2 = /* @__PURE__ */ new Set(["raise", "fail"]);
|
|
1597
1746
|
function raises(written, enclosing) {
|
|
1598
1747
|
const node = readThrough(written);
|
|
1599
1748
|
if (node.type === "identifier") {
|
|
1600
|
-
return
|
|
1749
|
+
return RAISING_METHODS2.has(node.text) && isBareCall(node, enclosing);
|
|
1601
1750
|
}
|
|
1602
1751
|
if (node.type !== "call") {
|
|
1603
1752
|
return false;
|
|
1604
1753
|
}
|
|
1605
1754
|
const receiver = field(node, "receiver");
|
|
1606
|
-
return
|
|
1755
|
+
return RAISING_METHODS2.has(field(node, "method")?.text ?? "") && (receiver === null || receiver.text === "Kernel");
|
|
1607
1756
|
}
|
|
1608
1757
|
function emitExpressionFacts(emitter, node) {
|
|
1609
1758
|
emitDynamicDefinition(emitter, node, node.type, []);
|
|
@@ -2559,9 +2708,7 @@ var EXPRESSION_TYPES = {
|
|
|
2559
2708
|
),
|
|
2560
2709
|
unary: (node) => {
|
|
2561
2710
|
const operand2 = field(node, "operand");
|
|
2562
|
-
const operator = node.
|
|
2563
|
-
(child) => child !== null && !child.isNamed
|
|
2564
|
-
);
|
|
2711
|
+
const operator = allChildren(node).find((child) => !child.isNamed);
|
|
2565
2712
|
if (operand2 === null || operator === void 0) {
|
|
2566
2713
|
return OPAQUE;
|
|
2567
2714
|
}
|
|
@@ -2763,8 +2910,25 @@ function statementOf(node) {
|
|
|
2763
2910
|
if (appending !== null) {
|
|
2764
2911
|
return appending;
|
|
2765
2912
|
}
|
|
2913
|
+
if (isRaiseCall(node) && !rescuedInSameFunction(node)) {
|
|
2914
|
+
return { kind: "throw" };
|
|
2915
|
+
}
|
|
2766
2916
|
return isTailExpression(node) ? { kind: "return", value: node } : { kind: "expression", value: node };
|
|
2767
2917
|
}
|
|
2918
|
+
var RESCUING_TYPES = /* @__PURE__ */ new Set(["begin", "body_statement"]);
|
|
2919
|
+
var UNRESCUED_PARTS = /* @__PURE__ */ new Set(["rescue", "else", "ensure"]);
|
|
2920
|
+
function rescuedInSameFunction(node) {
|
|
2921
|
+
let child = node;
|
|
2922
|
+
let parent = node.parent;
|
|
2923
|
+
while (parent !== null && !isRoot(parent)) {
|
|
2924
|
+
if (RESCUING_TYPES.has(parent.type) && !UNRESCUED_PARTS.has(child.type) && children(parent).some((part) => part.type === "rescue")) {
|
|
2925
|
+
return true;
|
|
2926
|
+
}
|
|
2927
|
+
child = parent;
|
|
2928
|
+
parent = parent.parent;
|
|
2929
|
+
}
|
|
2930
|
+
return false;
|
|
2931
|
+
}
|
|
2768
2932
|
function appendingStatement(node) {
|
|
2769
2933
|
if (node.type !== "binary" || field(node, "operator")?.text !== "<<") {
|
|
2770
2934
|
return null;
|
|
@@ -3420,6 +3584,10 @@ function writtenNodeOf(node, db, site) {
|
|
|
3420
3584
|
const context = db === void 0 ? void 0 : contexts.get(db);
|
|
3421
3585
|
return context === void 0 ? null : context.writtenTo(node, site);
|
|
3422
3586
|
}
|
|
3587
|
+
function calledDefinition(call, db) {
|
|
3588
|
+
const context = db === void 0 ? void 0 : contexts.get(db);
|
|
3589
|
+
return context === void 0 ? null : context.callable(call);
|
|
3590
|
+
}
|
|
3423
3591
|
function askWrittenValues(nodes, db) {
|
|
3424
3592
|
if (db === void 0 || !contexts.has(db)) {
|
|
3425
3593
|
return;
|
|
@@ -3482,7 +3650,7 @@ function methodDefinitionsIn(file, root) {
|
|
|
3482
3650
|
if (METHOD_TYPES.has(node.type)) {
|
|
3483
3651
|
found.set(nodeId(file, node), node);
|
|
3484
3652
|
}
|
|
3485
|
-
for (const child of node
|
|
3653
|
+
for (const child of children(node)) {
|
|
3486
3654
|
if (child !== null) {
|
|
3487
3655
|
visit(child);
|
|
3488
3656
|
}
|
|
@@ -3808,12 +3976,27 @@ function graphqlTypeNameFromQualified(qualifiedName, convention) {
|
|
|
3808
3976
|
|
|
3809
3977
|
// src/ancestry.ts
|
|
3810
3978
|
async function reachDefinition(qualifiedName, lookup) {
|
|
3979
|
+
const segments = qualifiedName.split("::");
|
|
3980
|
+
for (let length = segments.length; length > 0; length--) {
|
|
3981
|
+
const found = await definedInFileOf(
|
|
3982
|
+
segments.slice(0, length).join("::"),
|
|
3983
|
+
qualifiedName,
|
|
3984
|
+
lookup
|
|
3985
|
+
);
|
|
3986
|
+
if (found !== null) {
|
|
3987
|
+
return found;
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
return null;
|
|
3991
|
+
}
|
|
3992
|
+
async function definedInFileOf(fileConstant, qualifiedName, lookup) {
|
|
3811
3993
|
const filePath = resolveConstantFile(
|
|
3812
3994
|
lookup.root,
|
|
3813
|
-
|
|
3995
|
+
fileConstant,
|
|
3814
3996
|
lookup.pathConvention,
|
|
3815
3997
|
lookup.acronyms,
|
|
3816
|
-
lookup.constantFiles
|
|
3998
|
+
lookup.constantFiles,
|
|
3999
|
+
lookup.autoloadRoots
|
|
3817
4000
|
);
|
|
3818
4001
|
if (filePath === null) {
|
|
3819
4002
|
return null;
|
|
@@ -3958,7 +4141,7 @@ function superclassCandidatesOf(blocks) {
|
|
|
3958
4141
|
return [];
|
|
3959
4142
|
}
|
|
3960
4143
|
function methodInAncestry(ancestry, name, read = {}) {
|
|
3961
|
-
for (const entry of ancestry) {
|
|
4144
|
+
for (const [index, entry] of ancestry.entries()) {
|
|
3962
4145
|
if (entry.type === "root") {
|
|
3963
4146
|
return { type: "none" };
|
|
3964
4147
|
}
|
|
@@ -3966,7 +4149,8 @@ function methodInAncestry(ancestry, name, read = {}) {
|
|
|
3966
4149
|
return {
|
|
3967
4150
|
type: "unsettled",
|
|
3968
4151
|
reason: `inherited from ${entry.name}, which this run did not read`,
|
|
3969
|
-
cause: "unreadAncestor"
|
|
4152
|
+
cause: "unreadAncestor",
|
|
4153
|
+
definedLater: definedInProjectAfter(ancestry, index, name, read)
|
|
3970
4154
|
};
|
|
3971
4155
|
}
|
|
3972
4156
|
const found = definitionIn(entry.blocks, name, read);
|
|
@@ -3983,6 +4167,18 @@ function methodInAncestry(ancestry, name, read = {}) {
|
|
|
3983
4167
|
}
|
|
3984
4168
|
return { type: "none" };
|
|
3985
4169
|
}
|
|
4170
|
+
function definedInProjectAfter(ancestry, index, name, read) {
|
|
4171
|
+
return ancestry.slice(index + 1).some(
|
|
4172
|
+
(entry) => entry.type !== "root" && entry.type !== "unfollowed" && definitionIn(entry.blocks, name, read).method !== null
|
|
4173
|
+
);
|
|
4174
|
+
}
|
|
4175
|
+
function methodPastUnreadAncestors(ancestry, name, read = {}) {
|
|
4176
|
+
return methodInAncestry(
|
|
4177
|
+
ancestry.filter((entry) => entry.type !== "unfollowed"),
|
|
4178
|
+
name,
|
|
4179
|
+
read
|
|
4180
|
+
);
|
|
4181
|
+
}
|
|
3986
4182
|
function definitionIn(blocks, name, read) {
|
|
3987
4183
|
let method = null;
|
|
3988
4184
|
let block = null;
|
|
@@ -4027,12 +4223,12 @@ function inheritedStatements(ancestry, blockConfigures) {
|
|
|
4027
4223
|
}
|
|
4028
4224
|
|
|
4029
4225
|
// src/discovery.ts
|
|
4030
|
-
var
|
|
4031
|
-
var
|
|
4226
|
+
var import_behavioral_ir6 = require("@suss/behavioral-ir");
|
|
4227
|
+
var import_extractor11 = require("@suss/extractor");
|
|
4032
4228
|
|
|
4033
4229
|
// src/clientCalls.ts
|
|
4034
|
-
var
|
|
4035
|
-
var
|
|
4230
|
+
var import_behavioral_ir2 = require("@suss/behavioral-ir");
|
|
4231
|
+
var import_values14 = require("@suss/values");
|
|
4036
4232
|
|
|
4037
4233
|
// src/paths/effects.ts
|
|
4038
4234
|
var import_extractor2 = require("@suss/extractor");
|
|
@@ -4059,7 +4255,7 @@ function isRaise(node) {
|
|
|
4059
4255
|
return false;
|
|
4060
4256
|
}
|
|
4061
4257
|
const receiver = field(node, "receiver");
|
|
4062
|
-
const method = field(node, "method") ?? node.
|
|
4258
|
+
const method = field(node, "method") ?? node.namedChild(0) ?? null;
|
|
4063
4259
|
return receiver === null && method !== null && RAISE_NAMES.has(method.text);
|
|
4064
4260
|
}
|
|
4065
4261
|
function exitOf(node) {
|
|
@@ -4071,7 +4267,7 @@ function exitOf(node) {
|
|
|
4071
4267
|
function exitKindOf(node) {
|
|
4072
4268
|
let sawReturn = false;
|
|
4073
4269
|
const raises2 = (current) => {
|
|
4074
|
-
for (const child of current
|
|
4270
|
+
for (const child of children(current)) {
|
|
4075
4271
|
if (child === null || CAPTURES_RETURN.has(child.type)) {
|
|
4076
4272
|
continue;
|
|
4077
4273
|
}
|
|
@@ -4105,13 +4301,52 @@ function callHeaderOf(call, block) {
|
|
|
4105
4301
|
function blockStatements(block) {
|
|
4106
4302
|
return block === null ? [] : children(block);
|
|
4107
4303
|
}
|
|
4304
|
+
function attachedBlockOf(call) {
|
|
4305
|
+
return children(call).find(
|
|
4306
|
+
(child) => child !== null && (child.type === "do_block" || child.type === "block")
|
|
4307
|
+
) ?? null;
|
|
4308
|
+
}
|
|
4309
|
+
function soleBlockParameter(block) {
|
|
4310
|
+
const names = children(field(block, "parameters")).filter(
|
|
4311
|
+
(child) => child.type === "identifier"
|
|
4312
|
+
);
|
|
4313
|
+
return names.length === 1 ? names[0].text : null;
|
|
4314
|
+
}
|
|
4315
|
+
function blockBodyStatements(block) {
|
|
4316
|
+
const body = field(block, "body");
|
|
4317
|
+
if (body !== null) {
|
|
4318
|
+
return children(body);
|
|
4319
|
+
}
|
|
4320
|
+
return children(block).filter((child) => child.type !== "block_parameters");
|
|
4321
|
+
}
|
|
4322
|
+
function armBody(block) {
|
|
4323
|
+
return field(block, "body") ?? block;
|
|
4324
|
+
}
|
|
4325
|
+
function formatArmOf(statement, parameter) {
|
|
4326
|
+
if (statement.type !== "call") {
|
|
4327
|
+
return null;
|
|
4328
|
+
}
|
|
4329
|
+
const receiver = field(statement, "receiver");
|
|
4330
|
+
const format = field(statement, "method")?.text;
|
|
4331
|
+
if (receiver?.text !== parameter || format === void 0) {
|
|
4332
|
+
return null;
|
|
4333
|
+
}
|
|
4334
|
+
const block = attachedBlockOf(statement);
|
|
4335
|
+
return {
|
|
4336
|
+
format,
|
|
4337
|
+
header: block === null ? statement.text : callHeaderOf(statement, block).sourceText,
|
|
4338
|
+
block
|
|
4339
|
+
};
|
|
4340
|
+
}
|
|
4108
4341
|
var Lowerer = class {
|
|
4109
|
-
constructor(terminals, responseCalls) {
|
|
4342
|
+
constructor(terminals, responseCalls, formatSwitch) {
|
|
4110
4343
|
this.terminals = terminals;
|
|
4111
4344
|
this.responseCalls = responseCalls;
|
|
4345
|
+
this.formatSwitch = formatSwitch;
|
|
4112
4346
|
}
|
|
4113
4347
|
terminals;
|
|
4114
4348
|
responseCalls;
|
|
4349
|
+
formatSwitch;
|
|
4115
4350
|
terminalsByStmt = /* @__PURE__ */ new Map();
|
|
4116
4351
|
terminalHome = new NodeMap();
|
|
4117
4352
|
attachTerminals(statement, found) {
|
|
@@ -4142,7 +4377,7 @@ var Lowerer = class {
|
|
|
4142
4377
|
found.push(own);
|
|
4143
4378
|
return found;
|
|
4144
4379
|
}
|
|
4145
|
-
for (const child of node
|
|
4380
|
+
for (const child of children(node)) {
|
|
4146
4381
|
if (child !== null && !OWN_BODY_TYPES.has(child.type)) {
|
|
4147
4382
|
this.responsesIn(child, found);
|
|
4148
4383
|
}
|
|
@@ -4201,29 +4436,22 @@ var Lowerer = class {
|
|
|
4201
4436
|
};
|
|
4202
4437
|
}
|
|
4203
4438
|
lowerBegin(node) {
|
|
4204
|
-
const
|
|
4205
|
-
|
|
4206
|
-
)
|
|
4207
|
-
const ensureClause = node.namedChildren.find(
|
|
4208
|
-
(child) => child !== null && child.type === "ensure"
|
|
4209
|
-
) ?? null;
|
|
4210
|
-
const tryBody = node.namedChildren.filter(
|
|
4439
|
+
const rescues2 = children(node).filter((child) => child.type === "rescue");
|
|
4440
|
+
const ensureClause = children(node).find((child) => child.type === "ensure") ?? null;
|
|
4441
|
+
const tryBody = children(node).filter(
|
|
4211
4442
|
(child) => child !== null && child.type !== "rescue" && child.type !== "ensure" && child.type !== "else"
|
|
4212
4443
|
);
|
|
4213
4444
|
return {
|
|
4214
4445
|
kind: "try",
|
|
4215
4446
|
tryBody: tryBody.map((statement) => this.lower(statement)),
|
|
4216
|
-
catchBody:
|
|
4447
|
+
catchBody: rescues2.length > 0 ? rescues2.flatMap((clause) => this.lowerBlock(field(clause, "body"))) : null,
|
|
4217
4448
|
finallyBody: ensureClause === null ? null : this.lowerBlock(ensureClause),
|
|
4218
4449
|
exitKind: exitKindOf(node)
|
|
4219
4450
|
};
|
|
4220
4451
|
}
|
|
4221
4452
|
lowerCase(node) {
|
|
4222
4453
|
const groups = [];
|
|
4223
|
-
for (const child of node
|
|
4224
|
-
if (child === null) {
|
|
4225
|
-
continue;
|
|
4226
|
-
}
|
|
4454
|
+
for (const child of children(node)) {
|
|
4227
4455
|
if (child.type === "when") {
|
|
4228
4456
|
groups.push({
|
|
4229
4457
|
condition: handleOf(field(child, "pattern")),
|
|
@@ -4241,6 +4469,47 @@ var Lowerer = class {
|
|
|
4241
4469
|
}
|
|
4242
4470
|
return { kind: "switch", groups, exitKind: exitKindOf(node) };
|
|
4243
4471
|
}
|
|
4472
|
+
/**
|
|
4473
|
+
* `respond_to do |format| ... end` runs one arm per request, picked by
|
|
4474
|
+
* the format the request accepts, so it lowers to a switch with an arm
|
|
4475
|
+
* per `format.x`. The arm that accepts every format is the default.
|
|
4476
|
+
* Without one, a request no arm accepts makes the library raise. Null
|
|
4477
|
+
* when the block contains anything besides those arms.
|
|
4478
|
+
*/
|
|
4479
|
+
lowerFormatSwitch(node, block) {
|
|
4480
|
+
const declared = this.formatSwitch;
|
|
4481
|
+
if (declared === void 0 || node.type !== "call" || field(node, "receiver") !== null || field(node, "method")?.text !== declared.name) {
|
|
4482
|
+
return null;
|
|
4483
|
+
}
|
|
4484
|
+
const parameter = soleBlockParameter(block);
|
|
4485
|
+
if (parameter === null) {
|
|
4486
|
+
return null;
|
|
4487
|
+
}
|
|
4488
|
+
const arms = blockBodyStatements(block).map(
|
|
4489
|
+
(statement) => formatArmOf(statement, parameter)
|
|
4490
|
+
);
|
|
4491
|
+
if (arms.length === 0 || arms.some((arm) => arm === null)) {
|
|
4492
|
+
return null;
|
|
4493
|
+
}
|
|
4494
|
+
const groups = arms.map(
|
|
4495
|
+
(arm) => ({
|
|
4496
|
+
condition: arm.format === declared.matchesEvery ? null : { sourceText: arm.header, expression: null },
|
|
4497
|
+
hasTrailingBreak: true,
|
|
4498
|
+
body: arm.block === null ? [] : this.lowerBlock(armBody(arm.block))
|
|
4499
|
+
})
|
|
4500
|
+
);
|
|
4501
|
+
const named2 = groups.filter((group) => group.condition !== null);
|
|
4502
|
+
const fallback2 = groups.find((group) => group.condition === null) ?? {
|
|
4503
|
+
condition: null,
|
|
4504
|
+
hasTrailingBreak: true,
|
|
4505
|
+
body: [{ kind: "exit", exit: "throw", exitKind: "throw" }]
|
|
4506
|
+
};
|
|
4507
|
+
return {
|
|
4508
|
+
kind: "switch",
|
|
4509
|
+
groups: [...named2, fallback2],
|
|
4510
|
+
exitKind: exitKindOf(node)
|
|
4511
|
+
};
|
|
4512
|
+
}
|
|
4244
4513
|
lower(node) {
|
|
4245
4514
|
const exit = exitOf(node);
|
|
4246
4515
|
if (exit !== null) {
|
|
@@ -4270,10 +4539,12 @@ var Lowerer = class {
|
|
|
4270
4539
|
[header]
|
|
4271
4540
|
);
|
|
4272
4541
|
}
|
|
4273
|
-
const attachedBlock = node
|
|
4274
|
-
|
|
4275
|
-
)
|
|
4276
|
-
|
|
4542
|
+
const attachedBlock = attachedBlockOf(node);
|
|
4543
|
+
const formatSwitch = attachedBlock === null ? null : this.lowerFormatSwitch(node, attachedBlock);
|
|
4544
|
+
if (formatSwitch !== null) {
|
|
4545
|
+
return this.attach(formatSwitch, [node]);
|
|
4546
|
+
}
|
|
4547
|
+
if (node.type === "call" && attachedBlock !== null) {
|
|
4277
4548
|
return this.attach(
|
|
4278
4549
|
{
|
|
4279
4550
|
kind: "loop",
|
|
@@ -4300,10 +4571,11 @@ var Lowerer = class {
|
|
|
4300
4571
|
return this.attach({ kind: "opaque", exitKind: exitKindOf(node) }, [node]);
|
|
4301
4572
|
}
|
|
4302
4573
|
};
|
|
4303
|
-
function lowerRubyBody(body, terminals, responseCalls = []) {
|
|
4574
|
+
function lowerRubyBody(body, terminals, responseCalls = [], formatSwitch) {
|
|
4304
4575
|
const lowerer = new Lowerer(
|
|
4305
4576
|
new Map(terminals.map((terminal) => [terminal.id, terminal])),
|
|
4306
|
-
new NodeSet(responseCalls)
|
|
4577
|
+
new NodeSet(responseCalls),
|
|
4578
|
+
formatSwitch
|
|
4307
4579
|
);
|
|
4308
4580
|
return {
|
|
4309
4581
|
statements: lowerer.lowerBlock(body),
|
|
@@ -4464,6 +4736,14 @@ function enclosingStatement(call, body) {
|
|
|
4464
4736
|
return current;
|
|
4465
4737
|
}
|
|
4466
4738
|
function invocationEffects(definitionNode, inherited = NO_INHERITED_METHODS, keepsArglessCall = NO_ARGLESS_CALLS, facts) {
|
|
4739
|
+
return invocationSites(
|
|
4740
|
+
definitionNode,
|
|
4741
|
+
inherited,
|
|
4742
|
+
keepsArglessCall,
|
|
4743
|
+
facts
|
|
4744
|
+
).map((site) => site.effect);
|
|
4745
|
+
}
|
|
4746
|
+
function invocationSites(definitionNode, inherited = NO_INHERITED_METHODS, keepsArglessCall = NO_ARGLESS_CALLS, facts) {
|
|
4467
4747
|
const read = methodBody(definitionNode);
|
|
4468
4748
|
if (read === null) {
|
|
4469
4749
|
return [];
|
|
@@ -4476,7 +4756,7 @@ function moduleScopeInvocationEffects(root, inherited = NO_INHERITED_METHODS, ke
|
|
|
4476
4756
|
inherited,
|
|
4477
4757
|
keepsArglessCall,
|
|
4478
4758
|
facts
|
|
4479
|
-
);
|
|
4759
|
+
).map((site) => site.effect);
|
|
4480
4760
|
}
|
|
4481
4761
|
function effectsOfBody(read, inherited, keepsArglessCall, facts) {
|
|
4482
4762
|
const body = read.body;
|
|
@@ -4510,19 +4790,18 @@ function effectsOfBody(read, inherited, keepsArglessCall, facts) {
|
|
|
4510
4790
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement)
|
|
4511
4791
|
);
|
|
4512
4792
|
return {
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4793
|
+
call,
|
|
4794
|
+
effect: {
|
|
4795
|
+
type: "invocation",
|
|
4796
|
+
callee: calleeText(call),
|
|
4797
|
+
args: argsOf(call, facts),
|
|
4798
|
+
async: false,
|
|
4799
|
+
...conditions.length > 0 ? { preconditions: conditions } : {}
|
|
4800
|
+
}
|
|
4518
4801
|
};
|
|
4519
4802
|
});
|
|
4520
4803
|
}
|
|
4521
4804
|
|
|
4522
|
-
// src/responseStatus.ts
|
|
4523
|
-
var import_extractor4 = require("@suss/extractor");
|
|
4524
|
-
var import_values12 = require("@suss/values");
|
|
4525
|
-
|
|
4526
4805
|
// src/paths/predicates.ts
|
|
4527
4806
|
var OPERATORS = {
|
|
4528
4807
|
"==": "eq",
|
|
@@ -4541,11 +4820,11 @@ var opaqueOf = (node) => ({
|
|
|
4541
4820
|
var JOINING = /* @__PURE__ */ new Set(["&&", "||", "and", "or"]);
|
|
4542
4821
|
function predicateOf(node, inputs) {
|
|
4543
4822
|
if (node.type === "parenthesized_statements") {
|
|
4544
|
-
const inner = node.
|
|
4823
|
+
const inner = node.namedChild(0);
|
|
4545
4824
|
return inner == null ? opaqueOf(node) : predicateOf(inner, inputs);
|
|
4546
4825
|
}
|
|
4547
4826
|
if (node.type === "unary" && field(node, "operator")?.text === "!") {
|
|
4548
|
-
const operand2 = field(node, "operand") ?? node.
|
|
4827
|
+
const operand2 = field(node, "operand") ?? node.namedChild(0);
|
|
4549
4828
|
return operand2 == null ? opaqueOf(node) : { type: "negation", operand: predicateOf(operand2, inputs) };
|
|
4550
4829
|
}
|
|
4551
4830
|
if (node.type === "binary") {
|
|
@@ -4571,11 +4850,11 @@ function predicateOf(node, inputs) {
|
|
|
4571
4850
|
}
|
|
4572
4851
|
function operandsOf(node) {
|
|
4573
4852
|
if (node.type === "parenthesized_statements") {
|
|
4574
|
-
const inner = node.
|
|
4853
|
+
const inner = node.namedChild(0);
|
|
4575
4854
|
return inner == null ? [] : operandsOf(inner);
|
|
4576
4855
|
}
|
|
4577
4856
|
if (node.type === "unary" && field(node, "operator")?.text === "!") {
|
|
4578
|
-
const operand2 = field(node, "operand") ?? node.
|
|
4857
|
+
const operand2 = field(node, "operand") ?? node.namedChild(0);
|
|
4579
4858
|
return operand2 == null ? [] : operandsOf(operand2);
|
|
4580
4859
|
}
|
|
4581
4860
|
if (node.type === "binary") {
|
|
@@ -4671,8 +4950,317 @@ function calledMethod(node) {
|
|
|
4671
4950
|
return field(node, "method")?.text ?? null;
|
|
4672
4951
|
}
|
|
4673
4952
|
|
|
4674
|
-
// src/
|
|
4953
|
+
// src/responseHandOff.ts
|
|
4675
4954
|
var import_extractor3 = require("@suss/extractor");
|
|
4955
|
+
|
|
4956
|
+
// src/exceptionClasses.ts
|
|
4957
|
+
var ROOT_EXCEPTION = "Exception";
|
|
4958
|
+
var RUBY_EXCEPTION_PARENTS = {
|
|
4959
|
+
NoMemoryError: ROOT_EXCEPTION,
|
|
4960
|
+
ScriptError: ROOT_EXCEPTION,
|
|
4961
|
+
LoadError: "ScriptError",
|
|
4962
|
+
NotImplementedError: "ScriptError",
|
|
4963
|
+
SyntaxError: "ScriptError",
|
|
4964
|
+
SecurityError: ROOT_EXCEPTION,
|
|
4965
|
+
SignalException: ROOT_EXCEPTION,
|
|
4966
|
+
Interrupt: "SignalException",
|
|
4967
|
+
StandardError: ROOT_EXCEPTION,
|
|
4968
|
+
SystemExit: ROOT_EXCEPTION,
|
|
4969
|
+
SystemStackError: ROOT_EXCEPTION,
|
|
4970
|
+
ArgumentError: "StandardError",
|
|
4971
|
+
UncaughtThrowError: "ArgumentError",
|
|
4972
|
+
EncodingError: "StandardError",
|
|
4973
|
+
FiberError: "StandardError",
|
|
4974
|
+
IOError: "StandardError",
|
|
4975
|
+
EOFError: "IOError",
|
|
4976
|
+
IndexError: "StandardError",
|
|
4977
|
+
KeyError: "IndexError",
|
|
4978
|
+
StopIteration: "IndexError",
|
|
4979
|
+
ClosedQueueError: "StopIteration",
|
|
4980
|
+
LocalJumpError: "StandardError",
|
|
4981
|
+
NameError: "StandardError",
|
|
4982
|
+
NoMethodError: "NameError",
|
|
4983
|
+
RangeError: "StandardError",
|
|
4984
|
+
FloatDomainError: "RangeError",
|
|
4985
|
+
RegexpError: "StandardError",
|
|
4986
|
+
RuntimeError: "StandardError",
|
|
4987
|
+
FrozenError: "RuntimeError",
|
|
4988
|
+
SystemCallError: "StandardError",
|
|
4989
|
+
ThreadError: "StandardError",
|
|
4990
|
+
TypeError: "StandardError",
|
|
4991
|
+
ZeroDivisionError: "StandardError"
|
|
4992
|
+
};
|
|
4993
|
+
var MESSAGE_ONLY_EXCEPTION = "RuntimeError";
|
|
4994
|
+
var ExceptionReader = class {
|
|
4995
|
+
constructor(lookup, library) {
|
|
4996
|
+
this.library = library;
|
|
4997
|
+
this.walking = {
|
|
4998
|
+
...lookup,
|
|
4999
|
+
ancestryRootClassNames: [
|
|
5000
|
+
...Object.keys(library),
|
|
5001
|
+
...Object.keys(RUBY_EXCEPTION_PARENTS),
|
|
5002
|
+
ROOT_EXCEPTION
|
|
5003
|
+
]
|
|
5004
|
+
};
|
|
5005
|
+
}
|
|
5006
|
+
library;
|
|
5007
|
+
walking;
|
|
5008
|
+
known = /* @__PURE__ */ new Map();
|
|
5009
|
+
read(ref) {
|
|
5010
|
+
const key = [ref.text, ...ref.candidates].join("\0");
|
|
5011
|
+
let found = this.known.get(key);
|
|
5012
|
+
if (found === void 0) {
|
|
5013
|
+
found = readException(ref, this.walking, this.library);
|
|
5014
|
+
this.known.set(key, found);
|
|
5015
|
+
}
|
|
5016
|
+
return found;
|
|
5017
|
+
}
|
|
5018
|
+
};
|
|
5019
|
+
function listedException(name, library) {
|
|
5020
|
+
const fromLibrary = library[name];
|
|
5021
|
+
if (fromLibrary !== void 0) {
|
|
5022
|
+
return {
|
|
5023
|
+
name,
|
|
5024
|
+
ancestors: fromLibrary.ancestors,
|
|
5025
|
+
incomplete: false,
|
|
5026
|
+
inheritableByUnread: false
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
5029
|
+
const fromRuby = rubyAncestors(name);
|
|
5030
|
+
return fromRuby === null ? null : {
|
|
5031
|
+
name,
|
|
5032
|
+
ancestors: fromRuby,
|
|
5033
|
+
incomplete: false,
|
|
5034
|
+
inheritableByUnread: true
|
|
5035
|
+
};
|
|
5036
|
+
}
|
|
5037
|
+
function unreadException(name) {
|
|
5038
|
+
return {
|
|
5039
|
+
name,
|
|
5040
|
+
ancestors: [ROOT_EXCEPTION],
|
|
5041
|
+
incomplete: true,
|
|
5042
|
+
inheritableByUnread: true
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5045
|
+
function classesOf(exception) {
|
|
5046
|
+
return [exception.name, ...exception.ancestors];
|
|
5047
|
+
}
|
|
5048
|
+
async function readException(ref, lookup, library) {
|
|
5049
|
+
for (const candidate of ref.candidates) {
|
|
5050
|
+
const known = listedException(candidate, library);
|
|
5051
|
+
if (known !== null) {
|
|
5052
|
+
return known;
|
|
5053
|
+
}
|
|
5054
|
+
const defined = await reachConstant([candidate], lookup);
|
|
5055
|
+
if (defined !== null) {
|
|
5056
|
+
return projectException(defined, lookup, library);
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
return unreadException(ref.candidates.at(-1) ?? ref.text);
|
|
5060
|
+
}
|
|
5061
|
+
async function projectException(defined, lookup, library) {
|
|
5062
|
+
const chain = await ancestryOf(defined.name, defined.blocks, lookup);
|
|
5063
|
+
const ancestors = [];
|
|
5064
|
+
let incomplete = false;
|
|
5065
|
+
for (const entry of chain) {
|
|
5066
|
+
if (entry.type === "bodies" && entry.name === defined.name) {
|
|
5067
|
+
continue;
|
|
5068
|
+
}
|
|
5069
|
+
ancestors.push(entry.name);
|
|
5070
|
+
if (entry.type === "root") {
|
|
5071
|
+
ancestors.push(
|
|
5072
|
+
...listedException(entry.name, library)?.ancestors ?? []
|
|
5073
|
+
);
|
|
5074
|
+
}
|
|
5075
|
+
if (entry.type === "unfollowed") {
|
|
5076
|
+
incomplete = true;
|
|
5077
|
+
}
|
|
5078
|
+
}
|
|
5079
|
+
if (incomplete && !ancestors.includes(ROOT_EXCEPTION)) {
|
|
5080
|
+
ancestors.push(ROOT_EXCEPTION);
|
|
5081
|
+
}
|
|
5082
|
+
return {
|
|
5083
|
+
name: defined.name,
|
|
5084
|
+
ancestors,
|
|
5085
|
+
incomplete,
|
|
5086
|
+
inheritableByUnread: false
|
|
5087
|
+
};
|
|
5088
|
+
}
|
|
5089
|
+
function rubyAncestors(name) {
|
|
5090
|
+
if (name === ROOT_EXCEPTION) {
|
|
5091
|
+
return [];
|
|
5092
|
+
}
|
|
5093
|
+
if (RUBY_EXCEPTION_PARENTS[name] === void 0) {
|
|
5094
|
+
return null;
|
|
5095
|
+
}
|
|
5096
|
+
const ancestors = [];
|
|
5097
|
+
for (let parent = RUBY_EXCEPTION_PARENTS[name]; parent !== void 0; parent = RUBY_EXCEPTION_PARENTS[parent]) {
|
|
5098
|
+
ancestors.push(parent);
|
|
5099
|
+
}
|
|
5100
|
+
return ancestors;
|
|
5101
|
+
}
|
|
5102
|
+
|
|
5103
|
+
// src/raises.ts
|
|
5104
|
+
var RESCUING_BODIES = /* @__PURE__ */ new Set(["begin", "body_statement"]);
|
|
5105
|
+
var AFTER_CATCH = /* @__PURE__ */ new Set(["rescue", "else", "ensure"]);
|
|
5106
|
+
function escapingRaises(method) {
|
|
5107
|
+
const body = field(method, "body");
|
|
5108
|
+
if (body === null) {
|
|
5109
|
+
return [];
|
|
5110
|
+
}
|
|
5111
|
+
const found = [];
|
|
5112
|
+
const visit = (node) => {
|
|
5113
|
+
for (const child of children(node)) {
|
|
5114
|
+
if (child === null || OWN_BODY_TYPES.has(child.type)) {
|
|
5115
|
+
continue;
|
|
5116
|
+
}
|
|
5117
|
+
if (isRaise(child) && !caughtLocally(child, method)) {
|
|
5118
|
+
found.push(child);
|
|
5119
|
+
continue;
|
|
5120
|
+
}
|
|
5121
|
+
visit(child);
|
|
5122
|
+
}
|
|
5123
|
+
};
|
|
5124
|
+
visit(body);
|
|
5125
|
+
return found;
|
|
5126
|
+
}
|
|
5127
|
+
function caughtLocally(raise, method) {
|
|
5128
|
+
let child = raise;
|
|
5129
|
+
for (let parent = raise.parent; parent !== null && parent.id !== method.id; parent = parent.parent) {
|
|
5130
|
+
if (rescues(parent, child)) {
|
|
5131
|
+
return true;
|
|
5132
|
+
}
|
|
5133
|
+
child = parent;
|
|
5134
|
+
}
|
|
5135
|
+
return false;
|
|
5136
|
+
}
|
|
5137
|
+
function rescues(parent, child) {
|
|
5138
|
+
if (parent.type === "rescue_modifier") {
|
|
5139
|
+
return field(parent, "body")?.id === child.id;
|
|
5140
|
+
}
|
|
5141
|
+
return RESCUING_BODIES.has(parent.type) && !AFTER_CATCH.has(child.type) && children(parent).some((one) => one?.type === "rescue");
|
|
5142
|
+
}
|
|
5143
|
+
function raisedClassRef(call, nesting) {
|
|
5144
|
+
const first = readCallArgs(field(call, "arguments")).positional[0];
|
|
5145
|
+
if (first === void 0) {
|
|
5146
|
+
return null;
|
|
5147
|
+
}
|
|
5148
|
+
if (first.type === "string") {
|
|
5149
|
+
return {
|
|
5150
|
+
text: MESSAGE_ONLY_EXCEPTION,
|
|
5151
|
+
candidates: [MESSAGE_ONLY_EXCEPTION]
|
|
5152
|
+
};
|
|
5153
|
+
}
|
|
5154
|
+
const constant2 = constructedClass(first) ?? first;
|
|
5155
|
+
const candidates = constantRefCandidates(constant2, nesting);
|
|
5156
|
+
return candidates.length === 0 ? null : { text: constant2.text, candidates };
|
|
5157
|
+
}
|
|
5158
|
+
function constructedClass(node) {
|
|
5159
|
+
if (node.type !== "call" || field(node, "method")?.text !== "new") {
|
|
5160
|
+
return null;
|
|
5161
|
+
}
|
|
5162
|
+
return field(node, "receiver");
|
|
5163
|
+
}
|
|
5164
|
+
|
|
5165
|
+
// src/responseHandOff.ts
|
|
5166
|
+
function raiseEndings(method) {
|
|
5167
|
+
return escapingRaises(method).map((call) => ({
|
|
5168
|
+
call,
|
|
5169
|
+
terminal: raiseTerminal(call)
|
|
5170
|
+
}));
|
|
5171
|
+
}
|
|
5172
|
+
function raiseTerminal(call) {
|
|
5173
|
+
const [first, second] = readCallArgs(field(call, "arguments")).positional;
|
|
5174
|
+
const message = first === void 0 ? null : stringLiteralValue(first);
|
|
5175
|
+
return {
|
|
5176
|
+
kind: "throw",
|
|
5177
|
+
statusCode: null,
|
|
5178
|
+
body: null,
|
|
5179
|
+
exceptionType: raisedClassRef(call, [])?.text ?? null,
|
|
5180
|
+
message: message ?? (second === void 0 ? null : stringLiteralValue(second)),
|
|
5181
|
+
component: null,
|
|
5182
|
+
renderTree: null,
|
|
5183
|
+
delegateTarget: null,
|
|
5184
|
+
emitEvent: null,
|
|
5185
|
+
location: rangeOf(call)
|
|
5186
|
+
};
|
|
5187
|
+
}
|
|
5188
|
+
function throughResponseHelpers(branches, sites, options) {
|
|
5189
|
+
const handOffs = [];
|
|
5190
|
+
for (const { call, effect } of sites) {
|
|
5191
|
+
const helper = helperBranchesAt(call, options);
|
|
5192
|
+
if (helper !== null) {
|
|
5193
|
+
handOffs.push({
|
|
5194
|
+
helper,
|
|
5195
|
+
preconditions: effect.preconditions,
|
|
5196
|
+
line: rangeOf(call).start,
|
|
5197
|
+
at: rangeOf(call)
|
|
5198
|
+
});
|
|
5199
|
+
}
|
|
5200
|
+
}
|
|
5201
|
+
return handOffs.length === 0 ? [...branches] : branches.flatMap((branch) => (0, import_extractor3.splitAtHandOffs)(branch, handOffs));
|
|
5202
|
+
}
|
|
5203
|
+
function helperBranchesAt(call, options) {
|
|
5204
|
+
if (call.type !== "call") {
|
|
5205
|
+
return null;
|
|
5206
|
+
}
|
|
5207
|
+
const args = readCallArgs(field(call, "arguments"));
|
|
5208
|
+
const handedAt = args.positional.flatMap(
|
|
5209
|
+
(argument, position) => argument.type === "identifier" && refersToResponse(argument, options) ? [{ position, variable: argument.text }] : []
|
|
5210
|
+
);
|
|
5211
|
+
const handedAs = Object.entries(args.keyword).flatMap(
|
|
5212
|
+
([name, argument]) => argument.type === "identifier" && refersToResponse(argument, options) ? [{ name, variable: argument.text }] : []
|
|
5213
|
+
);
|
|
5214
|
+
if (handedAt.length === 0 && handedAs.length === 0) {
|
|
5215
|
+
return null;
|
|
5216
|
+
}
|
|
5217
|
+
const helper = calledDefinition(call, options.facts);
|
|
5218
|
+
if (helper === null) {
|
|
5219
|
+
return null;
|
|
5220
|
+
}
|
|
5221
|
+
const passed = /* @__PURE__ */ new Map();
|
|
5222
|
+
const names = parametersOf(helper).map(
|
|
5223
|
+
(parameter) => paramNameOf(parameter)?.text ?? null
|
|
5224
|
+
);
|
|
5225
|
+
for (const { position, variable } of handedAt) {
|
|
5226
|
+
const name = names[position];
|
|
5227
|
+
if (name !== void 0 && name !== null) {
|
|
5228
|
+
passed.set(name, variable);
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
for (const { name, variable } of handedAs) {
|
|
5232
|
+
if (names.includes(name)) {
|
|
5233
|
+
passed.set(name, variable);
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
return passed.size === 0 ? null : (0, import_extractor3.helperPathsOnVariables)(options.readHelper(helper), passed);
|
|
5237
|
+
}
|
|
5238
|
+
function refersToResponse(name, options) {
|
|
5239
|
+
const written = writtenNodeOf(name, options.facts);
|
|
5240
|
+
if (written === null) {
|
|
5241
|
+
return false;
|
|
5242
|
+
}
|
|
5243
|
+
if (sameNode(written, options.request)) {
|
|
5244
|
+
return true;
|
|
5245
|
+
}
|
|
5246
|
+
const member = written.type === "call" ? field(written, "method") : null;
|
|
5247
|
+
const receiver = written.type === "call" ? field(written, "receiver") : null;
|
|
5248
|
+
if (member === null || receiver?.type !== "identifier" || !options.bodyMethods.includes(member.text)) {
|
|
5249
|
+
return false;
|
|
5250
|
+
}
|
|
5251
|
+
const parsedFrom = writtenNodeOf(receiver, options.facts);
|
|
5252
|
+
return parsedFrom !== null && sameNode(parsedFrom, options.request);
|
|
5253
|
+
}
|
|
5254
|
+
function sameNode(a, b) {
|
|
5255
|
+
return a.startIndex === b.startIndex && a.endIndex === b.endIndex && a.tree === b.tree;
|
|
5256
|
+
}
|
|
5257
|
+
|
|
5258
|
+
// src/responseStatus.ts
|
|
5259
|
+
var import_extractor6 = require("@suss/extractor");
|
|
5260
|
+
var import_values13 = require("@suss/values");
|
|
5261
|
+
|
|
5262
|
+
// src/provenance.ts
|
|
5263
|
+
var import_extractor4 = require("@suss/extractor");
|
|
4676
5264
|
var import_values11 = require("@suss/values");
|
|
4677
5265
|
|
|
4678
5266
|
// src/storage.ts
|
|
@@ -4738,7 +5326,7 @@ function pickedSource(call, loader) {
|
|
|
4738
5326
|
return null;
|
|
4739
5327
|
}
|
|
4740
5328
|
const args = field(pick, "arguments");
|
|
4741
|
-
const given = args === null ? void 0 : args.
|
|
5329
|
+
const given = args === null ? void 0 : args.namedChild(source.at);
|
|
4742
5330
|
return given?.type === "constant" || given?.type === "scope_resolution" ? given : null;
|
|
4743
5331
|
}
|
|
4744
5332
|
|
|
@@ -5383,10 +5971,7 @@ function recognizeMethodStorage(method, file, options) {
|
|
|
5383
5971
|
return { effects, slots };
|
|
5384
5972
|
}
|
|
5385
5973
|
function callsUnder(node, found = []) {
|
|
5386
|
-
for (const child of node
|
|
5387
|
-
if (child === null) {
|
|
5388
|
-
continue;
|
|
5389
|
-
}
|
|
5974
|
+
for (const child of children(node)) {
|
|
5390
5975
|
if (child.type === "call") {
|
|
5391
5976
|
found.push(child);
|
|
5392
5977
|
}
|
|
@@ -5528,7 +6113,7 @@ function valueSources(values, context, question = "wantedSource") {
|
|
|
5528
6113
|
const spelling = spellingFor(context);
|
|
5529
6114
|
const found = new NodeMap();
|
|
5530
6115
|
for (const [value, key] of keys) {
|
|
5531
|
-
found.set(value, (0,
|
|
6116
|
+
found.set(value, (0, import_extractor4.sourceRefsOf)(leaves.get(key) ?? [], spelling));
|
|
5532
6117
|
}
|
|
5533
6118
|
return found;
|
|
5534
6119
|
}
|
|
@@ -5582,16 +6167,121 @@ function bareMethodOf(node) {
|
|
|
5582
6167
|
if (node.type !== "call" || field(node, "arguments") !== null) {
|
|
5583
6168
|
return null;
|
|
5584
6169
|
}
|
|
5585
|
-
return field(node, "method")?.text ?? null;
|
|
6170
|
+
return field(node, "method")?.text ?? null;
|
|
6171
|
+
}
|
|
6172
|
+
function literalAt(key, facts) {
|
|
6173
|
+
const node = nodeOfResolutionKey(key, facts);
|
|
6174
|
+
if (node === null) {
|
|
6175
|
+
return void 0;
|
|
6176
|
+
}
|
|
6177
|
+
const value = evaluatedValue(node, facts);
|
|
6178
|
+
const constant2 = (0, import_values11.constantOf)(value);
|
|
6179
|
+
return constant2 !== void 0 ? constant2 : (0, import_values11.literalOf)(value) ?? void 0;
|
|
6180
|
+
}
|
|
6181
|
+
|
|
6182
|
+
// src/raisedStatuses.ts
|
|
6183
|
+
function rescuedBy(handlers, exception) {
|
|
6184
|
+
if (handlers === "eachRoute") {
|
|
6185
|
+
return true;
|
|
6186
|
+
}
|
|
6187
|
+
const classes = new Set(classesOf(exception));
|
|
6188
|
+
return handlers.some(
|
|
6189
|
+
(caught) => caught.someUnread || caught.classes.some(
|
|
6190
|
+
(one) => classes.has(one.name) || exception.incomplete && one.inheritableByUnread
|
|
6191
|
+
)
|
|
6192
|
+
);
|
|
6193
|
+
}
|
|
6194
|
+
function raisedTerminal(pattern, exception, handlers, location) {
|
|
6195
|
+
const libraryStatus = exception === null ? void 0 : pattern.libraryExceptions?.[exception.name]?.status;
|
|
6196
|
+
const status = exception === null || rescuedBy(handlers, exception) ? void 0 : libraryStatus;
|
|
6197
|
+
return {
|
|
6198
|
+
kind: status === void 0 ? "throw" : "response",
|
|
6199
|
+
statusCode: status === void 0 ? null : { type: "literal", value: status },
|
|
6200
|
+
body: null,
|
|
6201
|
+
exceptionType: status === void 0 ? exception?.name ?? null : null,
|
|
6202
|
+
...status === void 0 && exception !== null ? {
|
|
6203
|
+
exceptionAncestry: {
|
|
6204
|
+
ancestors: exception.ancestors,
|
|
6205
|
+
incomplete: exception.incomplete
|
|
6206
|
+
}
|
|
6207
|
+
} : {},
|
|
6208
|
+
...status === void 0 && libraryStatus !== void 0 ? { statusWhenUncaught: libraryStatus } : {},
|
|
6209
|
+
message: null,
|
|
6210
|
+
component: null,
|
|
6211
|
+
renderTree: null,
|
|
6212
|
+
delegateTarget: null,
|
|
6213
|
+
emitEvent: null,
|
|
6214
|
+
location
|
|
6215
|
+
};
|
|
6216
|
+
}
|
|
6217
|
+
function raisedStatusBranches(pattern, storage, effects, handlers, location) {
|
|
6218
|
+
const operations = new Set(
|
|
6219
|
+
(effects ?? []).flatMap(
|
|
6220
|
+
(effect) => effect.type === "interaction" && effect.interaction.class === "storage-access" && effect.interaction.operation !== void 0 ? [effect.interaction.operation] : []
|
|
6221
|
+
)
|
|
6222
|
+
);
|
|
6223
|
+
const raised = new Set(
|
|
6224
|
+
storage.flatMap(
|
|
6225
|
+
(one) => (one.raises ?? []).flatMap(
|
|
6226
|
+
(raise) => raise.methods.some((method) => operations.has(method)) ? [raise.exception] : []
|
|
6227
|
+
)
|
|
6228
|
+
)
|
|
6229
|
+
);
|
|
6230
|
+
return [...raised].flatMap((name) => {
|
|
6231
|
+
const exception = listedException(name, pattern.libraryExceptions ?? {}) ?? unreadException(name);
|
|
6232
|
+
const terminal = raisedTerminal(pattern, exception, handlers, location);
|
|
6233
|
+
if (terminal.kind === "throw" && !rescuedBy(handlers, exception)) {
|
|
6234
|
+
return [];
|
|
6235
|
+
}
|
|
6236
|
+
return [
|
|
6237
|
+
{
|
|
6238
|
+
conditions: [
|
|
6239
|
+
{
|
|
6240
|
+
sourceText: `${name} raised`,
|
|
6241
|
+
structured: null,
|
|
6242
|
+
polarity: "positive",
|
|
6243
|
+
source: "earlyThrow"
|
|
6244
|
+
}
|
|
6245
|
+
],
|
|
6246
|
+
terminal,
|
|
6247
|
+
effects: [],
|
|
6248
|
+
location,
|
|
6249
|
+
isDefault: false
|
|
6250
|
+
}
|
|
6251
|
+
];
|
|
6252
|
+
});
|
|
6253
|
+
}
|
|
6254
|
+
|
|
6255
|
+
// src/responseBody.ts
|
|
6256
|
+
var import_extractor5 = require("@suss/extractor");
|
|
6257
|
+
var import_values12 = require("@suss/values");
|
|
6258
|
+
var BODY_KINDS = /* @__PURE__ */ new Set([
|
|
6259
|
+
"record",
|
|
6260
|
+
"sequence",
|
|
6261
|
+
"unbounded"
|
|
6262
|
+
]);
|
|
6263
|
+
function serializedValue(node, serializers) {
|
|
6264
|
+
const receiver = field(node, "receiver");
|
|
6265
|
+
const method = field(node, "method")?.text;
|
|
6266
|
+
if (node.type !== "call" || receiver === null || method === void 0 || !serializers.has(method) || field(node, "arguments") !== null) {
|
|
6267
|
+
return node;
|
|
6268
|
+
}
|
|
6269
|
+
return serializedValue(receiver, serializers);
|
|
5586
6270
|
}
|
|
5587
|
-
function
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
return void 0;
|
|
6271
|
+
function bodyReadingOfCall(call, declaration, facts) {
|
|
6272
|
+
if (declaration.bodyKeyword === void 0 || call.type !== "call") {
|
|
6273
|
+
return import_extractor5.absentReading;
|
|
5591
6274
|
}
|
|
5592
|
-
const
|
|
5593
|
-
|
|
5594
|
-
|
|
6275
|
+
const argument = readCallArgs(field(call, "arguments")).keyword[declaration.bodyKeyword];
|
|
6276
|
+
if (argument === void 0) {
|
|
6277
|
+
return import_extractor5.absentReading;
|
|
6278
|
+
}
|
|
6279
|
+
const body = serializedValue(
|
|
6280
|
+
argument,
|
|
6281
|
+
new Set(declaration.bodySerializers ?? [])
|
|
6282
|
+
);
|
|
6283
|
+
const value = evaluatedValue(body, facts);
|
|
6284
|
+
return BODY_KINDS.has(value.kind) ? (0, import_extractor5.writtenReading)((0, import_values12.shapeOfValue)(value), rangeOf(argument)) : import_extractor5.absentReading;
|
|
5595
6285
|
}
|
|
5596
6286
|
|
|
5597
6287
|
// src/responseStatus.ts
|
|
@@ -5606,13 +6296,17 @@ function statusArgumentOf(call, declaration) {
|
|
|
5606
6296
|
}
|
|
5607
6297
|
return args.positional[declaration.statusArgument] ?? null;
|
|
5608
6298
|
}
|
|
5609
|
-
function statusNumberOf(node, names, facts) {
|
|
6299
|
+
function statusNumberOf(node, names, facts, bound = /* @__PURE__ */ new Map()) {
|
|
6300
|
+
const passed = node.type === "identifier" ? bound.get(node.text) : void 0;
|
|
6301
|
+
if (passed !== void 0) {
|
|
6302
|
+
return passed;
|
|
6303
|
+
}
|
|
5610
6304
|
const value = evaluatedValue(node, facts);
|
|
5611
|
-
const constant2 = (0,
|
|
6305
|
+
const constant2 = (0, import_values13.constantOf)(value);
|
|
5612
6306
|
if (typeof constant2 === "number") {
|
|
5613
6307
|
return constant2;
|
|
5614
6308
|
}
|
|
5615
|
-
const name = (0,
|
|
6309
|
+
const name = (0, import_values13.literalOf)(value);
|
|
5616
6310
|
return name === null ? null : names[name] ?? null;
|
|
5617
6311
|
}
|
|
5618
6312
|
function declarationsByName(declarations) {
|
|
@@ -5630,21 +6324,42 @@ function declarationOf(node, byName, locals) {
|
|
|
5630
6324
|
const name = field(node, "method")?.text;
|
|
5631
6325
|
return name === void 0 ? void 0 : byName.get(name);
|
|
5632
6326
|
}
|
|
5633
|
-
function
|
|
5634
|
-
|
|
6327
|
+
function responderOf(node, responders) {
|
|
6328
|
+
const declaration = declarationOf(node, responders.byName, responders.locals);
|
|
6329
|
+
if (declaration !== void 0) {
|
|
6330
|
+
return { kind: "declared", declaration };
|
|
6331
|
+
}
|
|
6332
|
+
const name = receiverlessName(node, responders.locals);
|
|
6333
|
+
const reading = name === null || responders.helper === void 0 ? null : responders.helper(name, node);
|
|
6334
|
+
return reading === null ? void 0 : { kind: "helper", reading };
|
|
6335
|
+
}
|
|
6336
|
+
function receiverlessName(node, locals) {
|
|
6337
|
+
if (node.type === "identifier") {
|
|
6338
|
+
return isBareMethodCall(node, locals) ? node.text : null;
|
|
6339
|
+
}
|
|
6340
|
+
if (node.type !== "call" || field(node, "receiver") !== null) {
|
|
6341
|
+
return null;
|
|
6342
|
+
}
|
|
6343
|
+
return field(node, "method")?.text ?? null;
|
|
6344
|
+
}
|
|
6345
|
+
function readingOfResponder(call, responder, names, options) {
|
|
6346
|
+
return responder.kind === "helper" ? responder.reading : readingOfCall(call, responder.declaration, names, options);
|
|
6347
|
+
}
|
|
6348
|
+
function collectResponseCalls(node, responders, found) {
|
|
6349
|
+
for (const child of children(node)) {
|
|
5635
6350
|
if (child === null || OWN_BODY_TYPES.has(child.type)) {
|
|
5636
6351
|
continue;
|
|
5637
6352
|
}
|
|
5638
|
-
if (
|
|
6353
|
+
if (responderOf(child, responders) !== void 0) {
|
|
5639
6354
|
found.push(child);
|
|
5640
6355
|
continue;
|
|
5641
6356
|
}
|
|
5642
|
-
collectResponseCalls(child,
|
|
6357
|
+
collectResponseCalls(child, responders, found);
|
|
5643
6358
|
}
|
|
5644
6359
|
return found;
|
|
5645
6360
|
}
|
|
5646
6361
|
function collectReturns(node, found) {
|
|
5647
|
-
for (const child of node
|
|
6362
|
+
for (const child of children(node)) {
|
|
5648
6363
|
if (child === null || OWN_BODY_TYPES.has(child.type)) {
|
|
5649
6364
|
continue;
|
|
5650
6365
|
}
|
|
@@ -5656,23 +6371,28 @@ function collectReturns(node, found) {
|
|
|
5656
6371
|
}
|
|
5657
6372
|
return found;
|
|
5658
6373
|
}
|
|
5659
|
-
function readingOfCall(call, declaration, names,
|
|
6374
|
+
function readingOfCall(call, declaration, names, options) {
|
|
5660
6375
|
const argument = statusArgumentOf(call, declaration);
|
|
5661
6376
|
if (argument === null) {
|
|
5662
|
-
return declaration.defaultStatusCode === void 0 ?
|
|
6377
|
+
return declaration.defaultStatusCode === void 0 ? import_extractor6.absentReading : (0, import_extractor6.writtenReading)(declaration.defaultStatusCode, rangeOf(call));
|
|
5663
6378
|
}
|
|
5664
|
-
const status = statusNumberOf(
|
|
6379
|
+
const status = statusNumberOf(
|
|
6380
|
+
argument,
|
|
6381
|
+
names,
|
|
6382
|
+
options.facts,
|
|
6383
|
+
options.boundStatuses
|
|
6384
|
+
);
|
|
5665
6385
|
if (status === null) {
|
|
5666
|
-
return (0,
|
|
6386
|
+
return (0, import_extractor6.unreadableReading)(
|
|
5667
6387
|
"This response writes a status that does not settle on a number here, so this outcome claims none",
|
|
5668
6388
|
rangeOf(argument)
|
|
5669
6389
|
);
|
|
5670
6390
|
}
|
|
5671
|
-
return (0,
|
|
6391
|
+
return (0, import_extractor6.writtenReading)(status, rangeOf(argument));
|
|
5672
6392
|
}
|
|
5673
6393
|
function effectsReaching(effects, conditions) {
|
|
5674
6394
|
return effects.filter(
|
|
5675
|
-
(effect) => (0,
|
|
6395
|
+
(effect) => (0, import_extractor6.guardsHoldOn)(
|
|
5676
6396
|
effect.type === "invocation" ? effect.preconditions : void 0,
|
|
5677
6397
|
conditions
|
|
5678
6398
|
)
|
|
@@ -5697,6 +6417,45 @@ function conditionInputs(method, paths, facts) {
|
|
|
5697
6417
|
);
|
|
5698
6418
|
return operands.length === 0 ? void 0 : guardInputs(operands, { facts, unit: method });
|
|
5699
6419
|
}
|
|
6420
|
+
function boundStatusArguments(helper, call, pattern, facts) {
|
|
6421
|
+
const parameters = children(field(helper, "parameters")).filter(
|
|
6422
|
+
(child) => child.type === "identifier"
|
|
6423
|
+
);
|
|
6424
|
+
const args = call.type === "call" ? readCallArgs(field(call, "arguments")).positional : [];
|
|
6425
|
+
const bound = /* @__PURE__ */ new Map();
|
|
6426
|
+
parameters.forEach((parameter, index) => {
|
|
6427
|
+
const arg = args[index];
|
|
6428
|
+
const status = arg === void 0 ? null : statusNumberOf(arg, pattern.statusCodeNames ?? {}, facts);
|
|
6429
|
+
if (status !== null) {
|
|
6430
|
+
bound.set(parameter.text, status);
|
|
6431
|
+
}
|
|
6432
|
+
});
|
|
6433
|
+
return bound;
|
|
6434
|
+
}
|
|
6435
|
+
function helperResponse(helper, pattern, facts, boundStatuses = /* @__PURE__ */ new Map()) {
|
|
6436
|
+
const branches = responseBranches(helper, pattern, [], void 0, {
|
|
6437
|
+
fallthrough: "handOn",
|
|
6438
|
+
facts,
|
|
6439
|
+
boundStatuses
|
|
6440
|
+
});
|
|
6441
|
+
if (branches === null || branches.some((branch) => branch.terminal.kind !== "response")) {
|
|
6442
|
+
return null;
|
|
6443
|
+
}
|
|
6444
|
+
const statuses = new Set(
|
|
6445
|
+
branches.map((branch) => {
|
|
6446
|
+
const reading = branch.statusCodeReading?.reading;
|
|
6447
|
+
if (reading?.kind === "absent") {
|
|
6448
|
+
return branch.statusCodeReading?.libraryDefault ?? null;
|
|
6449
|
+
}
|
|
6450
|
+
return reading?.kind === "written" ? reading.value : null;
|
|
6451
|
+
})
|
|
6452
|
+
);
|
|
6453
|
+
const [only] = [...statuses];
|
|
6454
|
+
return statuses.size === 1 && typeof only === "number" ? (0, import_extractor6.writtenReading)(only, rangeOf(helper)) : (0, import_extractor6.unreadableReading)(
|
|
6455
|
+
"This response is sent by a helper whose status does not settle on one number here, so this outcome claims none",
|
|
6456
|
+
rangeOf(helper)
|
|
6457
|
+
);
|
|
6458
|
+
}
|
|
5700
6459
|
function branchOf(outcome, pattern, effects, extraEffects, options) {
|
|
5701
6460
|
if (outcome.fellThrough === true && options.fallthrough === "handOn") {
|
|
5702
6461
|
return handsOnBranch(outcome, effects, extraEffects);
|
|
@@ -5719,6 +6478,7 @@ function branchOf(outcome, pattern, effects, extraEffects, options) {
|
|
|
5719
6478
|
reading: outcome.reading,
|
|
5720
6479
|
libraryDefault: pattern.defaultStatusCode
|
|
5721
6480
|
},
|
|
6481
|
+
...outcome.body === void 0 ? {} : { bodyShapeReading: { reading: outcome.body } },
|
|
5722
6482
|
effects: effectsReaching(effects, outcome.conditions),
|
|
5723
6483
|
...extraEffects === void 0 ? {} : { extraEffects },
|
|
5724
6484
|
location: outcome.location,
|
|
@@ -5746,20 +6506,26 @@ function handsOnBranch(outcome, effects, extraEffects) {
|
|
|
5746
6506
|
isDefault: outcome.conditions.length === 0
|
|
5747
6507
|
};
|
|
5748
6508
|
}
|
|
5749
|
-
function returnPathBranches(method, effects, exits = [], facts) {
|
|
6509
|
+
function returnPathBranches(method, effects, exits = [], facts, keepsArms, raises2 = []) {
|
|
5750
6510
|
const body = field(method, "body");
|
|
5751
6511
|
if (body === null) {
|
|
5752
6512
|
return null;
|
|
5753
6513
|
}
|
|
5754
6514
|
const returns = collectReturns(body, []);
|
|
5755
6515
|
const exitCalls = exits.map((exit) => exit.call);
|
|
5756
|
-
const
|
|
5757
|
-
|
|
6516
|
+
const terminals = [
|
|
6517
|
+
...returns,
|
|
6518
|
+
...exitCalls,
|
|
6519
|
+
...raises2.map((raise) => raise.call)
|
|
6520
|
+
];
|
|
6521
|
+
const lowered = lowerRubyBody(body, terminals, exitCalls);
|
|
6522
|
+
const enumerated = (0, import_extractor6.enumerateOrDegrade)(
|
|
5758
6523
|
{
|
|
5759
6524
|
statements: lowered.statements,
|
|
5760
|
-
terminalsByStmt: lowered.terminalsByStmt
|
|
6525
|
+
terminalsByStmt: lowered.terminalsByStmt,
|
|
6526
|
+
...keepsArms === void 0 ? {} : { keepsArms }
|
|
5761
6527
|
},
|
|
5762
|
-
|
|
6528
|
+
terminals
|
|
5763
6529
|
);
|
|
5764
6530
|
const inputs = conditionInputs(
|
|
5765
6531
|
method,
|
|
@@ -5787,8 +6553,8 @@ function returnPathBranches(method, effects, exits = [], facts) {
|
|
|
5787
6553
|
returnTerminal(rangeOf(statement))
|
|
5788
6554
|
);
|
|
5789
6555
|
}
|
|
5790
|
-
for (const
|
|
5791
|
-
push(enumerated.byTerminal.get(
|
|
6556
|
+
for (const ending of [...exits, ...raises2]) {
|
|
6557
|
+
push(enumerated.byTerminal.get(ending.call) ?? [], ending.terminal);
|
|
5792
6558
|
}
|
|
5793
6559
|
push(enumerated.fallthrough, returnTerminal(rangeOf(method)));
|
|
5794
6560
|
return branches.length === 0 ? null : branches;
|
|
@@ -5813,21 +6579,30 @@ function responseBranches(method, pattern, effects, extraEffects, options = {})
|
|
|
5813
6579
|
if (declarations.length === 0 || body === null) {
|
|
5814
6580
|
return null;
|
|
5815
6581
|
}
|
|
5816
|
-
const
|
|
5817
|
-
|
|
5818
|
-
|
|
6582
|
+
const responders = {
|
|
6583
|
+
byName: declarationsByName(declarations),
|
|
6584
|
+
locals: localNamesIn(method),
|
|
6585
|
+
helper: options.respondingHelper
|
|
6586
|
+
};
|
|
6587
|
+
const responses = collectResponseCalls(body, responders, []);
|
|
5819
6588
|
const returns = collectReturns(body, []);
|
|
5820
|
-
const
|
|
6589
|
+
const raises2 = options.raises === void 0 ? [] : escapingRaises(method);
|
|
6590
|
+
const lowered = lowerRubyBody(
|
|
6591
|
+
body,
|
|
6592
|
+
[...returns, ...raises2],
|
|
6593
|
+
responses,
|
|
6594
|
+
pattern.formatSwitch
|
|
6595
|
+
);
|
|
5821
6596
|
const bareReturns = returns.filter(
|
|
5822
|
-
(node) => lowered.terminalHome.has(node) && collectResponseCalls(node,
|
|
6597
|
+
(node) => lowered.terminalHome.has(node) && collectResponseCalls(node, responders, []).length === 0
|
|
5823
6598
|
);
|
|
5824
6599
|
const terminals = [...responses, ...bareReturns];
|
|
5825
|
-
const enumerated = (0,
|
|
6600
|
+
const enumerated = (0, import_extractor6.enumerateOrDegrade)(
|
|
5826
6601
|
{
|
|
5827
6602
|
statements: lowered.statements,
|
|
5828
6603
|
terminalsByStmt: lowered.terminalsByStmt
|
|
5829
6604
|
},
|
|
5830
|
-
terminals
|
|
6605
|
+
[...terminals, ...raises2]
|
|
5831
6606
|
);
|
|
5832
6607
|
const statusNames = pattern.statusCodeNames ?? {};
|
|
5833
6608
|
const inputs = conditionInputs(
|
|
@@ -5838,30 +6613,58 @@ function responseBranches(method, pattern, effects, extraEffects, options = {})
|
|
|
5838
6613
|
const conditionsOf = (path7) => path7.map((condition) => conditionOf(condition, inputs));
|
|
5839
6614
|
const outcomes = [];
|
|
5840
6615
|
for (const terminal of terminals) {
|
|
5841
|
-
const
|
|
5842
|
-
const reading =
|
|
6616
|
+
const responder = responderOf(terminal, responders);
|
|
6617
|
+
const reading = responder === void 0 ? import_extractor6.absentReading : readingOfResponder(terminal, responder, statusNames, options);
|
|
6618
|
+
const body2 = responder?.kind === "declared" ? bodyReadingOfCall(terminal, responder.declaration, options.facts) : void 0;
|
|
5843
6619
|
for (const path7 of enumerated.byTerminal.get(terminal) ?? []) {
|
|
5844
6620
|
outcomes.push({
|
|
5845
6621
|
conditions: conditionsOf(path7),
|
|
5846
6622
|
reading,
|
|
5847
|
-
|
|
6623
|
+
...body2 === void 0 ? {} : { body: body2 },
|
|
6624
|
+
location: rangeOf(terminal),
|
|
6625
|
+
// A bare `return` wrote no response, so a filter that takes it
|
|
6626
|
+
// hands the request on the same as one that reaches its end.
|
|
6627
|
+
...responder === void 0 ? { fellThrough: true } : {}
|
|
5848
6628
|
});
|
|
5849
6629
|
}
|
|
5850
6630
|
}
|
|
5851
6631
|
for (const path7 of enumerated.fallthrough) {
|
|
5852
6632
|
outcomes.push({
|
|
5853
6633
|
conditions: conditionsOf(path7),
|
|
5854
|
-
reading:
|
|
6634
|
+
reading: import_extractor6.absentReading,
|
|
5855
6635
|
location: rangeOf(method),
|
|
5856
6636
|
fellThrough: true
|
|
5857
6637
|
});
|
|
5858
6638
|
}
|
|
5859
|
-
|
|
6639
|
+
const read = options.raises;
|
|
6640
|
+
const raised = raises2.flatMap((call) => {
|
|
6641
|
+
const terminal = raisedTerminal(
|
|
6642
|
+
pattern,
|
|
6643
|
+
read?.classes.get(call) ?? null,
|
|
6644
|
+
read?.handlers ?? [],
|
|
6645
|
+
rangeOf(call)
|
|
6646
|
+
);
|
|
6647
|
+
return (enumerated.byTerminal.get(call) ?? []).map((path7) => {
|
|
6648
|
+
const conditions = conditionsOf(path7);
|
|
6649
|
+
return {
|
|
6650
|
+
conditions,
|
|
6651
|
+
terminal,
|
|
6652
|
+
effects: effectsReaching(effects, conditions),
|
|
6653
|
+
...extraEffects === void 0 ? {} : { extraEffects },
|
|
6654
|
+
location: terminal.location,
|
|
6655
|
+
isDefault: false
|
|
6656
|
+
};
|
|
6657
|
+
});
|
|
6658
|
+
});
|
|
6659
|
+
if (outcomes.length === 0 && raised.length === 0) {
|
|
5860
6660
|
return null;
|
|
5861
6661
|
}
|
|
5862
|
-
return
|
|
5863
|
-
(
|
|
5864
|
-
|
|
6662
|
+
return [
|
|
6663
|
+
...outcomes.map(
|
|
6664
|
+
(outcome) => branchOf(outcome, pattern, effects, extraEffects, options)
|
|
6665
|
+
),
|
|
6666
|
+
...raised
|
|
6667
|
+
];
|
|
5865
6668
|
}
|
|
5866
6669
|
|
|
5867
6670
|
// src/clientCalls.ts
|
|
@@ -5874,7 +6677,16 @@ function clientCallUnits(root, pack, pattern, options) {
|
|
|
5874
6677
|
}
|
|
5875
6678
|
for (const call of callsUnder2(method)) {
|
|
5876
6679
|
for (const request of requestCalls(call, pattern, options)) {
|
|
5877
|
-
units.push(
|
|
6680
|
+
units.push(
|
|
6681
|
+
clientUnit(
|
|
6682
|
+
method,
|
|
6683
|
+
name,
|
|
6684
|
+
{ ...request, call },
|
|
6685
|
+
pattern,
|
|
6686
|
+
pack,
|
|
6687
|
+
options
|
|
6688
|
+
)
|
|
6689
|
+
);
|
|
5878
6690
|
}
|
|
5879
6691
|
}
|
|
5880
6692
|
}
|
|
@@ -5932,10 +6744,7 @@ function requestArgument(call, called, pattern) {
|
|
|
5932
6744
|
return pattern.requestObject?.attribute === called ? args.positional[0] : void 0;
|
|
5933
6745
|
}
|
|
5934
6746
|
function methodDefinitions(node, found = []) {
|
|
5935
|
-
for (const child of node
|
|
5936
|
-
if (child === null) {
|
|
5937
|
-
continue;
|
|
5938
|
-
}
|
|
6747
|
+
for (const child of children(node)) {
|
|
5939
6748
|
if (child.type === "method" || child.type === "singleton_method") {
|
|
5940
6749
|
found.push(child);
|
|
5941
6750
|
}
|
|
@@ -5944,10 +6753,7 @@ function methodDefinitions(node, found = []) {
|
|
|
5944
6753
|
return found;
|
|
5945
6754
|
}
|
|
5946
6755
|
function callsUnder2(node, found = []) {
|
|
5947
|
-
for (const child of node
|
|
5948
|
-
if (child === null) {
|
|
5949
|
-
continue;
|
|
5950
|
-
}
|
|
6756
|
+
for (const child of children(node)) {
|
|
5951
6757
|
if (child.type === "call") {
|
|
5952
6758
|
found.push(child);
|
|
5953
6759
|
}
|
|
@@ -5964,20 +6770,23 @@ function requestCalls(call, pattern, options) {
|
|
|
5964
6770
|
const read = (site) => requestCall(
|
|
5965
6771
|
call,
|
|
5966
6772
|
called,
|
|
5967
|
-
|
|
6773
|
+
receiverBase(receiver, pattern, options, site),
|
|
5968
6774
|
pattern,
|
|
5969
6775
|
options,
|
|
5970
6776
|
site
|
|
5971
6777
|
);
|
|
5972
6778
|
const plain = read();
|
|
5973
|
-
if (plain !== null && !(0,
|
|
6779
|
+
if (plain !== null && !(0, import_behavioral_ir2.hasNameHole)(plain.path)) {
|
|
5974
6780
|
return [plain];
|
|
5975
6781
|
}
|
|
5976
6782
|
const byBoundary = /* @__PURE__ */ new Map();
|
|
5977
6783
|
for (const site of constructionSitesOf(call, options.facts)) {
|
|
5978
6784
|
const stated = read(site);
|
|
5979
6785
|
if (stated !== null) {
|
|
5980
|
-
byBoundary.set(
|
|
6786
|
+
byBoundary.set(
|
|
6787
|
+
`${stated.method} ${stated.host ?? ""} ${stated.path}`,
|
|
6788
|
+
stated
|
|
6789
|
+
);
|
|
5981
6790
|
}
|
|
5982
6791
|
}
|
|
5983
6792
|
if (byBoundary.size > 0) {
|
|
@@ -5985,12 +6794,12 @@ function requestCalls(call, pattern, options) {
|
|
|
5985
6794
|
}
|
|
5986
6795
|
return plain === null ? [] : [plain];
|
|
5987
6796
|
}
|
|
5988
|
-
function requestCall(call, called,
|
|
6797
|
+
function requestCall(call, called, base, pattern, options, site) {
|
|
5989
6798
|
const args = readCallArgs(field(call, "arguments"));
|
|
5990
6799
|
const verb = pattern.verbMethodNames[called];
|
|
5991
6800
|
if (verb !== void 0) {
|
|
5992
|
-
const
|
|
5993
|
-
return
|
|
6801
|
+
const target2 = targetAt(urlNodeIn(args, pattern), options, site);
|
|
6802
|
+
return target2 === null ? null : { method: verb, ...underBase(base, target2) };
|
|
5994
6803
|
}
|
|
5995
6804
|
const sent = pattern.requestObject;
|
|
5996
6805
|
if (sent === void 0 || sent.attribute !== called) {
|
|
@@ -6000,8 +6809,14 @@ function requestCall(call, called, prefix, pattern, options, site) {
|
|
|
6000
6809
|
if (built === null) {
|
|
6001
6810
|
return null;
|
|
6002
6811
|
}
|
|
6003
|
-
const
|
|
6004
|
-
return
|
|
6812
|
+
const target = targetAt(built.url, options, site);
|
|
6813
|
+
return target === null ? null : { method: built.method, ...underBase(base, target) };
|
|
6814
|
+
}
|
|
6815
|
+
function underBase(base, target) {
|
|
6816
|
+
if (base === null || target.host !== void 0) {
|
|
6817
|
+
return target;
|
|
6818
|
+
}
|
|
6819
|
+
return { path: base.path + target.path, host: base.host };
|
|
6005
6820
|
}
|
|
6006
6821
|
function requestBuilt(argument, sent, options, site) {
|
|
6007
6822
|
if (argument === void 0) {
|
|
@@ -6022,16 +6837,19 @@ function requestBuilt(argument, sent, options, site) {
|
|
|
6022
6837
|
function isLibraryReceiver(receiver, pattern, options) {
|
|
6023
6838
|
return namesConstant2(receiver, pattern.constantName) || builderCallBehind(receiver, pattern, options.facts) !== null;
|
|
6024
6839
|
}
|
|
6025
|
-
function
|
|
6840
|
+
function receiverBase(receiver, pattern, options, site) {
|
|
6026
6841
|
const built = builderCallBehind(receiver, pattern, options.facts);
|
|
6027
6842
|
if (built === null) {
|
|
6028
|
-
return
|
|
6843
|
+
return null;
|
|
6029
6844
|
}
|
|
6030
6845
|
const args = readCallArgs(field(built, "arguments"));
|
|
6031
6846
|
const keyword = pattern.builderUrlKeyword;
|
|
6032
6847
|
const base = (keyword === void 0 ? void 0 : args.keyword[keyword]) ?? args.positional[0];
|
|
6033
|
-
|
|
6034
|
-
|
|
6848
|
+
if (base === void 0) {
|
|
6849
|
+
return null;
|
|
6850
|
+
}
|
|
6851
|
+
const value = evaluatedValue(base, options.facts, void 0, site);
|
|
6852
|
+
return { path: trimmed((0, import_values14.pathOf)(value) ?? ""), host: (0, import_values14.hostOf)(value) };
|
|
6035
6853
|
}
|
|
6036
6854
|
function trimmed(path7) {
|
|
6037
6855
|
return path7 === "/" ? "" : path7.replace(/\/+$/, "");
|
|
@@ -6054,22 +6872,32 @@ function builderCallBehind(receiver, pattern, facts) {
|
|
|
6054
6872
|
const constant2 = field(written, "receiver");
|
|
6055
6873
|
return constant2 !== null && namesConstant2(constant2, pattern.constantName) ? written : null;
|
|
6056
6874
|
}
|
|
6057
|
-
function urlIn(args, pattern, options, site) {
|
|
6058
|
-
return pathAt(urlNodeIn(args, pattern), options, site);
|
|
6059
|
-
}
|
|
6060
6875
|
function urlNodeIn(args, pattern) {
|
|
6061
6876
|
const keyword = pattern.url.keyword;
|
|
6062
6877
|
return (keyword === void 0 ? void 0 : args.keyword[keyword]) ?? args.positional[pattern.url.position];
|
|
6063
6878
|
}
|
|
6064
|
-
function
|
|
6879
|
+
function targetAt(written, options, site) {
|
|
6065
6880
|
if (written === void 0) {
|
|
6066
6881
|
return null;
|
|
6067
6882
|
}
|
|
6068
|
-
const
|
|
6069
|
-
|
|
6883
|
+
const value = evaluatedValue(written, options.facts, void 0, site);
|
|
6884
|
+
const path7 = (0, import_values14.pathOf)(value);
|
|
6885
|
+
return path7 === void 0 || (0, import_behavioral_ir2.namesNothing)(path7) ? null : { path: path7, host: (0, import_values14.hostOf)(value) };
|
|
6070
6886
|
}
|
|
6071
6887
|
function clientUnit(method, name, request, pattern, pack, options) {
|
|
6072
6888
|
const range = rangeOf(method);
|
|
6889
|
+
const accessors = responseAccessors(pattern);
|
|
6890
|
+
const statusMembers = (0, import_behavioral_ir2.statusMembersOf)(accessors);
|
|
6891
|
+
const reading = {
|
|
6892
|
+
facts: options.facts,
|
|
6893
|
+
statusMembers,
|
|
6894
|
+
handOff: {
|
|
6895
|
+
request: request.call,
|
|
6896
|
+
bodyMethods: accessors.bodyAccessors ?? [],
|
|
6897
|
+
facts: options.facts,
|
|
6898
|
+
readHelper: (helper) => callerBranches(helper, { facts: options.facts, statusMembers })
|
|
6899
|
+
}
|
|
6900
|
+
};
|
|
6073
6901
|
return {
|
|
6074
6902
|
identity: {
|
|
6075
6903
|
name,
|
|
@@ -6081,25 +6909,34 @@ function clientUnit(method, name, request, pattern, pack, options) {
|
|
|
6081
6909
|
exportName: name,
|
|
6082
6910
|
exportPath: [name]
|
|
6083
6911
|
},
|
|
6084
|
-
boundaryBinding: (0,
|
|
6912
|
+
boundaryBinding: (0, import_behavioral_ir2.restBinding)({
|
|
6085
6913
|
transport: pack.protocol,
|
|
6086
6914
|
method: request.method,
|
|
6087
6915
|
path: request.path,
|
|
6916
|
+
host: request.host,
|
|
6088
6917
|
recognition: pack.name
|
|
6089
6918
|
}),
|
|
6090
6919
|
parameters: [],
|
|
6091
|
-
branches: callerBranches(method,
|
|
6092
|
-
...
|
|
6920
|
+
branches: callerBranches(method, reading),
|
|
6921
|
+
...accessors,
|
|
6093
6922
|
bodyContent: "statements",
|
|
6094
6923
|
dependencyCalls: [],
|
|
6095
6924
|
declaredContract: null
|
|
6096
6925
|
};
|
|
6097
6926
|
}
|
|
6098
|
-
function callerBranches(method,
|
|
6099
|
-
const
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6927
|
+
function callerBranches(method, reading) {
|
|
6928
|
+
const sites = invocationSites(method, void 0, void 0, reading.facts);
|
|
6929
|
+
const effects = sites.map((site) => site.effect);
|
|
6930
|
+
const keepsArms = (condition) => (0, import_behavioral_ir2.testsStatus)(predicateOf(condition), reading.statusMembers);
|
|
6931
|
+
const found = returnPathBranches(
|
|
6932
|
+
method,
|
|
6933
|
+
effects,
|
|
6934
|
+
[],
|
|
6935
|
+
reading.facts,
|
|
6936
|
+
keepsArms,
|
|
6937
|
+
raiseEndings(method)
|
|
6938
|
+
) ?? [returnBranch(rangeOf(method), effects)];
|
|
6939
|
+
return reading.handOff === void 0 ? found : throughResponseHelpers(found, sites, reading.handOff);
|
|
6103
6940
|
}
|
|
6104
6941
|
function responseAccessors(pattern) {
|
|
6105
6942
|
const response = pattern.response;
|
|
@@ -6110,7 +6947,8 @@ function responseAccessors(pattern) {
|
|
|
6110
6947
|
...response.body === void 0 ? {} : { bodyAccessors: response.body },
|
|
6111
6948
|
...response.statusCode === void 0 ? {} : { statusAccessors: response.statusCode },
|
|
6112
6949
|
...response.success === void 0 ? {} : { successAccessors: response.success },
|
|
6113
|
-
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery }
|
|
6950
|
+
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery },
|
|
6951
|
+
...response.redirectDelivery === void 0 ? {} : { redirectDelivery: response.redirectDelivery }
|
|
6114
6952
|
};
|
|
6115
6953
|
}
|
|
6116
6954
|
function returnBranch(range, effects) {
|
|
@@ -6135,8 +6973,8 @@ function returnBranch(range, effects) {
|
|
|
6135
6973
|
}
|
|
6136
6974
|
|
|
6137
6975
|
// src/envReads.ts
|
|
6138
|
-
var
|
|
6139
|
-
var
|
|
6976
|
+
var import_behavioral_ir3 = require("@suss/behavioral-ir");
|
|
6977
|
+
var import_extractor7 = require("@suss/extractor");
|
|
6140
6978
|
var import_resolution9 = require("@suss/resolution");
|
|
6141
6979
|
|
|
6142
6980
|
// src/envSpellings.ts
|
|
@@ -6161,9 +6999,7 @@ function elementSite(node) {
|
|
|
6161
6999
|
if (object === null || !isEnv(object) || isAssignedTo(node)) {
|
|
6162
7000
|
return null;
|
|
6163
7001
|
}
|
|
6164
|
-
const index = node.
|
|
6165
|
-
(child) => child !== null && child.id !== object.id
|
|
6166
|
-
);
|
|
7002
|
+
const index = children(node).find((child) => child.id !== object.id);
|
|
6167
7003
|
if (index === void 0) {
|
|
6168
7004
|
return null;
|
|
6169
7005
|
}
|
|
@@ -6344,7 +7180,7 @@ function followsExitWhenAbsent(parent, child, subject) {
|
|
|
6344
7180
|
if (!STATEMENT_LIST_TYPES.has(parent.type)) {
|
|
6345
7181
|
return false;
|
|
6346
7182
|
}
|
|
6347
|
-
const statements = parent
|
|
7183
|
+
const statements = children(parent);
|
|
6348
7184
|
const at = statements.findIndex((statement) => statement?.id === child.id);
|
|
6349
7185
|
return statements.slice(0, at).some(
|
|
6350
7186
|
(statement) => statement !== null && leavesWhenAbsent(statement, subject)
|
|
@@ -6396,7 +7232,7 @@ function continuationRaises(from) {
|
|
|
6396
7232
|
let parent = current.parent;
|
|
6397
7233
|
while (parent !== null) {
|
|
6398
7234
|
if (STATEMENT_LIST_TYPES.has(parent.type)) {
|
|
6399
|
-
const statements = parent
|
|
7235
|
+
const statements = children(parent);
|
|
6400
7236
|
const at = statements.findIndex((one) => one?.id === current.id);
|
|
6401
7237
|
const exit = firstExit(statements.slice(at + 1));
|
|
6402
7238
|
if (exit !== null) {
|
|
@@ -6430,20 +7266,13 @@ function firstExit(statements) {
|
|
|
6430
7266
|
return null;
|
|
6431
7267
|
}
|
|
6432
7268
|
function exitOf2(statement) {
|
|
6433
|
-
if (
|
|
7269
|
+
if (isRaiseCall(statement)) {
|
|
6434
7270
|
return "raise";
|
|
6435
7271
|
}
|
|
6436
7272
|
if (LEAVING_TYPES.has(statement.type)) {
|
|
6437
7273
|
return "leave";
|
|
6438
7274
|
}
|
|
6439
|
-
return STATEMENT_LIST_TYPES.has(statement.type) ? firstExit(statement
|
|
6440
|
-
}
|
|
6441
|
-
var RAISING_METHODS2 = /* @__PURE__ */ new Set(["raise", "fail"]);
|
|
6442
|
-
function isRaise3(node) {
|
|
6443
|
-
if (node.type === "identifier") {
|
|
6444
|
-
return RAISING_METHODS2.has(node.text);
|
|
6445
|
-
}
|
|
6446
|
-
return node.type === "call" && field(node, "receiver") === null && RAISING_METHODS2.has(field(node, "method")?.text ?? "");
|
|
7275
|
+
return STATEMENT_LIST_TYPES.has(statement.type) ? firstExit(children(statement)) : null;
|
|
6447
7276
|
}
|
|
6448
7277
|
function isPresentWhen(test, outcome, subject) {
|
|
6449
7278
|
const expression = peelParens(test);
|
|
@@ -6511,7 +7340,7 @@ function isNilCheckOn(call, receiver) {
|
|
|
6511
7340
|
return call.type === "call" && field(call, "method")?.text === "nil?" && field(call, "receiver")?.id === receiver.id;
|
|
6512
7341
|
}
|
|
6513
7342
|
function peelParens(node) {
|
|
6514
|
-
const inner = node.type === "parenthesized_statements" && node.namedChildCount === 1 ? node.
|
|
7343
|
+
const inner = node.type === "parenthesized_statements" && node.namedChildCount === 1 ? node.namedChild(0) : null;
|
|
6515
7344
|
return inner === null || inner === void 0 ? node : peelParens(inner);
|
|
6516
7345
|
}
|
|
6517
7346
|
function climbParens(node) {
|
|
@@ -6556,7 +7385,7 @@ var DEFERRED_BODY_TYPES = /* @__PURE__ */ new Set(["method", "singleton_method",
|
|
|
6556
7385
|
function envReadEffects(root, facts) {
|
|
6557
7386
|
const helpers = helperFactsOf(facts);
|
|
6558
7387
|
const slots = [];
|
|
6559
|
-
(0,
|
|
7388
|
+
(0, import_extractor7.walkDescendants)(root, null, children, {
|
|
6560
7389
|
at: (node) => {
|
|
6561
7390
|
const read = envReadAt(node);
|
|
6562
7391
|
if (read !== null) {
|
|
@@ -6567,7 +7396,7 @@ function envReadEffects(root, facts) {
|
|
|
6567
7396
|
slots.push({ call: node });
|
|
6568
7397
|
}
|
|
6569
7398
|
},
|
|
6570
|
-
into: (node) => DEFERRED_BODY_TYPES.has(node.type) ?
|
|
7399
|
+
into: (node) => DEFERRED_BODY_TYPES.has(node.type) ? import_extractor7.SKIP_CHILDREN : null
|
|
6571
7400
|
});
|
|
6572
7401
|
const calls = slots.flatMap((slot) => "call" in slot ? [slot.call] : []);
|
|
6573
7402
|
const throughHelpers = helpers === null ? new NodeMap() : helperReads(calls, helpers);
|
|
@@ -6636,7 +7465,7 @@ function namedParameters(db) {
|
|
|
6636
7465
|
return named2;
|
|
6637
7466
|
}
|
|
6638
7467
|
function emitEnvFacts(db, file, root) {
|
|
6639
|
-
(0,
|
|
7468
|
+
(0, import_extractor7.walkDescendants)(root, null, children, {
|
|
6640
7469
|
at: (node) => {
|
|
6641
7470
|
if (isEnv(node) && handsOnward(node)) {
|
|
6642
7471
|
db.add("environmentObject", [
|
|
@@ -6734,7 +7563,7 @@ function readsAtCall(db, call, args) {
|
|
|
6734
7563
|
function configReadEffect(read) {
|
|
6735
7564
|
return {
|
|
6736
7565
|
type: "interaction",
|
|
6737
|
-
binding: (0,
|
|
7566
|
+
binding: (0, import_behavioral_ir3.runtimeConfigBinding)({ recognition: RUBY_ENV_RECOGNITION }),
|
|
6738
7567
|
callee: `ENV["${read.name}"]`,
|
|
6739
7568
|
interaction: {
|
|
6740
7569
|
class: "config-read",
|
|
@@ -6764,6 +7593,7 @@ function envSiteAt(node) {
|
|
|
6764
7593
|
}
|
|
6765
7594
|
|
|
6766
7595
|
// src/filters.ts
|
|
7596
|
+
var RESCUES_NOTHING = { refs: [], someUnread: false };
|
|
6767
7597
|
function controllerFilters(pattern, ancestry, read = {}) {
|
|
6768
7598
|
const forms = pattern.filters ?? [];
|
|
6769
7599
|
if (forms.length === 0) {
|
|
@@ -6777,18 +7607,29 @@ function controllerFilters(pattern, ancestry, read = {}) {
|
|
|
6777
7607
|
}
|
|
6778
7608
|
}
|
|
6779
7609
|
let declared = [];
|
|
6780
|
-
|
|
7610
|
+
const inlineSeen = /* @__PURE__ */ new Map();
|
|
7611
|
+
for (const { block, statement } of inheritedStatements(ancestry)) {
|
|
6781
7612
|
const called = calledName(statement);
|
|
6782
7613
|
if (called === null) {
|
|
6783
7614
|
continue;
|
|
6784
7615
|
}
|
|
6785
7616
|
const form = byName.get(called);
|
|
6786
7617
|
if (form !== void 0) {
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
7618
|
+
const inlineKey = `${block.file}\0${block.info.qualifiedName}\0${form.name}`;
|
|
7619
|
+
const ordinal = inlineSeen.get(inlineKey) ?? 0;
|
|
7620
|
+
const declarations = declarationsOf(
|
|
7621
|
+
statement,
|
|
7622
|
+
form,
|
|
7623
|
+
block,
|
|
7624
|
+
read.facts,
|
|
7625
|
+
ordinal
|
|
7626
|
+
);
|
|
7627
|
+
if (declarations.some((one) => one.inline !== void 0)) {
|
|
7628
|
+
inlineSeen.set(inlineKey, ordinal + 1);
|
|
7629
|
+
}
|
|
7630
|
+
for (const declaration of declarations) {
|
|
7631
|
+
const earlier = declaration.filter.onThrow === true ? void 0 : declared.find((one) => sameFilter(one, declaration));
|
|
7632
|
+
declared = [...declared.filter((one) => one !== earlier), declaration];
|
|
6792
7633
|
}
|
|
6793
7634
|
continue;
|
|
6794
7635
|
}
|
|
@@ -6799,62 +7640,105 @@ function controllerFilters(pattern, ancestry, read = {}) {
|
|
|
6799
7640
|
}
|
|
6800
7641
|
const resolved = [];
|
|
6801
7642
|
for (const declaration of declared) {
|
|
6802
|
-
const
|
|
6803
|
-
|
|
7643
|
+
const written = writtenAt(
|
|
7644
|
+
declaration,
|
|
7645
|
+
filterMethod(ancestry, declaration.methodName, read)
|
|
7646
|
+
);
|
|
7647
|
+
if (written === null) {
|
|
6804
7648
|
continue;
|
|
6805
7649
|
}
|
|
6806
7650
|
resolved.push({
|
|
6807
7651
|
filter: declaration.filter,
|
|
6808
|
-
|
|
6809
|
-
method: found.method,
|
|
6810
|
-
file: found.block.file,
|
|
6811
|
-
enclosingQualifiedName: found.block.info.qualifiedName,
|
|
7652
|
+
...written,
|
|
6812
7653
|
only: declaration.only,
|
|
6813
|
-
except: declaration.except
|
|
7654
|
+
except: declaration.except,
|
|
7655
|
+
rescues: declaration.rescues
|
|
6814
7656
|
});
|
|
6815
7657
|
}
|
|
6816
7658
|
return [
|
|
6817
7659
|
...resolved.filter((one) => one.filter.onThrow !== true),
|
|
6818
|
-
...resolved.filter((one) => one.filter.onThrow === true)
|
|
7660
|
+
...resolved.filter((one) => one.filter.onThrow === true).reverse()
|
|
6819
7661
|
];
|
|
6820
7662
|
}
|
|
7663
|
+
function writtenAt(declaration, found) {
|
|
7664
|
+
if (found.type === "found") {
|
|
7665
|
+
return {
|
|
7666
|
+
methodName: declaration.methodName,
|
|
7667
|
+
nameKind: "binding",
|
|
7668
|
+
method: found.method,
|
|
7669
|
+
file: found.block.file,
|
|
7670
|
+
enclosingQualifiedName: found.block.info.qualifiedName,
|
|
7671
|
+
nesting: found.block.info.bodyNesting
|
|
7672
|
+
};
|
|
7673
|
+
}
|
|
7674
|
+
const inline = declaration.inline;
|
|
7675
|
+
if (inline === void 0) {
|
|
7676
|
+
return null;
|
|
7677
|
+
}
|
|
7678
|
+
return {
|
|
7679
|
+
methodName: inline.label,
|
|
7680
|
+
nameKind: "label",
|
|
7681
|
+
method: inline.block,
|
|
7682
|
+
file: inline.declaredIn.file,
|
|
7683
|
+
enclosingQualifiedName: inline.declaredIn.info.qualifiedName,
|
|
7684
|
+
nesting: inline.declaredIn.info.bodyNesting
|
|
7685
|
+
};
|
|
7686
|
+
}
|
|
7687
|
+
function filterMethod(ancestry, name, read) {
|
|
7688
|
+
const found = methodInAncestry(ancestry, name, read);
|
|
7689
|
+
if (found.type === "unsettled" && found.cause === "unreadAncestor") {
|
|
7690
|
+
return methodPastUnreadAncestors(ancestry, name, read);
|
|
7691
|
+
}
|
|
7692
|
+
return found;
|
|
7693
|
+
}
|
|
6821
7694
|
function filterCoversAction(filter, actionName) {
|
|
6822
7695
|
if (filter.except.has(actionName)) {
|
|
6823
7696
|
return false;
|
|
6824
7697
|
}
|
|
6825
7698
|
return filter.only === null || filter.only.has(actionName);
|
|
6826
7699
|
}
|
|
6827
|
-
function filterReference(filter, displayPath) {
|
|
7700
|
+
function filterReference(filter, displayPath, caught) {
|
|
6828
7701
|
return {
|
|
6829
7702
|
file: displayPath,
|
|
6830
7703
|
name: filter.methodName,
|
|
6831
|
-
...filter.filter.onThrow === true ? { onThrow: true } : {}
|
|
7704
|
+
...filter.filter.onThrow === true ? { onThrow: true } : {},
|
|
7705
|
+
...caught === void 0 ? {} : {
|
|
7706
|
+
catches: caught.classes.map((one) => one.name),
|
|
7707
|
+
...caught.classes.some((one) => one.inheritableByUnread) ? { mayCatchUnreadClasses: true } : {},
|
|
7708
|
+
...caught.someUnread ? { mayCatchAny: true } : {}
|
|
7709
|
+
}
|
|
6832
7710
|
};
|
|
6833
7711
|
}
|
|
6834
|
-
function filterUnit(filter, pattern, displayPath, body,
|
|
7712
|
+
function filterUnit(filter, pattern, displayPath, body, reading = {}) {
|
|
6835
7713
|
const range = rangeOf(filter.method);
|
|
7714
|
+
const { respondingHelper, raises: raises2 } = reading;
|
|
6836
7715
|
const branches = responseBranches(
|
|
6837
7716
|
filter.method,
|
|
6838
7717
|
pattern,
|
|
6839
7718
|
body.effects ?? [],
|
|
6840
7719
|
body.extraEffects,
|
|
6841
|
-
{
|
|
7720
|
+
{
|
|
7721
|
+
fallthrough: "handOn",
|
|
7722
|
+
facts: reading.facts,
|
|
7723
|
+
...respondingHelper === void 0 ? {} : { respondingHelper },
|
|
7724
|
+
...raises2 === void 0 ? {} : { raises: raises2 }
|
|
7725
|
+
}
|
|
6842
7726
|
);
|
|
6843
7727
|
return {
|
|
6844
7728
|
identity: {
|
|
6845
7729
|
name: filter.methodName,
|
|
6846
|
-
nameKind:
|
|
7730
|
+
nameKind: filter.nameKind,
|
|
6847
7731
|
kind: "middleware",
|
|
6848
7732
|
file: displayPath,
|
|
6849
7733
|
range,
|
|
6850
7734
|
span: spanOf(filter.method),
|
|
6851
|
-
exportName: filter.methodName,
|
|
7735
|
+
exportName: filter.nameKind === "binding" ? filter.methodName : null,
|
|
6852
7736
|
exportPath: [filter.enclosingQualifiedName, filter.methodName]
|
|
6853
7737
|
},
|
|
6854
7738
|
boundaryBinding: null,
|
|
6855
7739
|
parameters: [],
|
|
6856
7740
|
branches: withSlotSources(
|
|
6857
|
-
branches ?? [handsOn(range, body)],
|
|
7741
|
+
[...branches ?? [handsOn(range, body)], ...reading.raised ?? []],
|
|
6858
7742
|
body.provenance
|
|
6859
7743
|
),
|
|
6860
7744
|
bodyContent: body.bodyContent ?? "absent",
|
|
@@ -6889,25 +7773,92 @@ function calledName(statement) {
|
|
|
6889
7773
|
}
|
|
6890
7774
|
return field(statement, "method")?.text ?? null;
|
|
6891
7775
|
}
|
|
6892
|
-
function declarationsOf(statement, filter, facts) {
|
|
7776
|
+
function declarationsOf(statement, filter, declaredIn, facts, inlineOrdinal) {
|
|
6893
7777
|
const args = readCallArgs(field(statement, "arguments"));
|
|
6894
7778
|
const keywords = filter.actionKeywords;
|
|
6895
7779
|
const only = keywords === void 0 ? null : actionsUnder(args.keyword[keywords.include], facts);
|
|
6896
7780
|
const except = keywords === void 0 ? null : actionsUnder(args.keyword[keywords.exclude], facts);
|
|
6897
|
-
|
|
7781
|
+
const rescues2 = filter.onThrow === true ? rescuedClasses(args, declaredIn.info.bodyNesting, facts) : RESCUES_NOTHING;
|
|
7782
|
+
const inline = inlineHandler(
|
|
7783
|
+
statement,
|
|
7784
|
+
args,
|
|
7785
|
+
filter,
|
|
7786
|
+
declaredIn,
|
|
7787
|
+
inlineOrdinal
|
|
7788
|
+
);
|
|
7789
|
+
return methodNamesOf(args, filter, facts, inline).map((methodName) => ({
|
|
6898
7790
|
filter,
|
|
6899
7791
|
methodName,
|
|
6900
7792
|
only,
|
|
6901
|
-
except: except ?? /* @__PURE__ */ new Set()
|
|
7793
|
+
except: except ?? /* @__PURE__ */ new Set(),
|
|
7794
|
+
rescues: rescues2,
|
|
7795
|
+
...inline === void 0 ? {} : { inline }
|
|
6902
7796
|
}));
|
|
6903
7797
|
}
|
|
6904
|
-
function
|
|
7798
|
+
function inlineHandler(statement, args, filter, declaredIn, ordinal) {
|
|
7799
|
+
const block = blockInPlaceOfMethod(statement, args, filter);
|
|
7800
|
+
if (block === null || blockStatements2(block).length === 0) {
|
|
7801
|
+
return void 0;
|
|
7802
|
+
}
|
|
7803
|
+
return { block, label: `${filter.name}#${ordinal}`, declaredIn };
|
|
7804
|
+
}
|
|
7805
|
+
function rescuedClasses(args, nesting, facts) {
|
|
7806
|
+
const refs = [];
|
|
7807
|
+
let someUnread = args.positional.length === 0;
|
|
7808
|
+
for (const arg of args.positional) {
|
|
7809
|
+
const candidates = constantRefCandidates(arg, nesting);
|
|
7810
|
+
const named2 = candidates.length === 0 ? stringValueOf(arg, facts) : null;
|
|
7811
|
+
if (candidates.length === 0 && named2 === null) {
|
|
7812
|
+
someUnread = true;
|
|
7813
|
+
continue;
|
|
7814
|
+
}
|
|
7815
|
+
refs.push({
|
|
7816
|
+
text: arg.text,
|
|
7817
|
+
candidates: named2 === null ? candidates : [named2]
|
|
7818
|
+
});
|
|
7819
|
+
}
|
|
7820
|
+
return { refs, someUnread };
|
|
7821
|
+
}
|
|
7822
|
+
function methodNamesOf(args, filter, facts, inline) {
|
|
7823
|
+
const named2 = filter.methodFrom === "withKeyword" ? withKeywordName(args, facts) : symbolArgumentNames(args, facts);
|
|
7824
|
+
if (named2.length > 0 || inline === void 0) {
|
|
7825
|
+
return named2;
|
|
7826
|
+
}
|
|
7827
|
+
return [blockHandlerName(inline.block) ?? inline.label];
|
|
7828
|
+
}
|
|
7829
|
+
function withKeywordName(args, facts) {
|
|
7830
|
+
const named2 = args.keyword.with;
|
|
7831
|
+
const value = named2 === void 0 ? null : stringValueOf(named2, facts);
|
|
7832
|
+
return value === null ? [] : [value];
|
|
7833
|
+
}
|
|
7834
|
+
function blockInPlaceOfMethod(statement, args, filter) {
|
|
6905
7835
|
if (filter.methodFrom === "withKeyword") {
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
7836
|
+
return args.keyword.with === void 0 ? field(statement, "block") : null;
|
|
7837
|
+
}
|
|
7838
|
+
const lambda = args.positional.find((arg) => arg.type === "lambda");
|
|
7839
|
+
if (lambda !== void 0) {
|
|
7840
|
+
return field(lambda, "body");
|
|
7841
|
+
}
|
|
7842
|
+
return args.positional.length === 0 ? field(statement, "block") : null;
|
|
7843
|
+
}
|
|
7844
|
+
function blockStatements2(block) {
|
|
7845
|
+
return children(field(block, "body")).filter(
|
|
7846
|
+
(child) => child.type !== "comment"
|
|
7847
|
+
);
|
|
7848
|
+
}
|
|
7849
|
+
function blockHandlerName(block) {
|
|
7850
|
+
const statements = blockStatements2(block);
|
|
7851
|
+
const only = statements.length === 1 ? statements[0] : void 0;
|
|
7852
|
+
if (only === void 0) {
|
|
7853
|
+
return null;
|
|
7854
|
+
}
|
|
7855
|
+
const parameters = new Set(
|
|
7856
|
+
children(field(block, "parameters")).map((parameter) => parameter.text)
|
|
7857
|
+
);
|
|
7858
|
+
if (only.type === "identifier") {
|
|
7859
|
+
return parameters.has(only.text) ? null : only.text;
|
|
6909
7860
|
}
|
|
6910
|
-
return
|
|
7861
|
+
return calledName(only);
|
|
6911
7862
|
}
|
|
6912
7863
|
function symbolArgumentNames(args, facts) {
|
|
6913
7864
|
return args.positional.map((arg) => stringValueOf(arg, facts)).filter((name) => name !== null);
|
|
@@ -6918,13 +7869,16 @@ function skipsOf(statement, filterName, facts) {
|
|
|
6918
7869
|
return args.positional.map((arg) => stringValueOf(arg, facts)).filter((name) => name !== null).map((methodName) => ({ filterName, methodName, actions }));
|
|
6919
7870
|
}
|
|
6920
7871
|
function sameFilter(one, other) {
|
|
6921
|
-
return one.filter.name === other.filter.name && one.methodName === other.methodName;
|
|
7872
|
+
return namedBySymbol(one) && namedBySymbol(other) && one.filter.name === other.filter.name && one.methodName === other.methodName;
|
|
7873
|
+
}
|
|
7874
|
+
function namedBySymbol(declaration) {
|
|
7875
|
+
return declaration.inline === void 0;
|
|
6922
7876
|
}
|
|
6923
7877
|
function applySkips(declared, skips) {
|
|
6924
7878
|
const left = [];
|
|
6925
7879
|
for (const declaration of declared) {
|
|
6926
7880
|
const reaching = skips.filter(
|
|
6927
|
-
(skip) => skip.filterName === declaration.filter.name && skip.methodName === declaration.methodName
|
|
7881
|
+
(skip) => namedBySymbol(declaration) && skip.filterName === declaration.filter.name && skip.methodName === declaration.methodName
|
|
6928
7882
|
);
|
|
6929
7883
|
if (reaching.some((skip) => skip.actions === null)) {
|
|
6930
7884
|
continue;
|
|
@@ -6948,8 +7902,8 @@ function actionsUnder(node, facts) {
|
|
|
6948
7902
|
}
|
|
6949
7903
|
|
|
6950
7904
|
// src/streamWrites.ts
|
|
6951
|
-
var
|
|
6952
|
-
var
|
|
7905
|
+
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
7906
|
+
var import_extractor8 = require("@suss/extractor");
|
|
6953
7907
|
var RUBY_STREAM_RECOGNITION = "ruby-stdlib";
|
|
6954
7908
|
var KERNEL_WRITES = /* @__PURE__ */ new Map([
|
|
6955
7909
|
["puts", "stdout"],
|
|
@@ -6967,14 +7921,14 @@ var STREAM_METHODS = /* @__PURE__ */ new Set(["puts", "print", "write", "<<"]);
|
|
|
6967
7921
|
var DEFERRED_BODY_TYPES2 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
6968
7922
|
function streamWriteEffects(root) {
|
|
6969
7923
|
const found = [];
|
|
6970
|
-
(0,
|
|
7924
|
+
(0, import_extractor8.walkDescendants)(root, null, children, {
|
|
6971
7925
|
at: (node) => {
|
|
6972
7926
|
const write = node.type === "call" ? streamWriteAt(node) : null;
|
|
6973
7927
|
if (write !== null) {
|
|
6974
7928
|
found.push(write);
|
|
6975
7929
|
}
|
|
6976
7930
|
},
|
|
6977
|
-
into: (node) => DEFERRED_BODY_TYPES2.has(node.type) ?
|
|
7931
|
+
into: (node) => DEFERRED_BODY_TYPES2.has(node.type) ? import_extractor8.SKIP_CHILDREN : null
|
|
6978
7932
|
});
|
|
6979
7933
|
return found;
|
|
6980
7934
|
}
|
|
@@ -7005,7 +7959,7 @@ function writeEffect(call, target, args) {
|
|
|
7005
7959
|
const method = field(call, "method")?.text ?? "";
|
|
7006
7960
|
return {
|
|
7007
7961
|
type: "interaction",
|
|
7008
|
-
binding: (0,
|
|
7962
|
+
binding: (0, import_behavioral_ir4.ioBinding)({ recognition: RUBY_STREAM_RECOGNITION, target }),
|
|
7009
7963
|
callee: receiver === null ? method : `${receiver.text}.${method}`,
|
|
7010
7964
|
groupId: `${call.startPosition.row + 1}:${call.startPosition.column + 1}`,
|
|
7011
7965
|
interaction: { class: "stream-write", ...payloadOf(args) }
|
|
@@ -7058,7 +8012,7 @@ function writtenShapeOf(node) {
|
|
|
7058
8012
|
return hashShape(node);
|
|
7059
8013
|
}
|
|
7060
8014
|
if (node.type === "array") {
|
|
7061
|
-
const first = node.
|
|
8015
|
+
const first = children(node).find((child) => child !== null);
|
|
7062
8016
|
return {
|
|
7063
8017
|
type: "array",
|
|
7064
8018
|
items: first ? writtenShapeOf(first) : { type: "unknown" }
|
|
@@ -7068,7 +8022,7 @@ function writtenShapeOf(node) {
|
|
|
7068
8022
|
}
|
|
7069
8023
|
function hashShape(node) {
|
|
7070
8024
|
const properties = {};
|
|
7071
|
-
for (const pair of node
|
|
8025
|
+
for (const pair of children(node)) {
|
|
7072
8026
|
if (pair?.type !== "pair") {
|
|
7073
8027
|
continue;
|
|
7074
8028
|
}
|
|
@@ -7086,10 +8040,10 @@ function keyName(key) {
|
|
|
7086
8040
|
}
|
|
7087
8041
|
|
|
7088
8042
|
// src/testCases.ts
|
|
7089
|
-
var
|
|
7090
|
-
var
|
|
8043
|
+
var import_behavioral_ir5 = require("@suss/behavioral-ir");
|
|
8044
|
+
var import_extractor9 = require("@suss/extractor");
|
|
7091
8045
|
var import_resolution10 = require("@suss/resolution");
|
|
7092
|
-
var
|
|
8046
|
+
var import_values17 = require("@suss/values");
|
|
7093
8047
|
var BLOCK_TYPES6 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
7094
8048
|
function testPatternsIn(packs) {
|
|
7095
8049
|
return packs.flatMap((pack) => pack.tests ?? []);
|
|
@@ -7273,7 +8227,7 @@ function groupStatements(group) {
|
|
|
7273
8227
|
}
|
|
7274
8228
|
function patternForFile(file, patterns) {
|
|
7275
8229
|
return patterns.find(
|
|
7276
|
-
(pattern) => (0,
|
|
8230
|
+
(pattern) => (0, import_extractor9.matchesTestFileName)(file, pattern.filePatterns) && (0, import_extractor9.isListedTestFile)(file, pattern.files)
|
|
7277
8231
|
) ?? null;
|
|
7278
8232
|
}
|
|
7279
8233
|
function groupNamesIn(pattern) {
|
|
@@ -7431,14 +8385,14 @@ var NodesSeen = class {
|
|
|
7431
8385
|
};
|
|
7432
8386
|
function exampleRun(example, pattern, shared) {
|
|
7433
8387
|
const byName = /* @__PURE__ */ new Map();
|
|
7434
|
-
const
|
|
8388
|
+
const always3 = [];
|
|
7435
8389
|
for (const group of withInlineIncludes(example.groups, pattern, shared)) {
|
|
7436
8390
|
for (const one of groupBlocks(group, pattern)) {
|
|
7437
8391
|
for (const name of one.names) {
|
|
7438
8392
|
byName.set(name, one.block);
|
|
7439
8393
|
}
|
|
7440
8394
|
if (one.always) {
|
|
7441
|
-
|
|
8395
|
+
always3.push(one.block);
|
|
7442
8396
|
}
|
|
7443
8397
|
}
|
|
7444
8398
|
}
|
|
@@ -7457,7 +8411,7 @@ function exampleRun(example, pattern, shared) {
|
|
|
7457
8411
|
}
|
|
7458
8412
|
};
|
|
7459
8413
|
include(example.block);
|
|
7460
|
-
for (const block of
|
|
8414
|
+
for (const block of always3) {
|
|
7461
8415
|
include(block);
|
|
7462
8416
|
}
|
|
7463
8417
|
const valueNames = /* @__PURE__ */ new Set([
|
|
@@ -7565,7 +8519,7 @@ function exampleCalls(run, inherited) {
|
|
|
7565
8519
|
}
|
|
7566
8520
|
function testCaseUnits(root, patterns, options) {
|
|
7567
8521
|
return patterns.flatMap((pattern) => {
|
|
7568
|
-
if (!(0,
|
|
8522
|
+
if (!(0, import_extractor9.matchesTestFileName)(options.absoluteFile, pattern.filePatterns) || !(0, import_extractor9.isListedTestFile)(options.absoluteFile, pattern.files)) {
|
|
7569
8523
|
return [];
|
|
7570
8524
|
}
|
|
7571
8525
|
return examplesIn(root, options.absoluteFile, pattern, options.shared).map(
|
|
@@ -7638,7 +8592,7 @@ function testUnitOf(parts) {
|
|
|
7638
8592
|
const range = rangeOf(anchor);
|
|
7639
8593
|
return {
|
|
7640
8594
|
identity: {
|
|
7641
|
-
name: (0,
|
|
8595
|
+
name: (0, import_behavioral_ir5.testUnitName)(titles.map((title) => title.text)),
|
|
7642
8596
|
nameKind: "label",
|
|
7643
8597
|
kind: "test",
|
|
7644
8598
|
file: options.filePath,
|
|
@@ -7684,7 +8638,7 @@ function titleOf(call, facts) {
|
|
|
7684
8638
|
if (first.type === "constant" || first.type === "scope_resolution") {
|
|
7685
8639
|
return { text: first.text, unresolved: false };
|
|
7686
8640
|
}
|
|
7687
|
-
const read = (0,
|
|
8641
|
+
const read = (0, import_values17.literalOf)(evaluatedValue(first, facts));
|
|
7688
8642
|
return read === null ? { text: first.text, unresolved: true } : { text: read, unresolved: false };
|
|
7689
8643
|
}
|
|
7690
8644
|
function isSkipped(example, pattern) {
|
|
@@ -7825,7 +8779,7 @@ function moduleOfConstant(node, options) {
|
|
|
7825
8779
|
const key = classBehind(facts, options.absoluteFile, node);
|
|
7826
8780
|
return key === void 0 ? null : options.displayPathOf((0, import_resolution10.fileOfKey)(key));
|
|
7827
8781
|
}
|
|
7828
|
-
const name = (0,
|
|
8782
|
+
const name = (0, import_values17.literalOf)(evaluatedValue(node, facts));
|
|
7829
8783
|
const keys = name === null ? [] : facts.lookup("rbConstantName", 1, name.replace(/^::/, "")).map((row) => String(row[0]));
|
|
7830
8784
|
const files = [...new Set(keys.map(import_resolution10.fileOfKey))];
|
|
7831
8785
|
return files.length === 1 ? options.displayPathOf(files[0]) : null;
|
|
@@ -7835,8 +8789,8 @@ function oneLine(text2) {
|
|
|
7835
8789
|
}
|
|
7836
8790
|
|
|
7837
8791
|
// src/testClasses.ts
|
|
7838
|
-
var
|
|
7839
|
-
var
|
|
8792
|
+
var import_extractor10 = require("@suss/extractor");
|
|
8793
|
+
var import_values19 = require("@suss/values");
|
|
7840
8794
|
var BLOCK_TYPES7 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
7841
8795
|
function testClassPatternsIn(packs) {
|
|
7842
8796
|
return packs.flatMap((pack) => pack.testClasses ?? []);
|
|
@@ -7879,7 +8833,7 @@ function testClassUnits(root, patterns, options) {
|
|
|
7879
8833
|
});
|
|
7880
8834
|
}
|
|
7881
8835
|
function readsFile(file, pattern) {
|
|
7882
|
-
return (0,
|
|
8836
|
+
return (0, import_extractor10.matchesTestFileName)(file, pattern.filePatterns) && (0, import_extractor10.isListedTestFile)(file, pattern.files);
|
|
7883
8837
|
}
|
|
7884
8838
|
function testClassesIn(root, file, pattern, facts) {
|
|
7885
8839
|
const found = [];
|
|
@@ -7925,7 +8879,7 @@ function testBlockOf(statement, pattern) {
|
|
|
7925
8879
|
}
|
|
7926
8880
|
function descriptionOf(call, facts) {
|
|
7927
8881
|
const first = firstArgument(call);
|
|
7928
|
-
return first === null ? null : (0,
|
|
8882
|
+
return first === null ? null : (0, import_values19.literalOf)(evaluatedValue(first, facts));
|
|
7929
8883
|
}
|
|
7930
8884
|
function anchorOf2(node) {
|
|
7931
8885
|
return BLOCK_TYPES7.has(node.type) ? node.parent ?? node : node;
|
|
@@ -8102,6 +9056,7 @@ function fieldReadContext(pattern, cache, fileBlocks, bodyRead, facts) {
|
|
|
8102
9056
|
},
|
|
8103
9057
|
lookup: {
|
|
8104
9058
|
root: pattern.root,
|
|
9059
|
+
autoloadRoots: pattern.autoloadRoots ?? [],
|
|
8105
9060
|
pathConvention: pattern.pathConvention,
|
|
8106
9061
|
acronyms: pattern.acronyms ?? [],
|
|
8107
9062
|
ancestryRootClassNames: pattern.ancestryRootClassNames,
|
|
@@ -8210,7 +9165,7 @@ function unitsFor(pattern, pack, info, ownBlocks, fileBlocks, options) {
|
|
|
8210
9165
|
graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, fileBlocks, options),
|
|
8211
9166
|
controllerActions: (p) => controllerActionUnits(p, pack, info, ownBlocks, fileBlocks, options)
|
|
8212
9167
|
};
|
|
8213
|
-
return (0,
|
|
9168
|
+
return (0, import_behavioral_ir6.dispatchByType)(table, pattern);
|
|
8214
9169
|
}
|
|
8215
9170
|
async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
|
|
8216
9171
|
if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
|
|
@@ -8257,6 +9212,7 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
8257
9212
|
}
|
|
8258
9213
|
const lookup = {
|
|
8259
9214
|
root: pattern.root,
|
|
9215
|
+
autoloadRoots: pattern.autoloadRoots ?? [],
|
|
8260
9216
|
pathConvention: pattern.pathConvention,
|
|
8261
9217
|
acronyms: pattern.acronyms ?? [],
|
|
8262
9218
|
ancestryRootClassNames: pattern.ancestryRootClassNames,
|
|
@@ -8295,15 +9251,41 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
8295
9251
|
options.facts,
|
|
8296
9252
|
options.storage
|
|
8297
9253
|
);
|
|
9254
|
+
const respondingHelper = respondingHelpersOf(ancestry, pattern, options);
|
|
9255
|
+
const exceptions = new ExceptionReader(
|
|
9256
|
+
lookup,
|
|
9257
|
+
pattern.libraryExceptions ?? {}
|
|
9258
|
+
);
|
|
9259
|
+
const caught = await handlerClasses(filters, exceptions);
|
|
9260
|
+
const handlersAround = (actionName) => filters.filter((filter) => filterCoversAction(filter, actionName)).flatMap((filter) => {
|
|
9261
|
+
const classes = caught.get(filter);
|
|
9262
|
+
return classes === void 0 ? [] : [classes];
|
|
9263
|
+
});
|
|
8298
9264
|
for (const filter of filters) {
|
|
8299
9265
|
const displayPath = options.displayPathOf?.(filter.file) ?? filter.file;
|
|
8300
|
-
const
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
9266
|
+
const body = bodyOfMethod(filter.method, filter.file, options);
|
|
9267
|
+
const handler = filter.filter.onThrow === true;
|
|
9268
|
+
const raw = filterUnit(filter, pattern, displayPath, body, {
|
|
9269
|
+
facts: options.facts,
|
|
9270
|
+
respondingHelper,
|
|
9271
|
+
...handler ? {} : {
|
|
9272
|
+
raises: {
|
|
9273
|
+
classes: await raisedClasses(
|
|
9274
|
+
filter.method,
|
|
9275
|
+
filter.nesting,
|
|
9276
|
+
exceptions
|
|
9277
|
+
),
|
|
9278
|
+
handlers: "eachRoute"
|
|
9279
|
+
},
|
|
9280
|
+
raised: raisedStatusBranches(
|
|
9281
|
+
pattern,
|
|
9282
|
+
options.storage?.patterns ?? [],
|
|
9283
|
+
body.extraEffects,
|
|
9284
|
+
"eachRoute",
|
|
9285
|
+
rangeOf(filter.method)
|
|
9286
|
+
)
|
|
9287
|
+
}
|
|
9288
|
+
});
|
|
8307
9289
|
units.push(raw);
|
|
8308
9290
|
options.onReachSeed?.(raw, {
|
|
8309
9291
|
file: filter.file,
|
|
@@ -8311,38 +9293,71 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
8311
9293
|
enclosingQualifiedName: filter.enclosingQualifiedName
|
|
8312
9294
|
});
|
|
8313
9295
|
}
|
|
8314
|
-
const emitAction = (actionName, method, block) => {
|
|
9296
|
+
const emitAction = async (actionName, method, block, routes) => {
|
|
8315
9297
|
const around = filters.filter((filter) => filterCoversAction(filter, actionName)).map(
|
|
8316
9298
|
(filter) => filterReference(
|
|
8317
9299
|
filter,
|
|
8318
|
-
options.displayPathOf?.(filter.file) ?? filter.file
|
|
9300
|
+
options.displayPathOf?.(filter.file) ?? filter.file,
|
|
9301
|
+
caught.get(filter)
|
|
8319
9302
|
)
|
|
8320
9303
|
);
|
|
8321
|
-
const
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
9304
|
+
const raises2 = {
|
|
9305
|
+
classes: await raisedClasses(method, block.info.bodyNesting, exceptions),
|
|
9306
|
+
handlers: handlersAround(actionName)
|
|
9307
|
+
};
|
|
9308
|
+
for (const route of routes.length === 0 ? [null] : routes) {
|
|
9309
|
+
const raw = buildControllerActionUnit(
|
|
9310
|
+
pack,
|
|
9311
|
+
pattern,
|
|
9312
|
+
info.qualifiedName,
|
|
9313
|
+
actionName,
|
|
9314
|
+
route,
|
|
9315
|
+
method,
|
|
9316
|
+
{
|
|
9317
|
+
display: block.file === (options.absoluteFile ?? options.filePath) ? options.filePath : options.displayPathOf?.(block.file) ?? block.file,
|
|
9318
|
+
absolute: block.file
|
|
9319
|
+
},
|
|
9320
|
+
options,
|
|
9321
|
+
around,
|
|
9322
|
+
respondingHelper,
|
|
9323
|
+
raises2
|
|
9324
|
+
);
|
|
9325
|
+
units.push(raw);
|
|
9326
|
+
options.onReachSeed?.(raw, {
|
|
9327
|
+
file: block.file,
|
|
9328
|
+
node: method,
|
|
9329
|
+
enclosingQualifiedName: block.info.qualifiedName
|
|
9330
|
+
});
|
|
9331
|
+
}
|
|
8340
9332
|
};
|
|
8341
9333
|
for (const [actionName, method, block] of actions) {
|
|
8342
|
-
|
|
9334
|
+
const routes = pattern.routesFor(info.qualifiedName, actionName);
|
|
9335
|
+
await emitAction(actionName, method, block, routes);
|
|
8343
9336
|
}
|
|
8344
9337
|
return units;
|
|
8345
9338
|
}
|
|
9339
|
+
async function handlerClasses(filters, exceptions) {
|
|
9340
|
+
const caught = /* @__PURE__ */ new Map();
|
|
9341
|
+
for (const filter of filters) {
|
|
9342
|
+
if (filter.filter.onThrow !== true) {
|
|
9343
|
+
continue;
|
|
9344
|
+
}
|
|
9345
|
+
const classes = [];
|
|
9346
|
+
for (const ref of filter.rescues.refs) {
|
|
9347
|
+
classes.push(await exceptions.read(ref));
|
|
9348
|
+
}
|
|
9349
|
+
caught.set(filter, { classes, someUnread: filter.rescues.someUnread });
|
|
9350
|
+
}
|
|
9351
|
+
return caught;
|
|
9352
|
+
}
|
|
9353
|
+
async function raisedClasses(method, nesting, exceptions) {
|
|
9354
|
+
const classes = new NodeMap();
|
|
9355
|
+
for (const call of escapingRaises(method)) {
|
|
9356
|
+
const ref = raisedClassRef(call, nesting);
|
|
9357
|
+
classes.set(call, ref === null ? null : await exceptions.read(ref));
|
|
9358
|
+
}
|
|
9359
|
+
return classes;
|
|
9360
|
+
}
|
|
8346
9361
|
function controllerActions(pattern, info, ownBlocks, ancestry, options) {
|
|
8347
9362
|
const actions = publicInstanceMethods(ownBlocks, options.bodyBlocks);
|
|
8348
9363
|
const seen = new Set(actions.map(([actionName]) => actionName));
|
|
@@ -8359,7 +9374,7 @@ function controllerActions(pattern, info, ownBlocks, ancestry, options) {
|
|
|
8359
9374
|
continue;
|
|
8360
9375
|
}
|
|
8361
9376
|
seen.add(actionName);
|
|
8362
|
-
if (pattern.
|
|
9377
|
+
if (pattern.routesFor(info.qualifiedName, actionName).length > 0) {
|
|
8363
9378
|
actions.push(action);
|
|
8364
9379
|
}
|
|
8365
9380
|
}
|
|
@@ -8384,16 +9399,52 @@ function publicInstanceMethods(blocks, bodyBlocks) {
|
|
|
8384
9399
|
}
|
|
8385
9400
|
return found;
|
|
8386
9401
|
}
|
|
8387
|
-
function
|
|
9402
|
+
function respondingHelpersOf(ancestry, pattern, options) {
|
|
9403
|
+
const methods = /* @__PURE__ */ new Map();
|
|
9404
|
+
const known = /* @__PURE__ */ new Map();
|
|
9405
|
+
const declared = new Set(
|
|
9406
|
+
(pattern.responseStatusCalls ?? []).map((call) => call.name)
|
|
9407
|
+
);
|
|
9408
|
+
const methodNamed = (name) => {
|
|
9409
|
+
if (!methods.has(name)) {
|
|
9410
|
+
const found = methodInAncestry(ancestry, name, {
|
|
9411
|
+
facts: options.facts,
|
|
9412
|
+
bodyBlocks: options.bodyBlocks,
|
|
9413
|
+
dynamicNames: options.dynamicNames
|
|
9414
|
+
});
|
|
9415
|
+
methods.set(name, found.type === "found" ? found.method : null);
|
|
9416
|
+
}
|
|
9417
|
+
return methods.get(name) ?? null;
|
|
9418
|
+
};
|
|
9419
|
+
return (name, call) => {
|
|
9420
|
+
const method = declared.has(name) ? null : methodNamed(name);
|
|
9421
|
+
if (method === null) {
|
|
9422
|
+
return null;
|
|
9423
|
+
}
|
|
9424
|
+
const bound = boundStatusArguments(method, call, pattern, options.facts);
|
|
9425
|
+
const key = `${name}(${[...bound].join(",")})`;
|
|
9426
|
+
if (!known.has(key)) {
|
|
9427
|
+
known.set(key, helperResponse(method, pattern, options.facts, bound));
|
|
9428
|
+
}
|
|
9429
|
+
return known.get(key) ?? null;
|
|
9430
|
+
};
|
|
9431
|
+
}
|
|
9432
|
+
function servesFormat(pattern, route) {
|
|
9433
|
+
return pattern.optionalFormat === true && route.formatless !== true && !route.path.endsWith("/");
|
|
9434
|
+
}
|
|
9435
|
+
function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actionName, route, method, file, bodyRead, wrappers, respondingHelper, raises2) {
|
|
8388
9436
|
const range = rangeOf(method);
|
|
8389
|
-
const route = pattern.routeFor(controllerQualifiedName, actionName);
|
|
8390
9437
|
const body = bodyOfMethod(method, file.absolute, bodyRead);
|
|
8391
9438
|
const perResponse = responseBranches(
|
|
8392
9439
|
method,
|
|
8393
9440
|
pattern,
|
|
8394
9441
|
body.effects ?? [],
|
|
8395
9442
|
body.extraEffects,
|
|
8396
|
-
{
|
|
9443
|
+
{
|
|
9444
|
+
facts: bodyRead.facts,
|
|
9445
|
+
respondingHelper,
|
|
9446
|
+
raises: raises2
|
|
9447
|
+
}
|
|
8397
9448
|
);
|
|
8398
9449
|
return {
|
|
8399
9450
|
identity: {
|
|
@@ -8406,11 +9457,12 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
8406
9457
|
exportName: actionName,
|
|
8407
9458
|
exportPath: [controllerQualifiedName, actionName]
|
|
8408
9459
|
},
|
|
8409
|
-
boundaryBinding: route === null ? null : (0,
|
|
9460
|
+
boundaryBinding: route === null ? null : (0, import_behavioral_ir6.restBinding)({
|
|
8410
9461
|
transport: pack.protocol,
|
|
8411
9462
|
method: route.method,
|
|
8412
9463
|
path: route.path,
|
|
8413
|
-
recognition: pack.name
|
|
9464
|
+
recognition: pack.name,
|
|
9465
|
+
optionalFormat: servesFormat(pattern, route)
|
|
8414
9466
|
}),
|
|
8415
9467
|
parameters: [],
|
|
8416
9468
|
branches: withSlotSources(
|
|
@@ -8430,7 +9482,7 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
8430
9482
|
location: range
|
|
8431
9483
|
},
|
|
8432
9484
|
statusCodeReading: {
|
|
8433
|
-
reading:
|
|
9485
|
+
reading: import_extractor11.absentReading,
|
|
8434
9486
|
libraryDefault: pattern.defaultStatusCode
|
|
8435
9487
|
},
|
|
8436
9488
|
effects: body.effects ?? [],
|
|
@@ -8440,6 +9492,14 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
8440
9492
|
}
|
|
8441
9493
|
],
|
|
8442
9494
|
body.provenance
|
|
9495
|
+
).concat(
|
|
9496
|
+
raisedStatusBranches(
|
|
9497
|
+
pattern,
|
|
9498
|
+
bodyRead.storage?.patterns ?? [],
|
|
9499
|
+
body.extraEffects,
|
|
9500
|
+
raises2.handlers,
|
|
9501
|
+
range
|
|
9502
|
+
)
|
|
8443
9503
|
),
|
|
8444
9504
|
bodyContent: body.bodyContent ?? "absent",
|
|
8445
9505
|
dependencyCalls: [],
|
|
@@ -8481,7 +9541,7 @@ function routingGapUnit(pattern, gaps) {
|
|
|
8481
9541
|
isDefault: true
|
|
8482
9542
|
}
|
|
8483
9543
|
],
|
|
8484
|
-
readings: gaps.map((gap) => (0,
|
|
9544
|
+
readings: gaps.map((gap) => (0, import_extractor11.unreadableReading)(gap, range)),
|
|
8485
9545
|
dependencyCalls: [],
|
|
8486
9546
|
declaredContract: null
|
|
8487
9547
|
};
|
|
@@ -8554,7 +9614,7 @@ var NO_METHOD_BEHIND_IT = {
|
|
|
8554
9614
|
readings: []
|
|
8555
9615
|
};
|
|
8556
9616
|
function methodNotSettled(reason, range) {
|
|
8557
|
-
return { readings: [(0,
|
|
9617
|
+
return { readings: [(0, import_extractor11.unreadableReading)(reason, range)] };
|
|
8558
9618
|
}
|
|
8559
9619
|
function bodyFromLookup(found, range, subject, nothingThere, bodyRead) {
|
|
8560
9620
|
const table = {
|
|
@@ -8572,7 +9632,7 @@ function bodyFromLookup(found, range, subject, nothingThere, bodyRead) {
|
|
|
8572
9632
|
),
|
|
8573
9633
|
none: () => nothingThere
|
|
8574
9634
|
};
|
|
8575
|
-
return (0,
|
|
9635
|
+
return (0, import_behavioral_ir6.dispatchByType)(table, found);
|
|
8576
9636
|
}
|
|
8577
9637
|
async function readFieldCall(stmt, scope, ctx, ancestry) {
|
|
8578
9638
|
if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
|
|
@@ -8615,7 +9675,7 @@ function computedNameDeclaration(stmt, nameArg) {
|
|
|
8615
9675
|
contract: null,
|
|
8616
9676
|
body: {
|
|
8617
9677
|
readings: [
|
|
8618
|
-
(0,
|
|
9678
|
+
(0, import_extractor11.unreadableReading)(
|
|
8619
9679
|
`This field is named by ${nameArg.text}, which is worked out when the class body runs, so the name the schema exposes it under was not read here`,
|
|
8620
9680
|
range
|
|
8621
9681
|
)
|
|
@@ -8846,7 +9906,7 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
|
|
|
8846
9906
|
exportName: null,
|
|
8847
9907
|
exportPath: null
|
|
8848
9908
|
},
|
|
8849
|
-
boundaryBinding: decl.namedOnTheWire ? (0,
|
|
9909
|
+
boundaryBinding: decl.namedOnTheWire ? (0, import_behavioral_ir6.graphqlResolverBinding)({
|
|
8850
9910
|
transport: pack.protocol,
|
|
8851
9911
|
recognition: pack.name,
|
|
8852
9912
|
typeName,
|
|
@@ -9262,15 +10322,15 @@ function parseWith(language, source) {
|
|
|
9262
10322
|
// src/project.ts
|
|
9263
10323
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
9264
10324
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
9265
|
-
var
|
|
10325
|
+
var import_behavioral_ir9 = require("@suss/behavioral-ir");
|
|
9266
10326
|
var import_datalog3 = require("@suss/datalog");
|
|
9267
|
-
var
|
|
10327
|
+
var import_extractor19 = require("@suss/extractor");
|
|
9268
10328
|
var import_resolution16 = require("@suss/resolution");
|
|
9269
10329
|
|
|
9270
10330
|
// src/diagnostics.ts
|
|
9271
|
-
var
|
|
10331
|
+
var import_extractor12 = require("@suss/extractor");
|
|
9272
10332
|
function buildRubyExtractionReport(args) {
|
|
9273
|
-
return (0,
|
|
10333
|
+
return (0, import_extractor12.buildUngatedExtractionReport)({
|
|
9274
10334
|
packs: args.packs.map((pack) => ({
|
|
9275
10335
|
name: pack.name,
|
|
9276
10336
|
version: pack.version ?? null,
|
|
@@ -9283,9 +10343,9 @@ function buildRubyExtractionReport(args) {
|
|
|
9283
10343
|
}
|
|
9284
10344
|
|
|
9285
10345
|
// src/exits.ts
|
|
9286
|
-
var
|
|
10346
|
+
var import_extractor13 = require("@suss/extractor");
|
|
9287
10347
|
var import_resolution11 = require("@suss/resolution");
|
|
9288
|
-
var
|
|
10348
|
+
var import_values22 = require("@suss/values");
|
|
9289
10349
|
var EXIT_METHODS = /* @__PURE__ */ new Map([
|
|
9290
10350
|
["exit", 0],
|
|
9291
10351
|
["exit!", 1],
|
|
@@ -9294,14 +10354,14 @@ var EXIT_METHODS = /* @__PURE__ */ new Map([
|
|
|
9294
10354
|
var DEFERRED_BODY_TYPES3 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
9295
10355
|
function exitSites(root) {
|
|
9296
10356
|
const found = [];
|
|
9297
|
-
(0,
|
|
10357
|
+
(0, import_extractor13.walkDescendants)(root, null, children, {
|
|
9298
10358
|
at: (node) => {
|
|
9299
10359
|
const site = node.type === "call" ? exitSiteAt(node) : null;
|
|
9300
10360
|
if (site !== null) {
|
|
9301
10361
|
found.push(site);
|
|
9302
10362
|
}
|
|
9303
10363
|
},
|
|
9304
|
-
into: (node) => DEFERRED_BODY_TYPES3.has(node.type) ?
|
|
10364
|
+
into: (node) => DEFERRED_BODY_TYPES3.has(node.type) ? import_extractor13.SKIP_CHILDREN : null
|
|
9305
10365
|
});
|
|
9306
10366
|
return found;
|
|
9307
10367
|
}
|
|
@@ -9338,7 +10398,7 @@ function exitCodeOf(site, facts) {
|
|
|
9338
10398
|
if (written !== void 0) {
|
|
9339
10399
|
return { type: "literal", value: written };
|
|
9340
10400
|
}
|
|
9341
|
-
const value = (0,
|
|
10401
|
+
const value = (0, import_values22.constantOf)(evaluatedValue(code, facts));
|
|
9342
10402
|
return typeof value === "number" ? { type: "literal", value } : { type: "dynamic", sourceText: code.text };
|
|
9343
10403
|
}
|
|
9344
10404
|
function exitingBranches(method, effects, facts) {
|
|
@@ -9359,7 +10419,7 @@ function markExitCodeFunctions(summaries, exits, facts, workspaceRoot) {
|
|
|
9359
10419
|
(site) => site.code === null ? [] : [nodeId(file, site.code)]
|
|
9360
10420
|
)
|
|
9361
10421
|
);
|
|
9362
|
-
(0,
|
|
10422
|
+
(0, import_extractor13.markReturnsAsExitCode)(
|
|
9363
10423
|
summaries,
|
|
9364
10424
|
(0, import_resolution11.exitCodeFunctions)(facts, sinks),
|
|
9365
10425
|
workspaceRoot
|
|
@@ -9409,9 +10469,9 @@ function eventsOf(args, called, callbacks, db) {
|
|
|
9409
10469
|
|
|
9410
10470
|
// src/facts.ts
|
|
9411
10471
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
9412
|
-
var
|
|
10472
|
+
var import_extractor14 = require("@suss/extractor");
|
|
9413
10473
|
function emitRequireFacts(db, filePath, root, known) {
|
|
9414
|
-
(0,
|
|
10474
|
+
(0, import_extractor14.walkDescendants)(root, null, children, {
|
|
9415
10475
|
at: (node) => {
|
|
9416
10476
|
const target = requiredRelativePath(node);
|
|
9417
10477
|
if (target === null) {
|
|
@@ -9425,7 +10485,7 @@ function emitRequireFacts(db, filePath, root, known) {
|
|
|
9425
10485
|
db.add("importsFile", [filePath, resolved]);
|
|
9426
10486
|
}
|
|
9427
10487
|
},
|
|
9428
|
-
into: (node) => node.type === "argument_list" ?
|
|
10488
|
+
into: (node) => node.type === "argument_list" ? import_extractor14.SKIP_CHILDREN : null
|
|
9429
10489
|
});
|
|
9430
10490
|
}
|
|
9431
10491
|
function requiredRelativePath(node) {
|
|
@@ -9437,17 +10497,17 @@ function requiredRelativePath(node) {
|
|
|
9437
10497
|
}
|
|
9438
10498
|
|
|
9439
10499
|
// src/moduleSurface.ts
|
|
9440
|
-
var
|
|
9441
|
-
var
|
|
10500
|
+
var import_behavioral_ir8 = require("@suss/behavioral-ir");
|
|
10501
|
+
var import_extractor17 = require("@suss/extractor");
|
|
9442
10502
|
|
|
9443
10503
|
// src/reach/closure.ts
|
|
9444
|
-
var
|
|
10504
|
+
var import_behavioral_ir7 = require("@suss/behavioral-ir");
|
|
9445
10505
|
var import_datalog2 = require("@suss/datalog");
|
|
9446
|
-
var
|
|
10506
|
+
var import_extractor16 = require("@suss/extractor");
|
|
9447
10507
|
var import_resolution13 = require("@suss/resolution");
|
|
9448
10508
|
|
|
9449
10509
|
// src/flags.ts
|
|
9450
|
-
var
|
|
10510
|
+
var import_extractor15 = require("@suss/extractor");
|
|
9451
10511
|
var PARSE_METHODS = /* @__PURE__ */ new Set(["parse", "parse!", "permute", "permute!"]);
|
|
9452
10512
|
var DEFERRED_BODY_TYPES4 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
9453
10513
|
function optionParserFlagReads(method, parameterNames3) {
|
|
@@ -9476,9 +10536,9 @@ function optionParserFlagReads(method, parameterNames3) {
|
|
|
9476
10536
|
return reads;
|
|
9477
10537
|
}
|
|
9478
10538
|
function walkBody2(body, at) {
|
|
9479
|
-
(0,
|
|
10539
|
+
(0, import_extractor15.walkDescendants)(body, null, children, {
|
|
9480
10540
|
at,
|
|
9481
|
-
into: (node) => DEFERRED_BODY_TYPES4.has(node.type) ?
|
|
10541
|
+
into: (node) => DEFERRED_BODY_TYPES4.has(node.type) ? import_extractor15.SKIP_CHILDREN : null
|
|
9482
10542
|
});
|
|
9483
10543
|
}
|
|
9484
10544
|
var OPTION_PARSER_SPELLINGS = /* @__PURE__ */ new Set(["OptionParser", "::OptionParser"]);
|
|
@@ -9492,7 +10552,7 @@ function flagsDeclaredIn(construction) {
|
|
|
9492
10552
|
return [];
|
|
9493
10553
|
}
|
|
9494
10554
|
const flags = [];
|
|
9495
|
-
(0,
|
|
10555
|
+
(0, import_extractor15.walkDescendants)(block, null, children, {
|
|
9496
10556
|
at: (node) => {
|
|
9497
10557
|
if (node.type !== "call" || field(node, "method")?.text !== "on") {
|
|
9498
10558
|
return;
|
|
@@ -9564,6 +10624,11 @@ var UNSETTLED_ON_SELF = {
|
|
|
9564
10624
|
reason: "noDeclaration",
|
|
9565
10625
|
matchByName: true
|
|
9566
10626
|
};
|
|
10627
|
+
var SELF_CALL_IN_MIXIN = {
|
|
10628
|
+
kind: "stopped",
|
|
10629
|
+
reason: "selfCallInMixin",
|
|
10630
|
+
matchByName: true
|
|
10631
|
+
};
|
|
9567
10632
|
function followed(target) {
|
|
9568
10633
|
return { kind: "followed", target };
|
|
9569
10634
|
}
|
|
@@ -9752,22 +10817,27 @@ function leavesRoomForATopLevelMethod(reason) {
|
|
|
9752
10817
|
return reason === "noDeclaration" || reason === "outsideRun";
|
|
9753
10818
|
}
|
|
9754
10819
|
function resolveImplicitSelf(methodName, site, ctx) {
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
site.enclosingQualifiedName,
|
|
9759
|
-
methodName,
|
|
9760
|
-
ctx
|
|
9761
|
-
);
|
|
9762
|
-
if (onClass.kind === "followed" || !leavesRoomForATopLevelMethod(onClass.reason)) {
|
|
9763
|
-
return onClass;
|
|
9764
|
-
}
|
|
10820
|
+
const onClass = site.enclosingQualifiedName === null ? null : methodOnSelf(site, site.enclosingQualifiedName, methodName, ctx);
|
|
10821
|
+
if (onClass !== null && (onClass.kind === "followed" || !leavesRoomForATopLevelMethod(onClass.reason))) {
|
|
10822
|
+
return onClass;
|
|
9765
10823
|
}
|
|
10824
|
+
const readWholeAncestry = onClass?.kind === "stopped" && onClass.reason === "noDeclaration";
|
|
9766
10825
|
const topLevel = resolveTopLevelName(methodName, ctx);
|
|
9767
10826
|
if (topLevel.kind === "followed" || topLevel.reason !== "noDeclaration") {
|
|
9768
10827
|
return topLevel;
|
|
9769
10828
|
}
|
|
9770
|
-
|
|
10829
|
+
if (declaredForTheOtherSelf(site, methodName, ctx)) {
|
|
10830
|
+
return NO_DECLARATION;
|
|
10831
|
+
}
|
|
10832
|
+
return readWholeAncestry && !OBJECT_METHODS.has(methodName) && inModuleInstanceMethod(site, ctx) ? SELF_CALL_IN_MIXIN : UNSETTLED_ON_SELF;
|
|
10833
|
+
}
|
|
10834
|
+
function inModuleInstanceMethod(site, ctx) {
|
|
10835
|
+
const qualifiedName = site.enclosingQualifiedName;
|
|
10836
|
+
if (qualifiedName === null || site.method === null || inClassMethod(site, ctx)) {
|
|
10837
|
+
return false;
|
|
10838
|
+
}
|
|
10839
|
+
const own = ctx.ancestries.get(qualifiedName)?.[0];
|
|
10840
|
+
return own?.type === "bodies" && own.blocks.every((block) => block.info.kind === "module");
|
|
9771
10841
|
}
|
|
9772
10842
|
function declaredForTheOtherSelf(site, methodName, ctx) {
|
|
9773
10843
|
const qualifiedName = site.enclosingQualifiedName;
|
|
@@ -9810,12 +10880,16 @@ function methodOnAncestryOf(qualifiedName, methodName, ctx) {
|
|
|
9810
10880
|
return followed(reachedMethod(found.method, found.block, methodName));
|
|
9811
10881
|
}
|
|
9812
10882
|
if (found.type === "unsettled") {
|
|
9813
|
-
return stop(
|
|
9814
|
-
found.cause === "dynamicDefine" ? "definedAtLoadTime" : "outsideRun"
|
|
9815
|
-
);
|
|
10883
|
+
return stop(unsettledReason(found));
|
|
9816
10884
|
}
|
|
9817
10885
|
return NO_DECLARATION;
|
|
9818
10886
|
}
|
|
10887
|
+
function unsettledReason(found) {
|
|
10888
|
+
if (found.cause === "dynamicDefine") {
|
|
10889
|
+
return "definedAtLoadTime";
|
|
10890
|
+
}
|
|
10891
|
+
return found.definedLater === true ? "behindUnreadAncestor" : "outsideRun";
|
|
10892
|
+
}
|
|
9819
10893
|
function reachedMethod(node, block, name) {
|
|
9820
10894
|
return {
|
|
9821
10895
|
file: block.file,
|
|
@@ -9975,15 +11049,15 @@ async function reachedFunctions(seeds, options) {
|
|
|
9975
11049
|
const build = () => {
|
|
9976
11050
|
const raw = libraryUnit(target, options);
|
|
9977
11051
|
dropPropertyReads(raw, propertyReadsByKey.get(key));
|
|
9978
|
-
const summary2 = (0,
|
|
11052
|
+
const summary2 = (0, import_extractor16.assembleSummary)(raw, { gapHandling });
|
|
9979
11053
|
if (gapHandling !== "silent") {
|
|
9980
11054
|
summary2.gaps.push(
|
|
9981
|
-
...(stopsByKey.get(key) ?? []).map(
|
|
11055
|
+
...(stopsByKey.get(key) ?? []).map(import_behavioral_ir7.unfollowedCallGap)
|
|
9982
11056
|
);
|
|
9983
11057
|
}
|
|
9984
|
-
(0,
|
|
9985
|
-
(0,
|
|
9986
|
-
(0,
|
|
11058
|
+
(0, import_behavioral_ir7.placeCalls)(summary2, targetsByKey.get(key));
|
|
11059
|
+
(0, import_behavioral_ir7.placeArgTargets)(summary2, argTargetsByKey.get(key));
|
|
11060
|
+
(0, import_behavioral_ir7.placeCalleeParameters)(summary2, parameterCallsByKey.get(key));
|
|
9987
11061
|
return summary2;
|
|
9988
11062
|
};
|
|
9989
11063
|
const summary = ledger === void 0 ? build() : ledger.charging(chargeOf(charges, key), () => {
|
|
@@ -9998,7 +11072,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
9998
11072
|
summaries.push(summary);
|
|
9999
11073
|
}
|
|
10000
11074
|
if (gapHandling !== "silent") {
|
|
10001
|
-
(0,
|
|
11075
|
+
(0, import_behavioral_ir7.recordParameterGaps)(parameterCallsByKey, summariesByKey, passedPositions);
|
|
10002
11076
|
}
|
|
10003
11077
|
return {
|
|
10004
11078
|
summaries,
|
|
@@ -10211,9 +11285,9 @@ function scanBody(source, ctx, options, read) {
|
|
|
10211
11285
|
);
|
|
10212
11286
|
const ownParameters = positionalParameters(source.node).map((p) => p.name);
|
|
10213
11287
|
const followed2 = [];
|
|
10214
|
-
const stops =
|
|
10215
|
-
const placements = new
|
|
10216
|
-
const receiverClasses = new
|
|
11288
|
+
const stops = new import_behavioral_ir7.StopList();
|
|
11289
|
+
const placements = new import_behavioral_ir7.TargetPlacements();
|
|
11290
|
+
const receiverClasses = new import_behavioral_ir7.ReceiverClasses();
|
|
10217
11291
|
const parameterCalls = [];
|
|
10218
11292
|
const passedPositions = /* @__PURE__ */ new Set();
|
|
10219
11293
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -10295,11 +11369,13 @@ function scanBody(source, ctx, options, read) {
|
|
|
10295
11369
|
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
10296
11370
|
);
|
|
10297
11371
|
if (outcome.kind === "stopped") {
|
|
10298
|
-
const stopKey = `${outcome.reason}:${callee}`;
|
|
10299
11372
|
const claimed = options.storage !== void 0 && storageClaims(call, callSite.file, options.storage, callSite.method);
|
|
10300
|
-
if (!
|
|
10301
|
-
|
|
10302
|
-
|
|
11373
|
+
if (!claimed && (0, import_behavioral_ir7.worthRecording)(outcome.reason)) {
|
|
11374
|
+
stops.add({
|
|
11375
|
+
callee,
|
|
11376
|
+
reason: outcome.reason,
|
|
11377
|
+
...resultUsedAsValue(call) ? { usedAsValue: true } : {}
|
|
11378
|
+
});
|
|
10303
11379
|
}
|
|
10304
11380
|
if (outcome.reason === "callerSupplied" && !parameterCallsSeen.has(callee)) {
|
|
10305
11381
|
const receiverName = field(call, "receiver")?.text;
|
|
@@ -10322,7 +11398,7 @@ function scanBody(source, ctx, options, read) {
|
|
|
10322
11398
|
}
|
|
10323
11399
|
return {
|
|
10324
11400
|
followed: followed2,
|
|
10325
|
-
stops,
|
|
11401
|
+
stops: stops.stops,
|
|
10326
11402
|
targets: placements.targets,
|
|
10327
11403
|
argTargets: placements.argTargets,
|
|
10328
11404
|
parameterCalls,
|
|
@@ -10363,7 +11439,7 @@ function propertyReadsAmong(argless, made, keptArgless) {
|
|
|
10363
11439
|
}
|
|
10364
11440
|
return reads;
|
|
10365
11441
|
}
|
|
10366
|
-
function libraryUnit(target, options, binding = (0,
|
|
11442
|
+
function libraryUnit(target, options, binding = (0, import_behavioral_ir7.functionCallBinding)({
|
|
10367
11443
|
transport: "in-process",
|
|
10368
11444
|
recognition: "reachable"
|
|
10369
11445
|
})) {
|
|
@@ -10448,10 +11524,10 @@ function parameterName(param) {
|
|
|
10448
11524
|
|
|
10449
11525
|
// src/moduleSurface.ts
|
|
10450
11526
|
function settleRubyModules(modules) {
|
|
10451
|
-
return (0,
|
|
11527
|
+
return (0, import_extractor17.settleModules)(modules, ["{name}.rb", "../{name}.rb"]);
|
|
10452
11528
|
}
|
|
10453
11529
|
function moduleExportUnits(root, file, options) {
|
|
10454
|
-
const module2 = (0,
|
|
11530
|
+
const module2 = (0, import_extractor17.moduleOfFile)(options.modules, file);
|
|
10455
11531
|
if (module2 === void 0 || !module2.public.includes(file)) {
|
|
10456
11532
|
return [];
|
|
10457
11533
|
}
|
|
@@ -10478,8 +11554,8 @@ function moduleExportUnits(root, file, options) {
|
|
|
10478
11554
|
exportPath: [info.qualifiedName, method]
|
|
10479
11555
|
},
|
|
10480
11556
|
options,
|
|
10481
|
-
(0,
|
|
10482
|
-
recognition:
|
|
11557
|
+
(0, import_behavioral_ir8.moduleExportBinding)({
|
|
11558
|
+
recognition: import_extractor17.MODULE_SURFACE_RECOGNITION,
|
|
10483
11559
|
module: module2.name,
|
|
10484
11560
|
exportName: name
|
|
10485
11561
|
})
|
|
@@ -10787,11 +11863,11 @@ var WalkReplay = class {
|
|
|
10787
11863
|
};
|
|
10788
11864
|
|
|
10789
11865
|
// src/testFactories.ts
|
|
10790
|
-
var
|
|
11866
|
+
var import_values29 = require("@suss/values");
|
|
10791
11867
|
function factoriesIn(packs) {
|
|
10792
11868
|
return packs.flatMap((pack) => pack.factories ?? []);
|
|
10793
11869
|
}
|
|
10794
|
-
function emitFactoryFacts(db, files,
|
|
11870
|
+
function emitFactoryFacts(db, files, isTestFile2, patterns, inflections) {
|
|
10795
11871
|
for (const pattern of patterns) {
|
|
10796
11872
|
const definitions = /* @__PURE__ */ new Map();
|
|
10797
11873
|
for (const { file, root } of files) {
|
|
@@ -10799,7 +11875,7 @@ function emitFactoryFacts(db, files, isTestFile, patterns, inflections) {
|
|
|
10799
11875
|
}
|
|
10800
11876
|
const classes = new FactoryClasses(db, definitions, inflections);
|
|
10801
11877
|
for (const { file, root } of files) {
|
|
10802
|
-
if (!
|
|
11878
|
+
if (!isTestFile2(file)) {
|
|
10803
11879
|
continue;
|
|
10804
11880
|
}
|
|
10805
11881
|
for (const [call, name] of buildsIn(db, root, pattern)) {
|
|
@@ -10849,7 +11925,7 @@ function classRefOf(db, file, node) {
|
|
|
10849
11925
|
if (node.type === "constant" || node.type === "scope_resolution") {
|
|
10850
11926
|
return { key: readKey(file, node, null) };
|
|
10851
11927
|
}
|
|
10852
|
-
const written = (0,
|
|
11928
|
+
const written = (0, import_values29.literalOf)(evaluatedValue(node, db));
|
|
10853
11929
|
if (written === null) {
|
|
10854
11930
|
return null;
|
|
10855
11931
|
}
|
|
@@ -10858,7 +11934,7 @@ function classRefOf(db, file, node) {
|
|
|
10858
11934
|
};
|
|
10859
11935
|
}
|
|
10860
11936
|
function nameOf(db, node) {
|
|
10861
|
-
return symbolValue(node) ?? (0,
|
|
11937
|
+
return symbolValue(node) ?? (0, import_values29.literalOf)(evaluatedValue(node, db));
|
|
10862
11938
|
}
|
|
10863
11939
|
var FactoryClasses = class {
|
|
10864
11940
|
constructor(db, definitions, inflections) {
|
|
@@ -10930,7 +12006,7 @@ function builtAt(db, call, pattern) {
|
|
|
10930
12006
|
|
|
10931
12007
|
// src/testSharedGroups.ts
|
|
10932
12008
|
var import_resolution15 = require("@suss/resolution");
|
|
10933
|
-
var
|
|
12009
|
+
var import_values31 = require("@suss/values");
|
|
10934
12010
|
var ByNode = class {
|
|
10935
12011
|
byTree = /* @__PURE__ */ new WeakMap();
|
|
10936
12012
|
set(node, value) {
|
|
@@ -11034,7 +12110,7 @@ var SharedGroupIndex = class {
|
|
|
11034
12110
|
}
|
|
11035
12111
|
nameOf(call) {
|
|
11036
12112
|
const first = firstArgument(call);
|
|
11037
|
-
return first === null ? null : (0,
|
|
12113
|
+
return first === null ? null : (0, import_values31.literalOf)(evaluatedValue(first, this.db));
|
|
11038
12114
|
}
|
|
11039
12115
|
noteRead(definition) {
|
|
11040
12116
|
if (definition !== null) {
|
|
@@ -11111,16 +12187,16 @@ function visibleAt(index, site, pattern) {
|
|
|
11111
12187
|
}
|
|
11112
12188
|
|
|
11113
12189
|
// src/version.ts
|
|
11114
|
-
var
|
|
12190
|
+
var import_extractor18 = require("@suss/extractor");
|
|
11115
12191
|
var ADAPTER_VERSION = "0.1.0";
|
|
11116
|
-
var adapterStamp = (0,
|
|
12192
|
+
var adapterStamp = (0, import_extractor18.createAdapterStamp)({
|
|
11117
12193
|
moduleUrl: importMetaUrl,
|
|
11118
12194
|
version: ADAPTER_VERSION
|
|
11119
12195
|
});
|
|
11120
12196
|
|
|
11121
12197
|
// src/project.ts
|
|
11122
12198
|
function keptRubyParses() {
|
|
11123
|
-
return new
|
|
12199
|
+
return new import_extractor19.KeptParses((root) => root.tree.delete());
|
|
11124
12200
|
}
|
|
11125
12201
|
async function parseRubyAhead(files, kept) {
|
|
11126
12202
|
for (const file of files) {
|
|
@@ -11225,7 +12301,7 @@ var RunFacts = class {
|
|
|
11225
12301
|
...this.testFiles.map(({ file }) => file),
|
|
11226
12302
|
...this.parsed.map(({ file }) => file).filter(
|
|
11227
12303
|
(file) => classTests.some(
|
|
11228
|
-
(one) => (0,
|
|
12304
|
+
(one) => (0, import_extractor19.matchesTestFileName)(file, one.filePatterns)
|
|
11229
12305
|
)
|
|
11230
12306
|
)
|
|
11231
12307
|
]);
|
|
@@ -11260,7 +12336,7 @@ function factsForFile(options) {
|
|
|
11260
12336
|
return facts.db;
|
|
11261
12337
|
}
|
|
11262
12338
|
function moduleInitUnit(options) {
|
|
11263
|
-
const raw = (0,
|
|
12339
|
+
const raw = (0, import_extractor19.moduleInitStructure)({
|
|
11264
12340
|
name: options.name,
|
|
11265
12341
|
file: options.file,
|
|
11266
12342
|
range: options.range,
|
|
@@ -11274,7 +12350,7 @@ function moduleInitUnit(options) {
|
|
|
11274
12350
|
}
|
|
11275
12351
|
function discoveredAs(raw) {
|
|
11276
12352
|
const reported = raw.identity.exportPath?.join(".") ?? raw.identity.name;
|
|
11277
|
-
const boundary = raw.boundaryBinding === null ? "" : (0,
|
|
12353
|
+
const boundary = raw.boundaryBinding === null ? "" : (0, import_behavioral_ir9.boundaryKey)(raw.boundaryBinding) ?? "";
|
|
11278
12354
|
return `${raw.identity.file}::${reported}::${raw.identity.range.start}::${boundary}`;
|
|
11279
12355
|
}
|
|
11280
12356
|
function replaysCleanly(units, discovered) {
|
|
@@ -11291,16 +12367,16 @@ function replaysCleanly(units, discovered) {
|
|
|
11291
12367
|
return true;
|
|
11292
12368
|
}
|
|
11293
12369
|
async function extractRubyProject(options) {
|
|
11294
|
-
const timer = options.onTiming !== void 0 ? (0,
|
|
12370
|
+
const timer = options.onTiming !== void 0 ? (0, import_extractor19.createTimer)() : (0, import_extractor19.noopTimer)();
|
|
11295
12371
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
11296
12372
|
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? import_node_path4.default.join(options.projectRoot, ".suss", "cache") : null)
|
|
11297
12373
|
);
|
|
11298
|
-
const layer = (0,
|
|
12374
|
+
const layer = (0, import_extractor19.createCacheLayer)(cacheDir);
|
|
11299
12375
|
const packsDigest = `${adapterStamp.packsDigest(
|
|
11300
12376
|
options.packs.map(
|
|
11301
12377
|
(pack) => pack.version !== void 0 ? { name: pack.name, version: pack.version } : { name: pack.name }
|
|
11302
12378
|
)
|
|
11303
|
-
)}|${(0,
|
|
12379
|
+
)}|${(0, import_extractor19.extractionConfigStamp)({
|
|
11304
12380
|
gapHandling: options.gapHandling,
|
|
11305
12381
|
workspaceRoot: options.workspaceRoot,
|
|
11306
12382
|
projectRoot: options.projectRoot,
|
|
@@ -11308,7 +12384,7 @@ async function extractRubyProject(options) {
|
|
|
11308
12384
|
})}`;
|
|
11309
12385
|
const input = {
|
|
11310
12386
|
files: cacheDir === null ? [] : options.files,
|
|
11311
|
-
adapterPacksDigest: cacheDir === null ? packsDigest : (0,
|
|
12387
|
+
adapterPacksDigest: cacheDir === null ? packsDigest : (0, import_extractor19.runDigest)(packsDigest, options.packs, options.files)
|
|
11312
12388
|
};
|
|
11313
12389
|
const lookup = await timer.timeAsync(
|
|
11314
12390
|
"cache.lookup",
|
|
@@ -11363,7 +12439,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11363
12439
|
const db = new import_datalog3.Database();
|
|
11364
12440
|
const summaries = [];
|
|
11365
12441
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
11366
|
-
const tallies = (0,
|
|
12442
|
+
const tallies = (0, import_extractor12.createPackTallies)(options.packs);
|
|
11367
12443
|
const ledger = cacheDir === null ? null : new import_resolution16.DependencyLedger(options.files);
|
|
11368
12444
|
const log = ledger === null ? null : new import_resolution16.FactLog(db, ledger);
|
|
11369
12445
|
if (ledger !== null) {
|
|
@@ -11465,7 +12541,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11465
12541
|
continue;
|
|
11466
12542
|
}
|
|
11467
12543
|
discovered.add(unit.dedup);
|
|
11468
|
-
(0,
|
|
12544
|
+
(0, import_extractor12.tallyUnit)(tallies, unit.recognition);
|
|
11469
12545
|
found.push({
|
|
11470
12546
|
replayed: unit.summary ?? null,
|
|
11471
12547
|
seedKey: unit.seed?.key ?? null
|
|
@@ -11546,7 +12622,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11546
12622
|
continue;
|
|
11547
12623
|
}
|
|
11548
12624
|
discovered.add(dedup);
|
|
11549
|
-
(0,
|
|
12625
|
+
(0, import_extractor12.tallyUnit)(tallies, recognition);
|
|
11550
12626
|
found.push({ raw, seedKey, draft: units[units.length - 1] });
|
|
11551
12627
|
if (seed !== void 0 && seedKey !== null && !seedKeys.has(seedKey)) {
|
|
11552
12628
|
seedKeys.add(seedKey);
|
|
@@ -11609,7 +12685,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11609
12685
|
}
|
|
11610
12686
|
const summary = timer.time(
|
|
11611
12687
|
"summarize",
|
|
11612
|
-
() => (0,
|
|
12688
|
+
() => (0, import_extractor19.assembleSummary)(routingGapUnit(pattern, gaps), { gapHandling })
|
|
11613
12689
|
);
|
|
11614
12690
|
summary.confidence = { source: "inferred_static", level: "low" };
|
|
11615
12691
|
found.push({ summary });
|
|
@@ -11665,7 +12741,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11665
12741
|
}
|
|
11666
12742
|
const summary = timer.time(
|
|
11667
12743
|
"summarize",
|
|
11668
|
-
() => (0,
|
|
12744
|
+
() => (0, import_extractor19.assembleSummary)(raw, { gapHandling })
|
|
11669
12745
|
);
|
|
11670
12746
|
summaries.push(summary);
|
|
11671
12747
|
assembledHere.add(summary);
|
|
@@ -11683,13 +12759,13 @@ async function runRuby(options, cache, previous) {
|
|
|
11683
12759
|
}
|
|
11684
12760
|
if (gapHandling !== "silent") {
|
|
11685
12761
|
summary.gaps.push(
|
|
11686
|
-
...(reached.stopsByKey.get(key) ?? []).map(
|
|
12762
|
+
...(reached.stopsByKey.get(key) ?? []).map(import_behavioral_ir9.unfollowedCallGap)
|
|
11687
12763
|
);
|
|
11688
12764
|
}
|
|
11689
|
-
(0,
|
|
11690
|
-
(0,
|
|
11691
|
-
(0,
|
|
11692
|
-
(0,
|
|
12765
|
+
(0, import_behavioral_ir9.placeCalls)(summary, reached.targetsByKey.get(key));
|
|
12766
|
+
(0, import_behavioral_ir9.placeArgTargets)(summary, reached.argTargetsByKey.get(key));
|
|
12767
|
+
(0, import_behavioral_ir9.placeCalleeParameters)(summary, reached.parameterCallsByKey.get(key));
|
|
12768
|
+
(0, import_behavioral_ir9.placeReceiverClasses)(summary, reached.receiverClassesByKey.get(key));
|
|
11693
12769
|
}
|
|
11694
12770
|
}
|
|
11695
12771
|
if (ledger !== null) {
|
|
@@ -11698,7 +12774,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11698
12774
|
}
|
|
11699
12775
|
}
|
|
11700
12776
|
if (gapHandling !== "silent") {
|
|
11701
|
-
(0,
|
|
12777
|
+
(0, import_behavioral_ir9.recordParameterGaps)(
|
|
11702
12778
|
reached.parameterCallsByKey,
|
|
11703
12779
|
summariesBySeed,
|
|
11704
12780
|
reached.passedPositions
|
|
@@ -11711,20 +12787,20 @@ async function runRuby(options, cache, previous) {
|
|
|
11711
12787
|
throw new ReplayFailed("");
|
|
11712
12788
|
}
|
|
11713
12789
|
const dependencies = (0, import_resolution16.importedFilesByFile)(db, displayPathOf);
|
|
11714
|
-
(0,
|
|
11715
|
-
(0,
|
|
12790
|
+
(0, import_extractor19.stampModuleImports)(summaries, (file) => dependencies.get(file) ?? []);
|
|
12791
|
+
(0, import_extractor19.stampModules)(summaries, declaredModules, options.workspaceRoot);
|
|
11716
12792
|
const idRoot = options.projectRoot ?? options.workspaceRoot;
|
|
11717
12793
|
for (const summary of summaries) {
|
|
11718
12794
|
const absoluteFile = options.workspaceRoot === void 0 ? summary.location.file : import_node_path4.default.resolve(options.workspaceRoot, summary.location.file);
|
|
11719
|
-
summary.identity.id = (0,
|
|
12795
|
+
summary.identity.id = (0, import_behavioral_ir9.summaryIdFromParts)({
|
|
11720
12796
|
workspace: void 0,
|
|
11721
12797
|
file: idRoot === void 0 ? absoluteFile : import_node_path4.default.relative(idRoot, absoluteFile),
|
|
11722
12798
|
name: summary.identity.name,
|
|
11723
12799
|
exportPath: summary.identity.exportPath
|
|
11724
12800
|
});
|
|
11725
12801
|
}
|
|
11726
|
-
(0,
|
|
11727
|
-
(0,
|
|
12802
|
+
(0, import_behavioral_ir9.disambiguateSummaryIds)(summaries);
|
|
12803
|
+
(0, import_behavioral_ir9.linkCallsToSummaries)(summaries);
|
|
11728
12804
|
const composed = timer.time("summarize", () => {
|
|
11729
12805
|
markExitCodeFunctions(
|
|
11730
12806
|
summaries,
|
|
@@ -11732,7 +12808,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11732
12808
|
db,
|
|
11733
12809
|
options.workspaceRoot
|
|
11734
12810
|
);
|
|
11735
|
-
return (0,
|
|
12811
|
+
return (0, import_extractor19.composeWrappers)(summaries, { gapHandling });
|
|
11736
12812
|
});
|
|
11737
12813
|
await timer.timeAsync("cache.write", async () => {
|
|
11738
12814
|
if (cacheDir === null || composed.length === 0) {
|
|
@@ -12011,7 +13087,7 @@ var RubyWhySession = class {
|
|
|
12011
13087
|
// src/stubEvidence.ts
|
|
12012
13088
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
12013
13089
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
12014
|
-
var
|
|
13090
|
+
var import_extractor20 = require("@suss/extractor");
|
|
12015
13091
|
function bareLetters(name) {
|
|
12016
13092
|
return name.replaceAll(/[-_]/g, "").toLowerCase();
|
|
12017
13093
|
}
|
|
@@ -12035,14 +13111,14 @@ function requireTarget(node) {
|
|
|
12035
13111
|
}
|
|
12036
13112
|
function requireSitesIn(root, file) {
|
|
12037
13113
|
const found = [];
|
|
12038
|
-
(0,
|
|
13114
|
+
(0, import_extractor20.walkDescendants)(root, null, children, {
|
|
12039
13115
|
at: (node) => {
|
|
12040
13116
|
const target = requireTarget(node);
|
|
12041
13117
|
if (target !== null) {
|
|
12042
13118
|
found.push({ target, file, line: rangeOf(node).start });
|
|
12043
13119
|
}
|
|
12044
13120
|
},
|
|
12045
|
-
into: (node) => node.type === "argument_list" ?
|
|
13121
|
+
into: (node) => node.type === "argument_list" ? import_extractor20.SKIP_CHILDREN : null
|
|
12046
13122
|
});
|
|
12047
13123
|
return found;
|
|
12048
13124
|
}
|
|
@@ -12086,6 +13162,7 @@ async function rubyStubEvidence(options) {
|
|
|
12086
13162
|
bindEvaluator,
|
|
12087
13163
|
bodyStatements,
|
|
12088
13164
|
booleanLiteralValue,
|
|
13165
|
+
children,
|
|
12089
13166
|
collectFileConstants,
|
|
12090
13167
|
createConstantFileCache,
|
|
12091
13168
|
createFileCache,
|