@suss/adapter-ruby 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1995 -504
- package/dist/index.d.cts +91 -19
- package/dist/index.d.ts +91 -19
- package/dist/index.js +1919 -412
- 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
|
},
|
|
@@ -320,8 +350,8 @@ var VISIBILITY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
320
350
|
"protected",
|
|
321
351
|
"public"
|
|
322
352
|
]);
|
|
323
|
-
function visibilityKeyword(
|
|
324
|
-
return VISIBILITY_KEYWORDS.has(
|
|
353
|
+
function visibilityKeyword(text3) {
|
|
354
|
+
return VISIBILITY_KEYWORDS.has(text3) ? text3 : null;
|
|
325
355
|
}
|
|
326
356
|
function setVisibility(visibility, name, keyword) {
|
|
327
357
|
if (keyword === "public") {
|
|
@@ -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 {
|
|
@@ -546,8 +621,8 @@ function lowerAcronyms(word, acronyms) {
|
|
|
546
621
|
(_match, before, acronym) => `${before === void 0 ? "" : "_"}${acronym.toLowerCase()}`
|
|
547
622
|
);
|
|
548
623
|
}
|
|
549
|
-
function escapeRegExp(
|
|
550
|
-
return
|
|
624
|
+
function escapeRegExp(text3) {
|
|
625
|
+
return text3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
551
626
|
}
|
|
552
627
|
var PATH_CONVENTIONS = {
|
|
553
628
|
railsUnderscore: underscoreConstantPath
|
|
@@ -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,80 @@ 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
|
+
]);
|
|
778
|
+
var SENDING_METHODS = /* @__PURE__ */ new Set([
|
|
779
|
+
"send",
|
|
780
|
+
"public_send",
|
|
781
|
+
"__send__"
|
|
782
|
+
]);
|
|
783
|
+
var METHOD_REFERENCE = "method";
|
|
784
|
+
var INVOKE_METHOD = "call";
|
|
785
|
+
var BLOCK_WRAPPERS = /* @__PURE__ */ new Set(["proc", "lambda"]);
|
|
786
|
+
var PROC_CLASS = "Proc";
|
|
633
787
|
var CONSTRUCTOR = "new";
|
|
634
788
|
|
|
635
789
|
// src/facts/resolve.ts
|
|
@@ -677,7 +831,13 @@ function resolveEnvObjects(db, objects) {
|
|
|
677
831
|
}
|
|
678
832
|
function writtenValueOf(db, key) {
|
|
679
833
|
resolveValues(db, [key]);
|
|
680
|
-
return (0, import_resolution.writtenValueOf)(
|
|
834
|
+
return (0, import_resolution.writtenValueOf)(
|
|
835
|
+
db,
|
|
836
|
+
key,
|
|
837
|
+
(keys) => resolveValues(db, keys),
|
|
838
|
+
void 0,
|
|
839
|
+
(0, import_resolution.answersFromTestsLeftOut)(key, import_behavioral_ir.isTestFile)
|
|
840
|
+
);
|
|
681
841
|
}
|
|
682
842
|
function writtenValueUnder(db, key, site) {
|
|
683
843
|
const program = (0, import_resolution.resolutionUnderProgram)(RUBY_RULES);
|
|
@@ -709,7 +869,7 @@ function isFieldOf(parent, node, name) {
|
|
|
709
869
|
function namedAt(parent, node) {
|
|
710
870
|
return isFieldOf(parent, node, "name");
|
|
711
871
|
}
|
|
712
|
-
function
|
|
872
|
+
function always2() {
|
|
713
873
|
return true;
|
|
714
874
|
}
|
|
715
875
|
var SPELLS_A_NAME = {
|
|
@@ -724,14 +884,14 @@ var SPELLS_A_NAME = {
|
|
|
724
884
|
hash_splat_parameter: namedAt,
|
|
725
885
|
keyword_parameter: namedAt,
|
|
726
886
|
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,
|
|
887
|
+
destructured_parameter: always2,
|
|
888
|
+
left_assignment_list: always2,
|
|
889
|
+
rest_assignment: always2,
|
|
890
|
+
destructured_left_assignment: always2,
|
|
891
|
+
exception_variable: always2,
|
|
892
|
+
undef: always2,
|
|
893
|
+
alias: always2,
|
|
894
|
+
...Object.fromEntries(PARAMETER_LIST_TYPES.map((type) => [type, always2]))
|
|
735
895
|
};
|
|
736
896
|
function addNamesUnder(node, names) {
|
|
737
897
|
if (node === null) {
|
|
@@ -1225,6 +1385,9 @@ function add(emitter, relation, ...tuple) {
|
|
|
1225
1385
|
}
|
|
1226
1386
|
emitter.db.add(relation, tuple);
|
|
1227
1387
|
}
|
|
1388
|
+
function rowsOf(emitter) {
|
|
1389
|
+
return (relation, row) => add(emitter, relation, ...row);
|
|
1390
|
+
}
|
|
1228
1391
|
function valueKey(emitter, written, parent) {
|
|
1229
1392
|
return readKey(emitter.filePath, written, emitter.enclosing, parent);
|
|
1230
1393
|
}
|
|
@@ -1308,6 +1471,97 @@ function emitCall(emitter, site) {
|
|
|
1308
1471
|
}
|
|
1309
1472
|
emitCallArguments(emitter, site);
|
|
1310
1473
|
emitConversion(emitter, site);
|
|
1474
|
+
emitSentChoice(emitter, site);
|
|
1475
|
+
emitMethodReference(emitter, site);
|
|
1476
|
+
emitBlockAsProc(emitter, site);
|
|
1477
|
+
}
|
|
1478
|
+
function emitBlockAsProc(emitter, site) {
|
|
1479
|
+
const { method, receiver, node } = site;
|
|
1480
|
+
const name = method?.text;
|
|
1481
|
+
const wraps = receiver === null ? name !== void 0 && BLOCK_WRAPPERS.has(name) : name === CONSTRUCTOR && receiver.text === PROC_CLASS;
|
|
1482
|
+
const block = field(node, "block");
|
|
1483
|
+
if (!wraps || block === null) {
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1486
|
+
const blockKey = nodeId(emitter.filePath, block);
|
|
1487
|
+
add(emitter, "func", blockKey);
|
|
1488
|
+
add(emitter, "binds", site.key, blockKey);
|
|
1489
|
+
for (const call of callsWrittenIn(block)) {
|
|
1490
|
+
add(emitter, "makesCall", blockKey, nodeId(emitter.filePath, call));
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
function callsWrittenIn(node, found = []) {
|
|
1494
|
+
for (const child of children(node)) {
|
|
1495
|
+
if (OWN_BODY_TYPES.has(child.type)) {
|
|
1496
|
+
continue;
|
|
1497
|
+
}
|
|
1498
|
+
if (child.type === "call") {
|
|
1499
|
+
found.push(child);
|
|
1500
|
+
}
|
|
1501
|
+
callsWrittenIn(child, found);
|
|
1502
|
+
}
|
|
1503
|
+
return found;
|
|
1504
|
+
}
|
|
1505
|
+
function emitSentChoice(emitter, site) {
|
|
1506
|
+
const { method, receiver, node } = site;
|
|
1507
|
+
if (method === null || !SENDING_METHODS.has(method.text)) {
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
const objectKey = receiver === null ? emitter.selfKey : valueKey(emitter, receiver, node);
|
|
1511
|
+
const [name] = readCallArgs(field(node, "arguments")).positional;
|
|
1512
|
+
if (objectKey === null || name === void 0) {
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
add(emitter, "callsChosenEntry", site.key);
|
|
1516
|
+
const written = symbolValue(name) ?? stringLiteralValue(name);
|
|
1517
|
+
if (written !== null) {
|
|
1518
|
+
for (const spelled of namesReadAs(emitter, receiver, objectKey, written)) {
|
|
1519
|
+
add(emitter, "choosesNamedEntry", site.key, objectKey, spelled);
|
|
1520
|
+
}
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
const ends = writtenEnds(name);
|
|
1524
|
+
if (ends === null) {
|
|
1525
|
+
add(emitter, "choosesEntry", site.key, objectKey);
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
for (const start of namesReadAs(emitter, receiver, objectKey, ends.start)) {
|
|
1529
|
+
add(emitter, "choosesEntryLike", site.key, objectKey, start, ends.end);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
function writtenEnds(node) {
|
|
1533
|
+
if (node.type !== "string" && node.type !== "delimited_symbol") {
|
|
1534
|
+
return null;
|
|
1535
|
+
}
|
|
1536
|
+
const parts = children(node);
|
|
1537
|
+
const written = (part) => part.type === "string_content";
|
|
1538
|
+
const firstComputed = parts.findIndex((part) => !written(part));
|
|
1539
|
+
if (firstComputed === -1) {
|
|
1540
|
+
return null;
|
|
1541
|
+
}
|
|
1542
|
+
const lastComputed = parts.length - 1 - [...parts].reverse().findIndex((part) => !written(part));
|
|
1543
|
+
const start = parts.slice(0, firstComputed).map((part) => part.text).join("");
|
|
1544
|
+
const end = parts.slice(lastComputed + 1).map((part) => part.text).join("");
|
|
1545
|
+
return start === "" && end === "" ? null : { start, end };
|
|
1546
|
+
}
|
|
1547
|
+
function emitMethodReference(emitter, site) {
|
|
1548
|
+
const { method, receiver, node } = site;
|
|
1549
|
+
if (method?.text !== METHOD_REFERENCE || receiver !== null || emitter.selfKey === null) {
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
const [name] = readCallArgs(field(node, "arguments")).positional;
|
|
1553
|
+
const written = name === void 0 ? null : symbolValue(name) ?? stringLiteralValue(name);
|
|
1554
|
+
if (written === null) {
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
for (const spelled of namesReadAs(
|
|
1558
|
+
emitter,
|
|
1559
|
+
receiver,
|
|
1560
|
+
emitter.selfKey,
|
|
1561
|
+
written
|
|
1562
|
+
)) {
|
|
1563
|
+
add(emitter, "readsProperty", site.key, emitter.selfKey, spelled);
|
|
1564
|
+
}
|
|
1311
1565
|
}
|
|
1312
1566
|
function emitConversion(emitter, site) {
|
|
1313
1567
|
const { method, receiver, node } = site;
|
|
@@ -1381,7 +1635,6 @@ var SELF_READS = {
|
|
|
1381
1635
|
function classSpelling(name) {
|
|
1382
1636
|
return name === CONSTRUCTOR ? name : (0, import_resolution4.classMemberName)(name);
|
|
1383
1637
|
}
|
|
1384
|
-
var INVOKE_METHOD = "call";
|
|
1385
1638
|
function invokedValueOf(call) {
|
|
1386
1639
|
if (call.type !== "call") {
|
|
1387
1640
|
return null;
|
|
@@ -1427,6 +1680,7 @@ function emitArray(emitter, array) {
|
|
|
1427
1680
|
const objectKey = nodeId(emitter.filePath, array);
|
|
1428
1681
|
add(emitter, "objectValue", objectKey);
|
|
1429
1682
|
let position = 0;
|
|
1683
|
+
const entries = [];
|
|
1430
1684
|
for (const element of children(array)) {
|
|
1431
1685
|
add(
|
|
1432
1686
|
emitter,
|
|
@@ -1436,12 +1690,24 @@ function emitArray(emitter, array) {
|
|
|
1436
1690
|
valueKey(emitter, element, array)
|
|
1437
1691
|
);
|
|
1438
1692
|
position += 1;
|
|
1693
|
+
entries.push(writtenEntry(emitter, element, array));
|
|
1439
1694
|
}
|
|
1695
|
+
(0, import_resolution4.addEntryRows)(rowsOf(emitter), objectKey, entries);
|
|
1696
|
+
}
|
|
1697
|
+
var SPREAD_TYPES = /* @__PURE__ */ new Set(["splat_argument", "hash_splat_argument"]);
|
|
1698
|
+
function writtenEntry(emitter, entry, parent) {
|
|
1699
|
+
const unpacked = SPREAD_TYPES.has(entry.type) ? children(entry)[0] : void 0;
|
|
1700
|
+
return unpacked === void 0 ? { key: valueKey(emitter, entry, parent), form: import_resolution4.VALUE_ENTRY } : { key: valueKey(emitter, unpacked, entry), form: import_resolution4.SPREAD_ENTRY };
|
|
1440
1701
|
}
|
|
1441
1702
|
function emitHash(emitter, hash) {
|
|
1442
1703
|
const objectKey = nodeId(emitter.filePath, hash);
|
|
1443
1704
|
add(emitter, "objectValue", objectKey);
|
|
1705
|
+
const entries = [];
|
|
1444
1706
|
for (const pair of children(hash)) {
|
|
1707
|
+
if (SPREAD_TYPES.has(pair.type)) {
|
|
1708
|
+
entries.push(writtenEntry(emitter, pair, hash));
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1445
1711
|
if (pair.type !== "pair") {
|
|
1446
1712
|
continue;
|
|
1447
1713
|
}
|
|
@@ -1450,6 +1716,7 @@ function emitHash(emitter, hash) {
|
|
|
1450
1716
|
if (key === null || value === null) {
|
|
1451
1717
|
continue;
|
|
1452
1718
|
}
|
|
1719
|
+
entries.push(writtenEntry(emitter, value, pair));
|
|
1453
1720
|
const keyText = pairKeyText(key);
|
|
1454
1721
|
if (keyText === null) {
|
|
1455
1722
|
add(emitter, "holdsUnderKey", objectKey, valueKey(emitter, value, pair));
|
|
@@ -1463,32 +1730,66 @@ function emitHash(emitter, hash) {
|
|
|
1463
1730
|
valueKey(emitter, value, pair)
|
|
1464
1731
|
);
|
|
1465
1732
|
}
|
|
1733
|
+
(0, import_resolution4.addEntryRows)(rowsOf(emitter), objectKey, entries);
|
|
1466
1734
|
}
|
|
1467
1735
|
var BLOCK_TYPES3 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
1468
1736
|
var LOOP_METHODS = /* @__PURE__ */ new Set(["each", "each_with_index", "map"]);
|
|
1469
|
-
var
|
|
1470
|
-
function
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
}
|
|
1474
|
-
const receiver = field(call, "receiver");
|
|
1475
|
-
const method = field(call, "method");
|
|
1737
|
+
var COUNTING_LOOP = "each_with_index";
|
|
1738
|
+
function emitLoopVariables(emitter, block, call) {
|
|
1739
|
+
const receiver = call.type === "call" ? field(call, "receiver") : null;
|
|
1740
|
+
const method = receiver === null ? null : field(call, "method");
|
|
1476
1741
|
if (receiver === null || method === null || !LOOP_METHODS.has(method.text)) {
|
|
1477
|
-
return
|
|
1742
|
+
return;
|
|
1478
1743
|
}
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1744
|
+
const variables = children(field(block, "parameters")).filter(
|
|
1745
|
+
(variable) => variable.type !== "block_parameter"
|
|
1746
|
+
);
|
|
1747
|
+
const counting = method.text === COUNTING_LOOP;
|
|
1748
|
+
const [first, position] = variables;
|
|
1749
|
+
if (first === void 0 || counting && variables.length > 2) {
|
|
1750
|
+
return;
|
|
1484
1751
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1752
|
+
const taken = counting || variables.length === 1 ? elementTakenBy(first) : partsTakenBy(variables);
|
|
1753
|
+
const blockKey = nodeId(emitter.filePath, block);
|
|
1754
|
+
const over = valueKey(emitter, receiver, call);
|
|
1755
|
+
for (const variable of taken) {
|
|
1756
|
+
const key = `${blockKey}#${variable.name}`;
|
|
1757
|
+
if (variable.part === null) {
|
|
1758
|
+
add(emitter, "elementOf", key, over);
|
|
1759
|
+
continue;
|
|
1760
|
+
}
|
|
1761
|
+
add(emitter, "elementPartOf", key, over, variable.part);
|
|
1762
|
+
}
|
|
1763
|
+
const [anchor] = taken;
|
|
1764
|
+
if (counting && position?.type === "identifier" && anchor !== void 0) {
|
|
1765
|
+
add(
|
|
1766
|
+
emitter,
|
|
1767
|
+
"positionOf",
|
|
1768
|
+
`${blockKey}#${position.text}`,
|
|
1769
|
+
`${blockKey}#${anchor.name}`
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
function elementTakenBy(variable) {
|
|
1774
|
+
if (variable.type === "identifier") {
|
|
1775
|
+
return [{ name: variable.text, part: null }];
|
|
1776
|
+
}
|
|
1777
|
+
return variable.type === "destructured_parameter" ? partsTakenBy(children(variable)) : [];
|
|
1778
|
+
}
|
|
1779
|
+
function partsTakenBy(variables) {
|
|
1780
|
+
const parts = [];
|
|
1781
|
+
for (const [position, variable] of variables.entries()) {
|
|
1782
|
+
if (variable.type === "splat_parameter") {
|
|
1783
|
+
break;
|
|
1784
|
+
}
|
|
1785
|
+
if (variable.type === "identifier") {
|
|
1786
|
+
parts.push({ name: variable.text, part: String(position) });
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
return parts;
|
|
1490
1790
|
}
|
|
1491
|
-
|
|
1791
|
+
var DEFINE_METHOD_CALL = "define_method";
|
|
1792
|
+
function emitDynamicDefinition(emitter, call, type) {
|
|
1492
1793
|
if (emitter.selfKey === null || // A call inside a method runs when the method runs, not when the class loads.
|
|
1493
1794
|
emitter.enclosing !== null || type !== "call" || field(call, "receiver") !== null || field(call, "method")?.text !== DEFINE_METHOD_CALL) {
|
|
1494
1795
|
return;
|
|
@@ -1497,33 +1798,16 @@ function emitDynamicDefinition(emitter, call, type, turns) {
|
|
|
1497
1798
|
const first = args === null ? void 0 : children(args)[0];
|
|
1498
1799
|
const nameKey2 = nodeId(emitter.filePath, first ?? call);
|
|
1499
1800
|
add(emitter, "definesMethodFrom", emitter.selfKey, nameKey2);
|
|
1500
|
-
for (const turn of turns) {
|
|
1501
|
-
add(
|
|
1502
|
-
emitter,
|
|
1503
|
-
"nameTurnsOn",
|
|
1504
|
-
nameKey2,
|
|
1505
|
-
turn.element,
|
|
1506
|
-
turn.index,
|
|
1507
|
-
turn.overKey
|
|
1508
|
-
);
|
|
1509
|
-
}
|
|
1510
1801
|
}
|
|
1511
|
-
function walkExpressions(node,
|
|
1802
|
+
function walkExpressions(node, visit, nested = null) {
|
|
1512
1803
|
for (const child of children(node)) {
|
|
1513
1804
|
const type = child.type;
|
|
1514
1805
|
if (OWN_BODY_TYPES.has(type)) {
|
|
1515
1806
|
nested?.push(child);
|
|
1516
1807
|
continue;
|
|
1517
1808
|
}
|
|
1518
|
-
visit(child, type, node
|
|
1519
|
-
|
|
1520
|
-
walkExpressions(
|
|
1521
|
-
child,
|
|
1522
|
-
emitter,
|
|
1523
|
-
visit,
|
|
1524
|
-
nested,
|
|
1525
|
-
opened === null ? turns : [...turns, opened]
|
|
1526
|
-
);
|
|
1809
|
+
visit(child, type, node);
|
|
1810
|
+
walkExpressions(child, visit, nested);
|
|
1527
1811
|
}
|
|
1528
1812
|
}
|
|
1529
1813
|
var WRITTEN_KEY_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -1537,22 +1821,23 @@ function emitKeyedRead(emitter, site, container, key, keyParent) {
|
|
|
1537
1821
|
if (WRITTEN_KEY_TYPES.has(key.type)) {
|
|
1538
1822
|
return;
|
|
1539
1823
|
}
|
|
1824
|
+
const siteKey = nodeId(emitter.filePath, site);
|
|
1825
|
+
const containerKey = valueKey(emitter, container, site);
|
|
1540
1826
|
add(
|
|
1541
1827
|
emitter,
|
|
1542
1828
|
"readsKeyed",
|
|
1543
|
-
|
|
1544
|
-
|
|
1829
|
+
siteKey,
|
|
1830
|
+
containerKey,
|
|
1545
1831
|
valueKey(emitter, key, keyParent)
|
|
1546
1832
|
);
|
|
1833
|
+
add(emitter, "choosesEntry", siteKey, containerKey);
|
|
1547
1834
|
}
|
|
1548
1835
|
function emitKeyedElement(emitter, node, parent) {
|
|
1549
1836
|
const object = field(node, "object");
|
|
1550
1837
|
if (object === null || isWriteTarget(node, parent)) {
|
|
1551
1838
|
return;
|
|
1552
1839
|
}
|
|
1553
|
-
const index = node.
|
|
1554
|
-
(child) => child !== null && child.id !== object.id
|
|
1555
|
-
);
|
|
1840
|
+
const index = children(node).find((child) => child.id !== object.id);
|
|
1556
1841
|
if (index !== void 0) {
|
|
1557
1842
|
emitKeyedRead(emitter, node, object, index, node);
|
|
1558
1843
|
emitWrittenKeyRead(emitter, node, object, index);
|
|
@@ -1593,27 +1878,27 @@ function fallbackBranchesOf(node, type, enclosing) {
|
|
|
1593
1878
|
}
|
|
1594
1879
|
return [left, right].filter((side) => !raises(side, enclosing));
|
|
1595
1880
|
}
|
|
1596
|
-
var
|
|
1881
|
+
var RAISING_METHODS2 = /* @__PURE__ */ new Set(["raise", "fail"]);
|
|
1597
1882
|
function raises(written, enclosing) {
|
|
1598
1883
|
const node = readThrough(written);
|
|
1599
1884
|
if (node.type === "identifier") {
|
|
1600
|
-
return
|
|
1885
|
+
return RAISING_METHODS2.has(node.text) && isBareCall(node, enclosing);
|
|
1601
1886
|
}
|
|
1602
1887
|
if (node.type !== "call") {
|
|
1603
1888
|
return false;
|
|
1604
1889
|
}
|
|
1605
1890
|
const receiver = field(node, "receiver");
|
|
1606
|
-
return
|
|
1891
|
+
return RAISING_METHODS2.has(field(node, "method")?.text ?? "") && (receiver === null || receiver.text === "Kernel");
|
|
1607
1892
|
}
|
|
1608
1893
|
function emitExpressionFacts(emitter, node) {
|
|
1609
|
-
emitDynamicDefinition(emitter, node, node.type
|
|
1610
|
-
walkExpressions(node,
|
|
1894
|
+
emitDynamicDefinition(emitter, node, node.type);
|
|
1895
|
+
walkExpressions(node, (child, type, parent) => {
|
|
1611
1896
|
const site = callSiteAt(emitter, child, type, parent);
|
|
1612
|
-
emitExpressionFact(emitter, child, type, parent,
|
|
1897
|
+
emitExpressionFact(emitter, child, type, parent, site);
|
|
1613
1898
|
});
|
|
1614
1899
|
}
|
|
1615
|
-
function emitExpressionFact(emitter, child, type, parent,
|
|
1616
|
-
emitDynamicDefinition(emitter, child, type
|
|
1900
|
+
function emitExpressionFact(emitter, child, type, parent, site) {
|
|
1901
|
+
emitDynamicDefinition(emitter, child, type);
|
|
1617
1902
|
if (site !== null) {
|
|
1618
1903
|
emitCall(emitter, site);
|
|
1619
1904
|
emitKeyedFetch(emitter, site);
|
|
@@ -1654,6 +1939,11 @@ function emitExpressionFact(emitter, child, type, parent, turns, site) {
|
|
|
1654
1939
|
}
|
|
1655
1940
|
if (BLOCK_TYPES3.has(type)) {
|
|
1656
1941
|
emitBlockValue(emitter, child);
|
|
1942
|
+
emitLoopVariables(emitter, child, parent);
|
|
1943
|
+
}
|
|
1944
|
+
const pieces = TEMPLATE_PIECES[type]?.(emitter, child) ?? [];
|
|
1945
|
+
if (pieces.length > 0) {
|
|
1946
|
+
(0, import_resolution4.addTemplateRows)(rowsOf(emitter), nodeId(emitter.filePath, child), pieces);
|
|
1657
1947
|
}
|
|
1658
1948
|
for (const branch of BRANCHES_OF[type]?.(child) ?? []) {
|
|
1659
1949
|
add(
|
|
@@ -1673,6 +1963,29 @@ function emitExpressionFact(emitter, child, type, parent, turns, site) {
|
|
|
1673
1963
|
emitParameterDefault(emitter, child);
|
|
1674
1964
|
}
|
|
1675
1965
|
}
|
|
1966
|
+
function interpolatedPieces(emitter, string) {
|
|
1967
|
+
const parts = children(string);
|
|
1968
|
+
if (!parts.some((part) => part.type === "interpolation")) {
|
|
1969
|
+
return [];
|
|
1970
|
+
}
|
|
1971
|
+
return parts.flatMap((part) => {
|
|
1972
|
+
if (part.type === "string_content") {
|
|
1973
|
+
return [{ text: part.text }];
|
|
1974
|
+
}
|
|
1975
|
+
const expression = part.type === "interpolation" ? children(part)[0] : void 0;
|
|
1976
|
+
return expression === void 0 ? [] : [{ hole: valueKey(emitter, expression, part) }];
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
function adjacentPieces(emitter, joined2) {
|
|
1980
|
+
return children(joined2).map((part) => ({
|
|
1981
|
+
hole: valueKey(emitter, part, joined2)
|
|
1982
|
+
}));
|
|
1983
|
+
}
|
|
1984
|
+
var TEMPLATE_PIECES = {
|
|
1985
|
+
string: interpolatedPieces,
|
|
1986
|
+
delimited_symbol: interpolatedPieces,
|
|
1987
|
+
chained_string: adjacentPieces
|
|
1988
|
+
};
|
|
1676
1989
|
function emitBlockArgument(emitter, argument) {
|
|
1677
1990
|
const [handed] = children(argument);
|
|
1678
1991
|
if (handed !== void 0) {
|
|
@@ -2095,11 +2408,10 @@ function emitMethodFacts(emitter, method) {
|
|
|
2095
2408
|
const collecting = { ...inside, heldRows: expressionFacts };
|
|
2096
2409
|
walkExpressions(
|
|
2097
2410
|
body,
|
|
2098
|
-
|
|
2099
|
-
(child, type, parent, turns) => {
|
|
2411
|
+
(child, type, parent) => {
|
|
2100
2412
|
const site = callSiteAt(inside, child, type, parent);
|
|
2101
2413
|
emitBodyFact(bodyFacts, inside, funcKey, child, type, site);
|
|
2102
|
-
emitExpressionFact(collecting, child, type, parent,
|
|
2414
|
+
emitExpressionFact(collecting, child, type, parent, site);
|
|
2103
2415
|
},
|
|
2104
2416
|
nested
|
|
2105
2417
|
);
|
|
@@ -2559,9 +2871,7 @@ var EXPRESSION_TYPES = {
|
|
|
2559
2871
|
),
|
|
2560
2872
|
unary: (node) => {
|
|
2561
2873
|
const operand2 = field(node, "operand");
|
|
2562
|
-
const operator = node.
|
|
2563
|
-
(child) => child !== null && !child.isNamed
|
|
2564
|
-
);
|
|
2874
|
+
const operator = allChildren(node).find((child) => !child.isNamed);
|
|
2565
2875
|
if (operand2 === null || operator === void 0) {
|
|
2566
2876
|
return OPAQUE;
|
|
2567
2877
|
}
|
|
@@ -2763,8 +3073,25 @@ function statementOf(node) {
|
|
|
2763
3073
|
if (appending !== null) {
|
|
2764
3074
|
return appending;
|
|
2765
3075
|
}
|
|
3076
|
+
if (isRaiseCall(node) && !rescuedInSameFunction(node)) {
|
|
3077
|
+
return { kind: "throw" };
|
|
3078
|
+
}
|
|
2766
3079
|
return isTailExpression(node) ? { kind: "return", value: node } : { kind: "expression", value: node };
|
|
2767
3080
|
}
|
|
3081
|
+
var RESCUING_TYPES = /* @__PURE__ */ new Set(["begin", "body_statement"]);
|
|
3082
|
+
var UNRESCUED_PARTS = /* @__PURE__ */ new Set(["rescue", "else", "ensure"]);
|
|
3083
|
+
function rescuedInSameFunction(node) {
|
|
3084
|
+
let child = node;
|
|
3085
|
+
let parent = node.parent;
|
|
3086
|
+
while (parent !== null && !isRoot(parent)) {
|
|
3087
|
+
if (RESCUING_TYPES.has(parent.type) && !UNRESCUED_PARTS.has(child.type) && children(parent).some((part) => part.type === "rescue")) {
|
|
3088
|
+
return true;
|
|
3089
|
+
}
|
|
3090
|
+
child = parent;
|
|
3091
|
+
parent = parent.parent;
|
|
3092
|
+
}
|
|
3093
|
+
return false;
|
|
3094
|
+
}
|
|
2768
3095
|
function appendingStatement(node) {
|
|
2769
3096
|
if (node.type !== "binary" || field(node, "operator")?.text !== "<<") {
|
|
2770
3097
|
return null;
|
|
@@ -3420,6 +3747,10 @@ function writtenNodeOf(node, db, site) {
|
|
|
3420
3747
|
const context = db === void 0 ? void 0 : contexts.get(db);
|
|
3421
3748
|
return context === void 0 ? null : context.writtenTo(node, site);
|
|
3422
3749
|
}
|
|
3750
|
+
function calledDefinition(call, db) {
|
|
3751
|
+
const context = db === void 0 ? void 0 : contexts.get(db);
|
|
3752
|
+
return context === void 0 ? null : context.callable(call);
|
|
3753
|
+
}
|
|
3423
3754
|
function askWrittenValues(nodes, db) {
|
|
3424
3755
|
if (db === void 0 || !contexts.has(db)) {
|
|
3425
3756
|
return;
|
|
@@ -3482,7 +3813,7 @@ function methodDefinitionsIn(file, root) {
|
|
|
3482
3813
|
if (METHOD_TYPES.has(node.type)) {
|
|
3483
3814
|
found.set(nodeId(file, node), node);
|
|
3484
3815
|
}
|
|
3485
|
-
for (const child of node
|
|
3816
|
+
for (const child of children(node)) {
|
|
3486
3817
|
if (child !== null) {
|
|
3487
3818
|
visit(child);
|
|
3488
3819
|
}
|
|
@@ -3560,8 +3891,24 @@ function literalElementsIn(value) {
|
|
|
3560
3891
|
}
|
|
3561
3892
|
return elements;
|
|
3562
3893
|
}
|
|
3563
|
-
function
|
|
3564
|
-
|
|
3894
|
+
function loopElementsOf(node, db) {
|
|
3895
|
+
const value = evaluatedValue(node, db);
|
|
3896
|
+
if (value.kind === "sequence") {
|
|
3897
|
+
return value.items.map((item) => elementOfList((0, import_values4.force)(item.value)));
|
|
3898
|
+
}
|
|
3899
|
+
if (value.kind === "record" && !value.open) {
|
|
3900
|
+
return [...value.fields].map(([key, item]) => {
|
|
3901
|
+
const parts = [(0, import_values4.text)(key), (0, import_values4.force)(item.value)];
|
|
3902
|
+
return { whole: (0, import_values4.sequence)(parts), parts };
|
|
3903
|
+
});
|
|
3904
|
+
}
|
|
3905
|
+
return null;
|
|
3906
|
+
}
|
|
3907
|
+
function elementOfList(whole) {
|
|
3908
|
+
return {
|
|
3909
|
+
whole,
|
|
3910
|
+
parts: whole.kind === "sequence" ? whole.items.map((item) => (0, import_values4.force)(item.value)) : [whole]
|
|
3911
|
+
};
|
|
3565
3912
|
}
|
|
3566
3913
|
function namesOf(node, db) {
|
|
3567
3914
|
const value = evaluatedValue(node, db);
|
|
@@ -3583,13 +3930,16 @@ function definedNamesOf(dynamic, classKey) {
|
|
|
3583
3930
|
}
|
|
3584
3931
|
function readDynamicNames(db, rootsByFile) {
|
|
3585
3932
|
const byClass = /* @__PURE__ */ new Map();
|
|
3586
|
-
|
|
3933
|
+
const definitions = db.facts("definesMethodFrom");
|
|
3934
|
+
const loops = definitions.length === 0 ? /* @__PURE__ */ new Map() : loopsByFile(db);
|
|
3935
|
+
for (const [classKey, nameKey2] of definitions) {
|
|
3587
3936
|
const key = String(classKey);
|
|
3937
|
+
const around = loopsAround(loops, key, String(nameKey2));
|
|
3588
3938
|
byClass.set(
|
|
3589
3939
|
key,
|
|
3590
3940
|
foldReading(
|
|
3591
3941
|
byClass.get(key) ?? NOTHING,
|
|
3592
|
-
readOne(db, rootsByFile, String(nameKey2))
|
|
3942
|
+
readOne(db, rootsByFile, String(nameKey2), around)
|
|
3593
3943
|
)
|
|
3594
3944
|
);
|
|
3595
3945
|
}
|
|
@@ -3610,11 +3960,11 @@ function foldReading(soFar, reading) {
|
|
|
3610
3960
|
unreadable: soFar.unreadable
|
|
3611
3961
|
};
|
|
3612
3962
|
}
|
|
3613
|
-
function readOne(db, rootsByFile, nameKey2) {
|
|
3963
|
+
function readOne(db, rootsByFile, nameKey2, loops) {
|
|
3614
3964
|
const node = (0, import_resolution6.nodeOfKey)(rootsByFile, nameKey2);
|
|
3615
3965
|
const names = [];
|
|
3616
3966
|
const patterns = [];
|
|
3617
|
-
for (const bindings of loopTurns(db, rootsByFile,
|
|
3967
|
+
for (const bindings of loopTurns(db, rootsByFile, loops)) {
|
|
3618
3968
|
const value = node === null ? (0, import_values5.hole)(nameKey2) : evaluatedValue(node, db, bindings.size === 0 ? void 0 : bindings);
|
|
3619
3969
|
const name = (0, import_values5.literalOf)(value);
|
|
3620
3970
|
if (name !== null) {
|
|
@@ -3647,38 +3997,105 @@ function patternOf(value) {
|
|
|
3647
3997
|
}
|
|
3648
3998
|
return readSomething ? new RegExp(`${source}$`) : null;
|
|
3649
3999
|
}
|
|
3650
|
-
function escapeForPattern(
|
|
3651
|
-
return
|
|
4000
|
+
function escapeForPattern(text3) {
|
|
4001
|
+
return text3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3652
4002
|
}
|
|
3653
|
-
function loopTurns(db, rootsByFile,
|
|
4003
|
+
function loopTurns(db, rootsByFile, loops) {
|
|
3654
4004
|
let turns = [/* @__PURE__ */ new Map()];
|
|
3655
|
-
for (const
|
|
4005
|
+
for (const loop of loops) {
|
|
4006
|
+
const bindings = bindingsOf(db, rootsByFile, loop);
|
|
4007
|
+
if (bindings === null) {
|
|
4008
|
+
continue;
|
|
4009
|
+
}
|
|
3656
4010
|
turns = turns.flatMap(
|
|
3657
|
-
(base) =>
|
|
3658
|
-
const binding = new Map([...base, [over.element, value]]);
|
|
3659
|
-
if (over.index !== "") {
|
|
3660
|
-
binding.set(over.index, String(position));
|
|
3661
|
-
}
|
|
3662
|
-
return binding;
|
|
3663
|
-
})
|
|
4011
|
+
(base) => bindings.map((binding) => new Map([...base, ...binding]))
|
|
3664
4012
|
);
|
|
3665
4013
|
}
|
|
3666
4014
|
return turns;
|
|
3667
4015
|
}
|
|
3668
|
-
function
|
|
3669
|
-
const
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
)
|
|
3675
|
-
const
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
4016
|
+
function bindingsOf(db, rootsByFile, loop) {
|
|
4017
|
+
const node = collectionNode(rootsByFile, loop);
|
|
4018
|
+
const elements = node === null ? null : loopElementsOf(node, db);
|
|
4019
|
+
if (elements === null) {
|
|
4020
|
+
return null;
|
|
4021
|
+
}
|
|
4022
|
+
const bound = [...loop.variables].flatMap(([name, takes]) => {
|
|
4023
|
+
const values = elements.map(
|
|
4024
|
+
(element, position) => GIVEN[takes.kind](element, position, takes)
|
|
4025
|
+
);
|
|
4026
|
+
return values.every((value) => value !== null) ? [{ name, values }] : [];
|
|
4027
|
+
});
|
|
4028
|
+
if (bound.length === 0) {
|
|
4029
|
+
return null;
|
|
4030
|
+
}
|
|
4031
|
+
return elements.map(
|
|
4032
|
+
(_, position) => new Map(bound.map(({ name, values }) => [name, values[position] ?? ""]))
|
|
4033
|
+
);
|
|
4034
|
+
}
|
|
4035
|
+
var GIVEN = {
|
|
4036
|
+
element: (element) => (0, import_values5.literalOf)(element.whole),
|
|
4037
|
+
part: (element, _, takes) => {
|
|
4038
|
+
const part = takes.kind === "part" ? element.parts[takes.part] : void 0;
|
|
4039
|
+
return part === void 0 ? null : (0, import_values5.literalOf)(part);
|
|
4040
|
+
},
|
|
4041
|
+
position: (_, position) => String(position)
|
|
4042
|
+
};
|
|
4043
|
+
function collectionNode(rootsByFile, loop) {
|
|
4044
|
+
const written = (0, import_resolution6.nodeOfKey)(rootsByFile, loop.over);
|
|
4045
|
+
if (written !== null) {
|
|
4046
|
+
return written;
|
|
4047
|
+
}
|
|
4048
|
+
const call = (0, import_resolution6.nodeOfKey)(rootsByFile, loop.block.key)?.parent ?? null;
|
|
4049
|
+
return call === null ? null : field(call, "receiver");
|
|
4050
|
+
}
|
|
4051
|
+
function blockVariableOf(key) {
|
|
4052
|
+
const at = key.lastIndexOf("#");
|
|
4053
|
+
const span = at < 0 ? null : (0, import_resolution6.spanOfKey)(key.slice(0, at));
|
|
4054
|
+
return span === null ? null : { block: { ...span, key: key.slice(0, at) }, name: key.slice(at + 1) };
|
|
4055
|
+
}
|
|
4056
|
+
function loopsByFile(db) {
|
|
4057
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
4058
|
+
const note = (key, over, takes) => {
|
|
4059
|
+
const variable = blockVariableOf(String(key));
|
|
4060
|
+
if (variable === null) {
|
|
4061
|
+
return;
|
|
3679
4062
|
}
|
|
4063
|
+
const known = blocks.get(variable.block.key);
|
|
4064
|
+
const loop = known ?? {
|
|
4065
|
+
block: variable.block,
|
|
4066
|
+
over: String(over),
|
|
4067
|
+
variables: /* @__PURE__ */ new Map()
|
|
4068
|
+
};
|
|
4069
|
+
loop.variables.set(variable.name, takes);
|
|
4070
|
+
blocks.set(variable.block.key, loop);
|
|
4071
|
+
};
|
|
4072
|
+
for (const [element, over] of db.facts("elementOf")) {
|
|
4073
|
+
note(element, over, { kind: "element" });
|
|
3680
4074
|
}
|
|
3681
|
-
|
|
4075
|
+
for (const [element, over, part] of db.facts("elementPartOf")) {
|
|
4076
|
+
note(element, over, { kind: "part", part: Number(part) });
|
|
4077
|
+
}
|
|
4078
|
+
for (const [position, element] of db.facts("positionOf")) {
|
|
4079
|
+
const block = blockVariableOf(String(element))?.block.key;
|
|
4080
|
+
if (block !== void 0 && blocks.has(block)) {
|
|
4081
|
+
note(position, blocks.get(block)?.over, { kind: "position" });
|
|
4082
|
+
}
|
|
4083
|
+
}
|
|
4084
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
4085
|
+
for (const loop of blocks.values()) {
|
|
4086
|
+
byFile.set(loop.block.file, [...byFile.get(loop.block.file) ?? [], loop]);
|
|
4087
|
+
}
|
|
4088
|
+
return byFile;
|
|
4089
|
+
}
|
|
4090
|
+
function loopsAround(loops, classKey, nameKey2) {
|
|
4091
|
+
const cls = (0, import_resolution6.spanOfKey)(classKey);
|
|
4092
|
+
const name = (0, import_resolution6.spanOfKey)(nameKey2);
|
|
4093
|
+
if (cls === null || name === null) {
|
|
4094
|
+
return [];
|
|
4095
|
+
}
|
|
4096
|
+
return (loops.get(name.file) ?? []).filter(
|
|
4097
|
+
({ block }) => cls.start <= block.start && block.end <= cls.end && block.start <= name.start && name.end <= block.end
|
|
4098
|
+
).sort((a, b) => a.block.start - b.block.start);
|
|
3682
4099
|
}
|
|
3683
4100
|
|
|
3684
4101
|
// src/scope.ts
|
|
@@ -3808,12 +4225,27 @@ function graphqlTypeNameFromQualified(qualifiedName, convention) {
|
|
|
3808
4225
|
|
|
3809
4226
|
// src/ancestry.ts
|
|
3810
4227
|
async function reachDefinition(qualifiedName, lookup) {
|
|
4228
|
+
const segments = qualifiedName.split("::");
|
|
4229
|
+
for (let length = segments.length; length > 0; length--) {
|
|
4230
|
+
const found = await definedInFileOf(
|
|
4231
|
+
segments.slice(0, length).join("::"),
|
|
4232
|
+
qualifiedName,
|
|
4233
|
+
lookup
|
|
4234
|
+
);
|
|
4235
|
+
if (found !== null) {
|
|
4236
|
+
return found;
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
return null;
|
|
4240
|
+
}
|
|
4241
|
+
async function definedInFileOf(fileConstant, qualifiedName, lookup) {
|
|
3811
4242
|
const filePath = resolveConstantFile(
|
|
3812
4243
|
lookup.root,
|
|
3813
|
-
|
|
4244
|
+
fileConstant,
|
|
3814
4245
|
lookup.pathConvention,
|
|
3815
4246
|
lookup.acronyms,
|
|
3816
|
-
lookup.constantFiles
|
|
4247
|
+
lookup.constantFiles,
|
|
4248
|
+
lookup.autoloadRoots
|
|
3817
4249
|
);
|
|
3818
4250
|
if (filePath === null) {
|
|
3819
4251
|
return null;
|
|
@@ -3958,7 +4390,7 @@ function superclassCandidatesOf(blocks) {
|
|
|
3958
4390
|
return [];
|
|
3959
4391
|
}
|
|
3960
4392
|
function methodInAncestry(ancestry, name, read = {}) {
|
|
3961
|
-
for (const entry of ancestry) {
|
|
4393
|
+
for (const [index, entry] of ancestry.entries()) {
|
|
3962
4394
|
if (entry.type === "root") {
|
|
3963
4395
|
return { type: "none" };
|
|
3964
4396
|
}
|
|
@@ -3966,7 +4398,8 @@ function methodInAncestry(ancestry, name, read = {}) {
|
|
|
3966
4398
|
return {
|
|
3967
4399
|
type: "unsettled",
|
|
3968
4400
|
reason: `inherited from ${entry.name}, which this run did not read`,
|
|
3969
|
-
cause: "unreadAncestor"
|
|
4401
|
+
cause: "unreadAncestor",
|
|
4402
|
+
definedLater: definedInProjectAfter(ancestry, index, name, read)
|
|
3970
4403
|
};
|
|
3971
4404
|
}
|
|
3972
4405
|
const found = definitionIn(entry.blocks, name, read);
|
|
@@ -3983,6 +4416,18 @@ function methodInAncestry(ancestry, name, read = {}) {
|
|
|
3983
4416
|
}
|
|
3984
4417
|
return { type: "none" };
|
|
3985
4418
|
}
|
|
4419
|
+
function definedInProjectAfter(ancestry, index, name, read) {
|
|
4420
|
+
return ancestry.slice(index + 1).some(
|
|
4421
|
+
(entry) => entry.type !== "root" && entry.type !== "unfollowed" && definitionIn(entry.blocks, name, read).method !== null
|
|
4422
|
+
);
|
|
4423
|
+
}
|
|
4424
|
+
function methodPastUnreadAncestors(ancestry, name, read = {}) {
|
|
4425
|
+
return methodInAncestry(
|
|
4426
|
+
ancestry.filter((entry) => entry.type !== "unfollowed"),
|
|
4427
|
+
name,
|
|
4428
|
+
read
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
3986
4431
|
function definitionIn(blocks, name, read) {
|
|
3987
4432
|
let method = null;
|
|
3988
4433
|
let block = null;
|
|
@@ -4027,12 +4472,12 @@ function inheritedStatements(ancestry, blockConfigures) {
|
|
|
4027
4472
|
}
|
|
4028
4473
|
|
|
4029
4474
|
// src/discovery.ts
|
|
4030
|
-
var
|
|
4031
|
-
var
|
|
4475
|
+
var import_behavioral_ir6 = require("@suss/behavioral-ir");
|
|
4476
|
+
var import_extractor11 = require("@suss/extractor");
|
|
4032
4477
|
|
|
4033
4478
|
// src/clientCalls.ts
|
|
4034
|
-
var
|
|
4035
|
-
var
|
|
4479
|
+
var import_behavioral_ir2 = require("@suss/behavioral-ir");
|
|
4480
|
+
var import_values14 = require("@suss/values");
|
|
4036
4481
|
|
|
4037
4482
|
// src/paths/effects.ts
|
|
4038
4483
|
var import_extractor2 = require("@suss/extractor");
|
|
@@ -4059,7 +4504,7 @@ function isRaise(node) {
|
|
|
4059
4504
|
return false;
|
|
4060
4505
|
}
|
|
4061
4506
|
const receiver = field(node, "receiver");
|
|
4062
|
-
const method = field(node, "method") ?? node.
|
|
4507
|
+
const method = field(node, "method") ?? node.namedChild(0) ?? null;
|
|
4063
4508
|
return receiver === null && method !== null && RAISE_NAMES.has(method.text);
|
|
4064
4509
|
}
|
|
4065
4510
|
function exitOf(node) {
|
|
@@ -4071,7 +4516,7 @@ function exitOf(node) {
|
|
|
4071
4516
|
function exitKindOf(node) {
|
|
4072
4517
|
let sawReturn = false;
|
|
4073
4518
|
const raises2 = (current) => {
|
|
4074
|
-
for (const child of current
|
|
4519
|
+
for (const child of children(current)) {
|
|
4075
4520
|
if (child === null || CAPTURES_RETURN.has(child.type)) {
|
|
4076
4521
|
continue;
|
|
4077
4522
|
}
|
|
@@ -4105,13 +4550,52 @@ function callHeaderOf(call, block) {
|
|
|
4105
4550
|
function blockStatements(block) {
|
|
4106
4551
|
return block === null ? [] : children(block);
|
|
4107
4552
|
}
|
|
4553
|
+
function attachedBlockOf(call) {
|
|
4554
|
+
return children(call).find(
|
|
4555
|
+
(child) => child !== null && (child.type === "do_block" || child.type === "block")
|
|
4556
|
+
) ?? null;
|
|
4557
|
+
}
|
|
4558
|
+
function soleBlockParameter(block) {
|
|
4559
|
+
const names = children(field(block, "parameters")).filter(
|
|
4560
|
+
(child) => child.type === "identifier"
|
|
4561
|
+
);
|
|
4562
|
+
return names.length === 1 ? names[0].text : null;
|
|
4563
|
+
}
|
|
4564
|
+
function blockBodyStatements(block) {
|
|
4565
|
+
const body = field(block, "body");
|
|
4566
|
+
if (body !== null) {
|
|
4567
|
+
return children(body);
|
|
4568
|
+
}
|
|
4569
|
+
return children(block).filter((child) => child.type !== "block_parameters");
|
|
4570
|
+
}
|
|
4571
|
+
function armBody(block) {
|
|
4572
|
+
return field(block, "body") ?? block;
|
|
4573
|
+
}
|
|
4574
|
+
function formatArmOf(statement, parameter) {
|
|
4575
|
+
if (statement.type !== "call") {
|
|
4576
|
+
return null;
|
|
4577
|
+
}
|
|
4578
|
+
const receiver = field(statement, "receiver");
|
|
4579
|
+
const format = field(statement, "method")?.text;
|
|
4580
|
+
if (receiver?.text !== parameter || format === void 0) {
|
|
4581
|
+
return null;
|
|
4582
|
+
}
|
|
4583
|
+
const block = attachedBlockOf(statement);
|
|
4584
|
+
return {
|
|
4585
|
+
format,
|
|
4586
|
+
header: block === null ? statement.text : callHeaderOf(statement, block).sourceText,
|
|
4587
|
+
block
|
|
4588
|
+
};
|
|
4589
|
+
}
|
|
4108
4590
|
var Lowerer = class {
|
|
4109
|
-
constructor(terminals, responseCalls) {
|
|
4591
|
+
constructor(terminals, responseCalls, formatSwitch) {
|
|
4110
4592
|
this.terminals = terminals;
|
|
4111
4593
|
this.responseCalls = responseCalls;
|
|
4594
|
+
this.formatSwitch = formatSwitch;
|
|
4112
4595
|
}
|
|
4113
4596
|
terminals;
|
|
4114
4597
|
responseCalls;
|
|
4598
|
+
formatSwitch;
|
|
4115
4599
|
terminalsByStmt = /* @__PURE__ */ new Map();
|
|
4116
4600
|
terminalHome = new NodeMap();
|
|
4117
4601
|
attachTerminals(statement, found) {
|
|
@@ -4142,7 +4626,7 @@ var Lowerer = class {
|
|
|
4142
4626
|
found.push(own);
|
|
4143
4627
|
return found;
|
|
4144
4628
|
}
|
|
4145
|
-
for (const child of node
|
|
4629
|
+
for (const child of children(node)) {
|
|
4146
4630
|
if (child !== null && !OWN_BODY_TYPES.has(child.type)) {
|
|
4147
4631
|
this.responsesIn(child, found);
|
|
4148
4632
|
}
|
|
@@ -4201,29 +4685,22 @@ var Lowerer = class {
|
|
|
4201
4685
|
};
|
|
4202
4686
|
}
|
|
4203
4687
|
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(
|
|
4688
|
+
const rescues2 = children(node).filter((child) => child.type === "rescue");
|
|
4689
|
+
const ensureClause = children(node).find((child) => child.type === "ensure") ?? null;
|
|
4690
|
+
const tryBody = children(node).filter(
|
|
4211
4691
|
(child) => child !== null && child.type !== "rescue" && child.type !== "ensure" && child.type !== "else"
|
|
4212
4692
|
);
|
|
4213
4693
|
return {
|
|
4214
4694
|
kind: "try",
|
|
4215
4695
|
tryBody: tryBody.map((statement) => this.lower(statement)),
|
|
4216
|
-
catchBody:
|
|
4696
|
+
catchBody: rescues2.length > 0 ? rescues2.flatMap((clause) => this.lowerBlock(field(clause, "body"))) : null,
|
|
4217
4697
|
finallyBody: ensureClause === null ? null : this.lowerBlock(ensureClause),
|
|
4218
4698
|
exitKind: exitKindOf(node)
|
|
4219
4699
|
};
|
|
4220
4700
|
}
|
|
4221
4701
|
lowerCase(node) {
|
|
4222
4702
|
const groups = [];
|
|
4223
|
-
for (const child of node
|
|
4224
|
-
if (child === null) {
|
|
4225
|
-
continue;
|
|
4226
|
-
}
|
|
4703
|
+
for (const child of children(node)) {
|
|
4227
4704
|
if (child.type === "when") {
|
|
4228
4705
|
groups.push({
|
|
4229
4706
|
condition: handleOf(field(child, "pattern")),
|
|
@@ -4241,6 +4718,47 @@ var Lowerer = class {
|
|
|
4241
4718
|
}
|
|
4242
4719
|
return { kind: "switch", groups, exitKind: exitKindOf(node) };
|
|
4243
4720
|
}
|
|
4721
|
+
/**
|
|
4722
|
+
* `respond_to do |format| ... end` runs one arm per request, picked by
|
|
4723
|
+
* the format the request accepts, so it lowers to a switch with an arm
|
|
4724
|
+
* per `format.x`. The arm that accepts every format is the default.
|
|
4725
|
+
* Without one, a request no arm accepts makes the library raise. Null
|
|
4726
|
+
* when the block contains anything besides those arms.
|
|
4727
|
+
*/
|
|
4728
|
+
lowerFormatSwitch(node, block) {
|
|
4729
|
+
const declared = this.formatSwitch;
|
|
4730
|
+
if (declared === void 0 || node.type !== "call" || field(node, "receiver") !== null || field(node, "method")?.text !== declared.name) {
|
|
4731
|
+
return null;
|
|
4732
|
+
}
|
|
4733
|
+
const parameter = soleBlockParameter(block);
|
|
4734
|
+
if (parameter === null) {
|
|
4735
|
+
return null;
|
|
4736
|
+
}
|
|
4737
|
+
const arms = blockBodyStatements(block).map(
|
|
4738
|
+
(statement) => formatArmOf(statement, parameter)
|
|
4739
|
+
);
|
|
4740
|
+
if (arms.length === 0 || arms.some((arm) => arm === null)) {
|
|
4741
|
+
return null;
|
|
4742
|
+
}
|
|
4743
|
+
const groups = arms.map(
|
|
4744
|
+
(arm) => ({
|
|
4745
|
+
condition: arm.format === declared.matchesEvery ? null : { sourceText: arm.header, expression: null },
|
|
4746
|
+
hasTrailingBreak: true,
|
|
4747
|
+
body: arm.block === null ? [] : this.lowerBlock(armBody(arm.block))
|
|
4748
|
+
})
|
|
4749
|
+
);
|
|
4750
|
+
const named2 = groups.filter((group) => group.condition !== null);
|
|
4751
|
+
const fallback2 = groups.find((group) => group.condition === null) ?? {
|
|
4752
|
+
condition: null,
|
|
4753
|
+
hasTrailingBreak: true,
|
|
4754
|
+
body: [{ kind: "exit", exit: "throw", exitKind: "throw" }]
|
|
4755
|
+
};
|
|
4756
|
+
return {
|
|
4757
|
+
kind: "switch",
|
|
4758
|
+
groups: [...named2, fallback2],
|
|
4759
|
+
exitKind: exitKindOf(node)
|
|
4760
|
+
};
|
|
4761
|
+
}
|
|
4244
4762
|
lower(node) {
|
|
4245
4763
|
const exit = exitOf(node);
|
|
4246
4764
|
if (exit !== null) {
|
|
@@ -4270,10 +4788,12 @@ var Lowerer = class {
|
|
|
4270
4788
|
[header]
|
|
4271
4789
|
);
|
|
4272
4790
|
}
|
|
4273
|
-
const attachedBlock = node
|
|
4274
|
-
|
|
4275
|
-
)
|
|
4276
|
-
|
|
4791
|
+
const attachedBlock = attachedBlockOf(node);
|
|
4792
|
+
const formatSwitch = attachedBlock === null ? null : this.lowerFormatSwitch(node, attachedBlock);
|
|
4793
|
+
if (formatSwitch !== null) {
|
|
4794
|
+
return this.attach(formatSwitch, [node]);
|
|
4795
|
+
}
|
|
4796
|
+
if (node.type === "call" && attachedBlock !== null) {
|
|
4277
4797
|
return this.attach(
|
|
4278
4798
|
{
|
|
4279
4799
|
kind: "loop",
|
|
@@ -4300,10 +4820,11 @@ var Lowerer = class {
|
|
|
4300
4820
|
return this.attach({ kind: "opaque", exitKind: exitKindOf(node) }, [node]);
|
|
4301
4821
|
}
|
|
4302
4822
|
};
|
|
4303
|
-
function lowerRubyBody(body, terminals, responseCalls = []) {
|
|
4823
|
+
function lowerRubyBody(body, terminals, responseCalls = [], formatSwitch) {
|
|
4304
4824
|
const lowerer = new Lowerer(
|
|
4305
4825
|
new Map(terminals.map((terminal) => [terminal.id, terminal])),
|
|
4306
|
-
new NodeSet(responseCalls)
|
|
4826
|
+
new NodeSet(responseCalls),
|
|
4827
|
+
formatSwitch
|
|
4307
4828
|
);
|
|
4308
4829
|
return {
|
|
4309
4830
|
statements: lowerer.lowerBlock(body),
|
|
@@ -4323,9 +4844,9 @@ var BLOCK_TYPES5 = /* @__PURE__ */ new Set([
|
|
|
4323
4844
|
]);
|
|
4324
4845
|
function literalArgOf(node, facts) {
|
|
4325
4846
|
const value = evaluatedValue(node, facts);
|
|
4326
|
-
const
|
|
4327
|
-
if (
|
|
4328
|
-
return { kind: "string", value:
|
|
4847
|
+
const text3 = (0, import_values7.literalOf)(value);
|
|
4848
|
+
if (text3 !== null) {
|
|
4849
|
+
return { kind: "string", value: text3 };
|
|
4329
4850
|
}
|
|
4330
4851
|
const constant2 = (0, import_values7.constantOf)(value);
|
|
4331
4852
|
if (typeof constant2 === "number") {
|
|
@@ -4391,7 +4912,7 @@ function isCall(node, locals, inherited) {
|
|
|
4391
4912
|
}
|
|
4392
4913
|
function collectCalls(node, read, inherited, found) {
|
|
4393
4914
|
for (const child of children(node)) {
|
|
4394
|
-
if (read.stops.has(child.type)) {
|
|
4915
|
+
if (read.stops.has(child.type) && !isLambdaArgument(child)) {
|
|
4395
4916
|
continue;
|
|
4396
4917
|
}
|
|
4397
4918
|
if (isCall(child, read.locals, inherited)) {
|
|
@@ -4401,6 +4922,9 @@ function collectCalls(node, read, inherited, found) {
|
|
|
4401
4922
|
}
|
|
4402
4923
|
return found;
|
|
4403
4924
|
}
|
|
4925
|
+
function isLambdaArgument(node) {
|
|
4926
|
+
return node.type === LAMBDA_TYPE && node.parent?.type === "argument_list";
|
|
4927
|
+
}
|
|
4404
4928
|
function methodBody(definitionNode) {
|
|
4405
4929
|
const body = field(definitionNode, "body");
|
|
4406
4930
|
if (body === null) {
|
|
@@ -4464,6 +4988,14 @@ function enclosingStatement(call, body) {
|
|
|
4464
4988
|
return current;
|
|
4465
4989
|
}
|
|
4466
4990
|
function invocationEffects(definitionNode, inherited = NO_INHERITED_METHODS, keepsArglessCall = NO_ARGLESS_CALLS, facts) {
|
|
4991
|
+
return invocationSites(
|
|
4992
|
+
definitionNode,
|
|
4993
|
+
inherited,
|
|
4994
|
+
keepsArglessCall,
|
|
4995
|
+
facts
|
|
4996
|
+
).map((site) => site.effect);
|
|
4997
|
+
}
|
|
4998
|
+
function invocationSites(definitionNode, inherited = NO_INHERITED_METHODS, keepsArglessCall = NO_ARGLESS_CALLS, facts) {
|
|
4467
4999
|
const read = methodBody(definitionNode);
|
|
4468
5000
|
if (read === null) {
|
|
4469
5001
|
return [];
|
|
@@ -4476,7 +5008,7 @@ function moduleScopeInvocationEffects(root, inherited = NO_INHERITED_METHODS, ke
|
|
|
4476
5008
|
inherited,
|
|
4477
5009
|
keepsArglessCall,
|
|
4478
5010
|
facts
|
|
4479
|
-
);
|
|
5011
|
+
).map((site) => site.effect);
|
|
4480
5012
|
}
|
|
4481
5013
|
function effectsOfBody(read, inherited, keepsArglessCall, facts) {
|
|
4482
5014
|
const body = read.body;
|
|
@@ -4510,19 +5042,18 @@ function effectsOfBody(read, inherited, keepsArglessCall, facts) {
|
|
|
4510
5042
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement)
|
|
4511
5043
|
);
|
|
4512
5044
|
return {
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
5045
|
+
call,
|
|
5046
|
+
effect: {
|
|
5047
|
+
type: "invocation",
|
|
5048
|
+
callee: calleeText(call),
|
|
5049
|
+
args: argsOf(call, facts),
|
|
5050
|
+
async: false,
|
|
5051
|
+
...conditions.length > 0 ? { preconditions: conditions } : {}
|
|
5052
|
+
}
|
|
4518
5053
|
};
|
|
4519
5054
|
});
|
|
4520
5055
|
}
|
|
4521
5056
|
|
|
4522
|
-
// src/responseStatus.ts
|
|
4523
|
-
var import_extractor4 = require("@suss/extractor");
|
|
4524
|
-
var import_values12 = require("@suss/values");
|
|
4525
|
-
|
|
4526
5057
|
// src/paths/predicates.ts
|
|
4527
5058
|
var OPERATORS = {
|
|
4528
5059
|
"==": "eq",
|
|
@@ -4541,11 +5072,11 @@ var opaqueOf = (node) => ({
|
|
|
4541
5072
|
var JOINING = /* @__PURE__ */ new Set(["&&", "||", "and", "or"]);
|
|
4542
5073
|
function predicateOf(node, inputs) {
|
|
4543
5074
|
if (node.type === "parenthesized_statements") {
|
|
4544
|
-
const inner = node.
|
|
5075
|
+
const inner = node.namedChild(0);
|
|
4545
5076
|
return inner == null ? opaqueOf(node) : predicateOf(inner, inputs);
|
|
4546
5077
|
}
|
|
4547
5078
|
if (node.type === "unary" && field(node, "operator")?.text === "!") {
|
|
4548
|
-
const operand2 = field(node, "operand") ?? node.
|
|
5079
|
+
const operand2 = field(node, "operand") ?? node.namedChild(0);
|
|
4549
5080
|
return operand2 == null ? opaqueOf(node) : { type: "negation", operand: predicateOf(operand2, inputs) };
|
|
4550
5081
|
}
|
|
4551
5082
|
if (node.type === "binary") {
|
|
@@ -4571,11 +5102,11 @@ function predicateOf(node, inputs) {
|
|
|
4571
5102
|
}
|
|
4572
5103
|
function operandsOf(node) {
|
|
4573
5104
|
if (node.type === "parenthesized_statements") {
|
|
4574
|
-
const inner = node.
|
|
5105
|
+
const inner = node.namedChild(0);
|
|
4575
5106
|
return inner == null ? [] : operandsOf(inner);
|
|
4576
5107
|
}
|
|
4577
5108
|
if (node.type === "unary" && field(node, "operator")?.text === "!") {
|
|
4578
|
-
const operand2 = field(node, "operand") ?? node.
|
|
5109
|
+
const operand2 = field(node, "operand") ?? node.namedChild(0);
|
|
4579
5110
|
return operand2 == null ? [] : operandsOf(operand2);
|
|
4580
5111
|
}
|
|
4581
5112
|
if (node.type === "binary") {
|
|
@@ -4671,8 +5202,317 @@ function calledMethod(node) {
|
|
|
4671
5202
|
return field(node, "method")?.text ?? null;
|
|
4672
5203
|
}
|
|
4673
5204
|
|
|
4674
|
-
// src/
|
|
5205
|
+
// src/responseHandOff.ts
|
|
4675
5206
|
var import_extractor3 = require("@suss/extractor");
|
|
5207
|
+
|
|
5208
|
+
// src/exceptionClasses.ts
|
|
5209
|
+
var ROOT_EXCEPTION = "Exception";
|
|
5210
|
+
var RUBY_EXCEPTION_PARENTS = {
|
|
5211
|
+
NoMemoryError: ROOT_EXCEPTION,
|
|
5212
|
+
ScriptError: ROOT_EXCEPTION,
|
|
5213
|
+
LoadError: "ScriptError",
|
|
5214
|
+
NotImplementedError: "ScriptError",
|
|
5215
|
+
SyntaxError: "ScriptError",
|
|
5216
|
+
SecurityError: ROOT_EXCEPTION,
|
|
5217
|
+
SignalException: ROOT_EXCEPTION,
|
|
5218
|
+
Interrupt: "SignalException",
|
|
5219
|
+
StandardError: ROOT_EXCEPTION,
|
|
5220
|
+
SystemExit: ROOT_EXCEPTION,
|
|
5221
|
+
SystemStackError: ROOT_EXCEPTION,
|
|
5222
|
+
ArgumentError: "StandardError",
|
|
5223
|
+
UncaughtThrowError: "ArgumentError",
|
|
5224
|
+
EncodingError: "StandardError",
|
|
5225
|
+
FiberError: "StandardError",
|
|
5226
|
+
IOError: "StandardError",
|
|
5227
|
+
EOFError: "IOError",
|
|
5228
|
+
IndexError: "StandardError",
|
|
5229
|
+
KeyError: "IndexError",
|
|
5230
|
+
StopIteration: "IndexError",
|
|
5231
|
+
ClosedQueueError: "StopIteration",
|
|
5232
|
+
LocalJumpError: "StandardError",
|
|
5233
|
+
NameError: "StandardError",
|
|
5234
|
+
NoMethodError: "NameError",
|
|
5235
|
+
RangeError: "StandardError",
|
|
5236
|
+
FloatDomainError: "RangeError",
|
|
5237
|
+
RegexpError: "StandardError",
|
|
5238
|
+
RuntimeError: "StandardError",
|
|
5239
|
+
FrozenError: "RuntimeError",
|
|
5240
|
+
SystemCallError: "StandardError",
|
|
5241
|
+
ThreadError: "StandardError",
|
|
5242
|
+
TypeError: "StandardError",
|
|
5243
|
+
ZeroDivisionError: "StandardError"
|
|
5244
|
+
};
|
|
5245
|
+
var MESSAGE_ONLY_EXCEPTION = "RuntimeError";
|
|
5246
|
+
var ExceptionReader = class {
|
|
5247
|
+
constructor(lookup, library) {
|
|
5248
|
+
this.library = library;
|
|
5249
|
+
this.walking = {
|
|
5250
|
+
...lookup,
|
|
5251
|
+
ancestryRootClassNames: [
|
|
5252
|
+
...Object.keys(library),
|
|
5253
|
+
...Object.keys(RUBY_EXCEPTION_PARENTS),
|
|
5254
|
+
ROOT_EXCEPTION
|
|
5255
|
+
]
|
|
5256
|
+
};
|
|
5257
|
+
}
|
|
5258
|
+
library;
|
|
5259
|
+
walking;
|
|
5260
|
+
known = /* @__PURE__ */ new Map();
|
|
5261
|
+
read(ref) {
|
|
5262
|
+
const key = [ref.text, ...ref.candidates].join("\0");
|
|
5263
|
+
let found = this.known.get(key);
|
|
5264
|
+
if (found === void 0) {
|
|
5265
|
+
found = readException(ref, this.walking, this.library);
|
|
5266
|
+
this.known.set(key, found);
|
|
5267
|
+
}
|
|
5268
|
+
return found;
|
|
5269
|
+
}
|
|
5270
|
+
};
|
|
5271
|
+
function listedException(name, library) {
|
|
5272
|
+
const fromLibrary = library[name];
|
|
5273
|
+
if (fromLibrary !== void 0) {
|
|
5274
|
+
return {
|
|
5275
|
+
name,
|
|
5276
|
+
ancestors: fromLibrary.ancestors,
|
|
5277
|
+
incomplete: false,
|
|
5278
|
+
inheritableByUnread: false
|
|
5279
|
+
};
|
|
5280
|
+
}
|
|
5281
|
+
const fromRuby = rubyAncestors(name);
|
|
5282
|
+
return fromRuby === null ? null : {
|
|
5283
|
+
name,
|
|
5284
|
+
ancestors: fromRuby,
|
|
5285
|
+
incomplete: false,
|
|
5286
|
+
inheritableByUnread: true
|
|
5287
|
+
};
|
|
5288
|
+
}
|
|
5289
|
+
function unreadException(name) {
|
|
5290
|
+
return {
|
|
5291
|
+
name,
|
|
5292
|
+
ancestors: [ROOT_EXCEPTION],
|
|
5293
|
+
incomplete: true,
|
|
5294
|
+
inheritableByUnread: true
|
|
5295
|
+
};
|
|
5296
|
+
}
|
|
5297
|
+
function classesOf(exception) {
|
|
5298
|
+
return [exception.name, ...exception.ancestors];
|
|
5299
|
+
}
|
|
5300
|
+
async function readException(ref, lookup, library) {
|
|
5301
|
+
for (const candidate of ref.candidates) {
|
|
5302
|
+
const known = listedException(candidate, library);
|
|
5303
|
+
if (known !== null) {
|
|
5304
|
+
return known;
|
|
5305
|
+
}
|
|
5306
|
+
const defined = await reachConstant([candidate], lookup);
|
|
5307
|
+
if (defined !== null) {
|
|
5308
|
+
return projectException(defined, lookup, library);
|
|
5309
|
+
}
|
|
5310
|
+
}
|
|
5311
|
+
return unreadException(ref.candidates.at(-1) ?? ref.text);
|
|
5312
|
+
}
|
|
5313
|
+
async function projectException(defined, lookup, library) {
|
|
5314
|
+
const chain = await ancestryOf(defined.name, defined.blocks, lookup);
|
|
5315
|
+
const ancestors = [];
|
|
5316
|
+
let incomplete = false;
|
|
5317
|
+
for (const entry of chain) {
|
|
5318
|
+
if (entry.type === "bodies" && entry.name === defined.name) {
|
|
5319
|
+
continue;
|
|
5320
|
+
}
|
|
5321
|
+
ancestors.push(entry.name);
|
|
5322
|
+
if (entry.type === "root") {
|
|
5323
|
+
ancestors.push(
|
|
5324
|
+
...listedException(entry.name, library)?.ancestors ?? []
|
|
5325
|
+
);
|
|
5326
|
+
}
|
|
5327
|
+
if (entry.type === "unfollowed") {
|
|
5328
|
+
incomplete = true;
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5331
|
+
if (incomplete && !ancestors.includes(ROOT_EXCEPTION)) {
|
|
5332
|
+
ancestors.push(ROOT_EXCEPTION);
|
|
5333
|
+
}
|
|
5334
|
+
return {
|
|
5335
|
+
name: defined.name,
|
|
5336
|
+
ancestors,
|
|
5337
|
+
incomplete,
|
|
5338
|
+
inheritableByUnread: false
|
|
5339
|
+
};
|
|
5340
|
+
}
|
|
5341
|
+
function rubyAncestors(name) {
|
|
5342
|
+
if (name === ROOT_EXCEPTION) {
|
|
5343
|
+
return [];
|
|
5344
|
+
}
|
|
5345
|
+
if (RUBY_EXCEPTION_PARENTS[name] === void 0) {
|
|
5346
|
+
return null;
|
|
5347
|
+
}
|
|
5348
|
+
const ancestors = [];
|
|
5349
|
+
for (let parent = RUBY_EXCEPTION_PARENTS[name]; parent !== void 0; parent = RUBY_EXCEPTION_PARENTS[parent]) {
|
|
5350
|
+
ancestors.push(parent);
|
|
5351
|
+
}
|
|
5352
|
+
return ancestors;
|
|
5353
|
+
}
|
|
5354
|
+
|
|
5355
|
+
// src/raises.ts
|
|
5356
|
+
var RESCUING_BODIES = /* @__PURE__ */ new Set(["begin", "body_statement"]);
|
|
5357
|
+
var AFTER_CATCH = /* @__PURE__ */ new Set(["rescue", "else", "ensure"]);
|
|
5358
|
+
function escapingRaises(method) {
|
|
5359
|
+
const body = field(method, "body");
|
|
5360
|
+
if (body === null) {
|
|
5361
|
+
return [];
|
|
5362
|
+
}
|
|
5363
|
+
const found = [];
|
|
5364
|
+
const visit = (node) => {
|
|
5365
|
+
for (const child of children(node)) {
|
|
5366
|
+
if (child === null || OWN_BODY_TYPES.has(child.type)) {
|
|
5367
|
+
continue;
|
|
5368
|
+
}
|
|
5369
|
+
if (isRaise(child) && !caughtLocally(child, method)) {
|
|
5370
|
+
found.push(child);
|
|
5371
|
+
continue;
|
|
5372
|
+
}
|
|
5373
|
+
visit(child);
|
|
5374
|
+
}
|
|
5375
|
+
};
|
|
5376
|
+
visit(body);
|
|
5377
|
+
return found;
|
|
5378
|
+
}
|
|
5379
|
+
function caughtLocally(raise, method) {
|
|
5380
|
+
let child = raise;
|
|
5381
|
+
for (let parent = raise.parent; parent !== null && parent.id !== method.id; parent = parent.parent) {
|
|
5382
|
+
if (rescues(parent, child)) {
|
|
5383
|
+
return true;
|
|
5384
|
+
}
|
|
5385
|
+
child = parent;
|
|
5386
|
+
}
|
|
5387
|
+
return false;
|
|
5388
|
+
}
|
|
5389
|
+
function rescues(parent, child) {
|
|
5390
|
+
if (parent.type === "rescue_modifier") {
|
|
5391
|
+
return field(parent, "body")?.id === child.id;
|
|
5392
|
+
}
|
|
5393
|
+
return RESCUING_BODIES.has(parent.type) && !AFTER_CATCH.has(child.type) && children(parent).some((one) => one?.type === "rescue");
|
|
5394
|
+
}
|
|
5395
|
+
function raisedClassRef(call, nesting) {
|
|
5396
|
+
const first = readCallArgs(field(call, "arguments")).positional[0];
|
|
5397
|
+
if (first === void 0) {
|
|
5398
|
+
return null;
|
|
5399
|
+
}
|
|
5400
|
+
if (first.type === "string") {
|
|
5401
|
+
return {
|
|
5402
|
+
text: MESSAGE_ONLY_EXCEPTION,
|
|
5403
|
+
candidates: [MESSAGE_ONLY_EXCEPTION]
|
|
5404
|
+
};
|
|
5405
|
+
}
|
|
5406
|
+
const constant2 = constructedClass(first) ?? first;
|
|
5407
|
+
const candidates = constantRefCandidates(constant2, nesting);
|
|
5408
|
+
return candidates.length === 0 ? null : { text: constant2.text, candidates };
|
|
5409
|
+
}
|
|
5410
|
+
function constructedClass(node) {
|
|
5411
|
+
if (node.type !== "call" || field(node, "method")?.text !== "new") {
|
|
5412
|
+
return null;
|
|
5413
|
+
}
|
|
5414
|
+
return field(node, "receiver");
|
|
5415
|
+
}
|
|
5416
|
+
|
|
5417
|
+
// src/responseHandOff.ts
|
|
5418
|
+
function raiseEndings(method) {
|
|
5419
|
+
return escapingRaises(method).map((call) => ({
|
|
5420
|
+
call,
|
|
5421
|
+
terminal: raiseTerminal(call)
|
|
5422
|
+
}));
|
|
5423
|
+
}
|
|
5424
|
+
function raiseTerminal(call) {
|
|
5425
|
+
const [first, second] = readCallArgs(field(call, "arguments")).positional;
|
|
5426
|
+
const message = first === void 0 ? null : stringLiteralValue(first);
|
|
5427
|
+
return {
|
|
5428
|
+
kind: "throw",
|
|
5429
|
+
statusCode: null,
|
|
5430
|
+
body: null,
|
|
5431
|
+
exceptionType: raisedClassRef(call, [])?.text ?? null,
|
|
5432
|
+
message: message ?? (second === void 0 ? null : stringLiteralValue(second)),
|
|
5433
|
+
component: null,
|
|
5434
|
+
renderTree: null,
|
|
5435
|
+
delegateTarget: null,
|
|
5436
|
+
emitEvent: null,
|
|
5437
|
+
location: rangeOf(call)
|
|
5438
|
+
};
|
|
5439
|
+
}
|
|
5440
|
+
function throughResponseHelpers(branches, sites, options) {
|
|
5441
|
+
const handOffs = [];
|
|
5442
|
+
for (const { call, effect } of sites) {
|
|
5443
|
+
const helper = helperBranchesAt(call, options);
|
|
5444
|
+
if (helper !== null) {
|
|
5445
|
+
handOffs.push({
|
|
5446
|
+
helper,
|
|
5447
|
+
preconditions: effect.preconditions,
|
|
5448
|
+
line: rangeOf(call).start,
|
|
5449
|
+
at: rangeOf(call)
|
|
5450
|
+
});
|
|
5451
|
+
}
|
|
5452
|
+
}
|
|
5453
|
+
return handOffs.length === 0 ? [...branches] : branches.flatMap((branch) => (0, import_extractor3.splitAtHandOffs)(branch, handOffs));
|
|
5454
|
+
}
|
|
5455
|
+
function helperBranchesAt(call, options) {
|
|
5456
|
+
if (call.type !== "call") {
|
|
5457
|
+
return null;
|
|
5458
|
+
}
|
|
5459
|
+
const args = readCallArgs(field(call, "arguments"));
|
|
5460
|
+
const handedAt = args.positional.flatMap(
|
|
5461
|
+
(argument, position) => argument.type === "identifier" && refersToResponse(argument, options) ? [{ position, variable: argument.text }] : []
|
|
5462
|
+
);
|
|
5463
|
+
const handedAs = Object.entries(args.keyword).flatMap(
|
|
5464
|
+
([name, argument]) => argument.type === "identifier" && refersToResponse(argument, options) ? [{ name, variable: argument.text }] : []
|
|
5465
|
+
);
|
|
5466
|
+
if (handedAt.length === 0 && handedAs.length === 0) {
|
|
5467
|
+
return null;
|
|
5468
|
+
}
|
|
5469
|
+
const helper = calledDefinition(call, options.facts);
|
|
5470
|
+
if (helper === null) {
|
|
5471
|
+
return null;
|
|
5472
|
+
}
|
|
5473
|
+
const passed = /* @__PURE__ */ new Map();
|
|
5474
|
+
const names = parametersOf(helper).map(
|
|
5475
|
+
(parameter) => paramNameOf(parameter)?.text ?? null
|
|
5476
|
+
);
|
|
5477
|
+
for (const { position, variable } of handedAt) {
|
|
5478
|
+
const name = names[position];
|
|
5479
|
+
if (name !== void 0 && name !== null) {
|
|
5480
|
+
passed.set(name, variable);
|
|
5481
|
+
}
|
|
5482
|
+
}
|
|
5483
|
+
for (const { name, variable } of handedAs) {
|
|
5484
|
+
if (names.includes(name)) {
|
|
5485
|
+
passed.set(name, variable);
|
|
5486
|
+
}
|
|
5487
|
+
}
|
|
5488
|
+
return passed.size === 0 ? null : (0, import_extractor3.helperPathsOnVariables)(options.readHelper(helper), passed);
|
|
5489
|
+
}
|
|
5490
|
+
function refersToResponse(name, options) {
|
|
5491
|
+
const written = writtenNodeOf(name, options.facts);
|
|
5492
|
+
if (written === null) {
|
|
5493
|
+
return false;
|
|
5494
|
+
}
|
|
5495
|
+
if (sameNode(written, options.request)) {
|
|
5496
|
+
return true;
|
|
5497
|
+
}
|
|
5498
|
+
const member = written.type === "call" ? field(written, "method") : null;
|
|
5499
|
+
const receiver = written.type === "call" ? field(written, "receiver") : null;
|
|
5500
|
+
if (member === null || receiver?.type !== "identifier" || !options.bodyMethods.includes(member.text)) {
|
|
5501
|
+
return false;
|
|
5502
|
+
}
|
|
5503
|
+
const parsedFrom = writtenNodeOf(receiver, options.facts);
|
|
5504
|
+
return parsedFrom !== null && sameNode(parsedFrom, options.request);
|
|
5505
|
+
}
|
|
5506
|
+
function sameNode(a, b) {
|
|
5507
|
+
return a.startIndex === b.startIndex && a.endIndex === b.endIndex && a.tree === b.tree;
|
|
5508
|
+
}
|
|
5509
|
+
|
|
5510
|
+
// src/responseStatus.ts
|
|
5511
|
+
var import_extractor6 = require("@suss/extractor");
|
|
5512
|
+
var import_values13 = require("@suss/values");
|
|
5513
|
+
|
|
5514
|
+
// src/provenance.ts
|
|
5515
|
+
var import_extractor4 = require("@suss/extractor");
|
|
4676
5516
|
var import_values11 = require("@suss/values");
|
|
4677
5517
|
|
|
4678
5518
|
// src/storage.ts
|
|
@@ -4738,7 +5578,7 @@ function pickedSource(call, loader) {
|
|
|
4738
5578
|
return null;
|
|
4739
5579
|
}
|
|
4740
5580
|
const args = field(pick, "arguments");
|
|
4741
|
-
const given = args === null ? void 0 : args.
|
|
5581
|
+
const given = args === null ? void 0 : args.namedChild(source.at);
|
|
4742
5582
|
return given?.type === "constant" || given?.type === "scope_resolution" ? given : null;
|
|
4743
5583
|
}
|
|
4744
5584
|
|
|
@@ -5383,10 +6223,7 @@ function recognizeMethodStorage(method, file, options) {
|
|
|
5383
6223
|
return { effects, slots };
|
|
5384
6224
|
}
|
|
5385
6225
|
function callsUnder(node, found = []) {
|
|
5386
|
-
for (const child of node
|
|
5387
|
-
if (child === null) {
|
|
5388
|
-
continue;
|
|
5389
|
-
}
|
|
6226
|
+
for (const child of children(node)) {
|
|
5390
6227
|
if (child.type === "call") {
|
|
5391
6228
|
found.push(child);
|
|
5392
6229
|
}
|
|
@@ -5528,7 +6365,7 @@ function valueSources(values, context, question = "wantedSource") {
|
|
|
5528
6365
|
const spelling = spellingFor(context);
|
|
5529
6366
|
const found = new NodeMap();
|
|
5530
6367
|
for (const [value, key] of keys) {
|
|
5531
|
-
found.set(value, (0,
|
|
6368
|
+
found.set(value, (0, import_extractor4.sourceRefsOf)(leaves.get(key) ?? [], spelling));
|
|
5532
6369
|
}
|
|
5533
6370
|
return found;
|
|
5534
6371
|
}
|
|
@@ -5594,6 +6431,111 @@ function literalAt(key, facts) {
|
|
|
5594
6431
|
return constant2 !== void 0 ? constant2 : (0, import_values11.literalOf)(value) ?? void 0;
|
|
5595
6432
|
}
|
|
5596
6433
|
|
|
6434
|
+
// src/raisedStatuses.ts
|
|
6435
|
+
function rescuedBy(handlers, exception) {
|
|
6436
|
+
if (handlers === "eachRoute") {
|
|
6437
|
+
return true;
|
|
6438
|
+
}
|
|
6439
|
+
const classes = new Set(classesOf(exception));
|
|
6440
|
+
return handlers.some(
|
|
6441
|
+
(caught) => caught.someUnread || caught.classes.some(
|
|
6442
|
+
(one) => classes.has(one.name) || exception.incomplete && one.inheritableByUnread
|
|
6443
|
+
)
|
|
6444
|
+
);
|
|
6445
|
+
}
|
|
6446
|
+
function raisedTerminal(pattern, exception, handlers, location) {
|
|
6447
|
+
const libraryStatus = exception === null ? void 0 : pattern.libraryExceptions?.[exception.name]?.status;
|
|
6448
|
+
const status = exception === null || rescuedBy(handlers, exception) ? void 0 : libraryStatus;
|
|
6449
|
+
return {
|
|
6450
|
+
kind: status === void 0 ? "throw" : "response",
|
|
6451
|
+
statusCode: status === void 0 ? null : { type: "literal", value: status },
|
|
6452
|
+
body: null,
|
|
6453
|
+
exceptionType: status === void 0 ? exception?.name ?? null : null,
|
|
6454
|
+
...status === void 0 && exception !== null ? {
|
|
6455
|
+
exceptionAncestry: {
|
|
6456
|
+
ancestors: exception.ancestors,
|
|
6457
|
+
incomplete: exception.incomplete
|
|
6458
|
+
}
|
|
6459
|
+
} : {},
|
|
6460
|
+
...status === void 0 && libraryStatus !== void 0 ? { statusWhenUncaught: libraryStatus } : {},
|
|
6461
|
+
message: null,
|
|
6462
|
+
component: null,
|
|
6463
|
+
renderTree: null,
|
|
6464
|
+
delegateTarget: null,
|
|
6465
|
+
emitEvent: null,
|
|
6466
|
+
location
|
|
6467
|
+
};
|
|
6468
|
+
}
|
|
6469
|
+
function raisedStatusBranches(pattern, storage, effects, handlers, location) {
|
|
6470
|
+
const operations = new Set(
|
|
6471
|
+
(effects ?? []).flatMap(
|
|
6472
|
+
(effect) => effect.type === "interaction" && effect.interaction.class === "storage-access" && effect.interaction.operation !== void 0 ? [effect.interaction.operation] : []
|
|
6473
|
+
)
|
|
6474
|
+
);
|
|
6475
|
+
const raised = new Set(
|
|
6476
|
+
storage.flatMap(
|
|
6477
|
+
(one) => (one.raises ?? []).flatMap(
|
|
6478
|
+
(raise) => raise.methods.some((method) => operations.has(method)) ? [raise.exception] : []
|
|
6479
|
+
)
|
|
6480
|
+
)
|
|
6481
|
+
);
|
|
6482
|
+
return [...raised].flatMap((name) => {
|
|
6483
|
+
const exception = listedException(name, pattern.libraryExceptions ?? {}) ?? unreadException(name);
|
|
6484
|
+
const terminal = raisedTerminal(pattern, exception, handlers, location);
|
|
6485
|
+
if (terminal.kind === "throw" && !rescuedBy(handlers, exception)) {
|
|
6486
|
+
return [];
|
|
6487
|
+
}
|
|
6488
|
+
return [
|
|
6489
|
+
{
|
|
6490
|
+
conditions: [
|
|
6491
|
+
{
|
|
6492
|
+
sourceText: `${name} raised`,
|
|
6493
|
+
structured: null,
|
|
6494
|
+
polarity: "positive",
|
|
6495
|
+
source: "earlyThrow"
|
|
6496
|
+
}
|
|
6497
|
+
],
|
|
6498
|
+
terminal,
|
|
6499
|
+
effects: [],
|
|
6500
|
+
location,
|
|
6501
|
+
isDefault: false
|
|
6502
|
+
}
|
|
6503
|
+
];
|
|
6504
|
+
});
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6507
|
+
// src/responseBody.ts
|
|
6508
|
+
var import_extractor5 = require("@suss/extractor");
|
|
6509
|
+
var import_values12 = require("@suss/values");
|
|
6510
|
+
var BODY_KINDS = /* @__PURE__ */ new Set([
|
|
6511
|
+
"record",
|
|
6512
|
+
"sequence",
|
|
6513
|
+
"unbounded"
|
|
6514
|
+
]);
|
|
6515
|
+
function serializedValue(node, serializers) {
|
|
6516
|
+
const receiver = field(node, "receiver");
|
|
6517
|
+
const method = field(node, "method")?.text;
|
|
6518
|
+
if (node.type !== "call" || receiver === null || method === void 0 || !serializers.has(method) || field(node, "arguments") !== null) {
|
|
6519
|
+
return node;
|
|
6520
|
+
}
|
|
6521
|
+
return serializedValue(receiver, serializers);
|
|
6522
|
+
}
|
|
6523
|
+
function bodyReadingOfCall(call, declaration, facts) {
|
|
6524
|
+
if (declaration.bodyKeyword === void 0 || call.type !== "call") {
|
|
6525
|
+
return import_extractor5.absentReading;
|
|
6526
|
+
}
|
|
6527
|
+
const argument = readCallArgs(field(call, "arguments")).keyword[declaration.bodyKeyword];
|
|
6528
|
+
if (argument === void 0) {
|
|
6529
|
+
return import_extractor5.absentReading;
|
|
6530
|
+
}
|
|
6531
|
+
const body = serializedValue(
|
|
6532
|
+
argument,
|
|
6533
|
+
new Set(declaration.bodySerializers ?? [])
|
|
6534
|
+
);
|
|
6535
|
+
const value = evaluatedValue(body, facts);
|
|
6536
|
+
return BODY_KINDS.has(value.kind) ? (0, import_extractor5.writtenReading)((0, import_values12.shapeOfValue)(value), rangeOf(argument)) : import_extractor5.absentReading;
|
|
6537
|
+
}
|
|
6538
|
+
|
|
5597
6539
|
// src/responseStatus.ts
|
|
5598
6540
|
function statusArgumentOf(call, declaration) {
|
|
5599
6541
|
const args = readCallArgs(field(call, "arguments"));
|
|
@@ -5606,13 +6548,17 @@ function statusArgumentOf(call, declaration) {
|
|
|
5606
6548
|
}
|
|
5607
6549
|
return args.positional[declaration.statusArgument] ?? null;
|
|
5608
6550
|
}
|
|
5609
|
-
function statusNumberOf(node, names, facts) {
|
|
6551
|
+
function statusNumberOf(node, names, facts, bound = /* @__PURE__ */ new Map()) {
|
|
6552
|
+
const passed = node.type === "identifier" ? bound.get(node.text) : void 0;
|
|
6553
|
+
if (passed !== void 0) {
|
|
6554
|
+
return passed;
|
|
6555
|
+
}
|
|
5610
6556
|
const value = evaluatedValue(node, facts);
|
|
5611
|
-
const constant2 = (0,
|
|
6557
|
+
const constant2 = (0, import_values13.constantOf)(value);
|
|
5612
6558
|
if (typeof constant2 === "number") {
|
|
5613
6559
|
return constant2;
|
|
5614
6560
|
}
|
|
5615
|
-
const name = (0,
|
|
6561
|
+
const name = (0, import_values13.literalOf)(value);
|
|
5616
6562
|
return name === null ? null : names[name] ?? null;
|
|
5617
6563
|
}
|
|
5618
6564
|
function declarationsByName(declarations) {
|
|
@@ -5630,21 +6576,42 @@ function declarationOf(node, byName, locals) {
|
|
|
5630
6576
|
const name = field(node, "method")?.text;
|
|
5631
6577
|
return name === void 0 ? void 0 : byName.get(name);
|
|
5632
6578
|
}
|
|
5633
|
-
function
|
|
5634
|
-
|
|
6579
|
+
function responderOf(node, responders) {
|
|
6580
|
+
const declaration = declarationOf(node, responders.byName, responders.locals);
|
|
6581
|
+
if (declaration !== void 0) {
|
|
6582
|
+
return { kind: "declared", declaration };
|
|
6583
|
+
}
|
|
6584
|
+
const name = receiverlessName(node, responders.locals);
|
|
6585
|
+
const reading = name === null || responders.helper === void 0 ? null : responders.helper(name, node);
|
|
6586
|
+
return reading === null ? void 0 : { kind: "helper", reading };
|
|
6587
|
+
}
|
|
6588
|
+
function receiverlessName(node, locals) {
|
|
6589
|
+
if (node.type === "identifier") {
|
|
6590
|
+
return isBareMethodCall(node, locals) ? node.text : null;
|
|
6591
|
+
}
|
|
6592
|
+
if (node.type !== "call" || field(node, "receiver") !== null) {
|
|
6593
|
+
return null;
|
|
6594
|
+
}
|
|
6595
|
+
return field(node, "method")?.text ?? null;
|
|
6596
|
+
}
|
|
6597
|
+
function readingOfResponder(call, responder, names, options) {
|
|
6598
|
+
return responder.kind === "helper" ? responder.reading : readingOfCall(call, responder.declaration, names, options);
|
|
6599
|
+
}
|
|
6600
|
+
function collectResponseCalls(node, responders, found) {
|
|
6601
|
+
for (const child of children(node)) {
|
|
5635
6602
|
if (child === null || OWN_BODY_TYPES.has(child.type)) {
|
|
5636
6603
|
continue;
|
|
5637
6604
|
}
|
|
5638
|
-
if (
|
|
6605
|
+
if (responderOf(child, responders) !== void 0) {
|
|
5639
6606
|
found.push(child);
|
|
5640
6607
|
continue;
|
|
5641
6608
|
}
|
|
5642
|
-
collectResponseCalls(child,
|
|
6609
|
+
collectResponseCalls(child, responders, found);
|
|
5643
6610
|
}
|
|
5644
6611
|
return found;
|
|
5645
6612
|
}
|
|
5646
6613
|
function collectReturns(node, found) {
|
|
5647
|
-
for (const child of node
|
|
6614
|
+
for (const child of children(node)) {
|
|
5648
6615
|
if (child === null || OWN_BODY_TYPES.has(child.type)) {
|
|
5649
6616
|
continue;
|
|
5650
6617
|
}
|
|
@@ -5656,23 +6623,28 @@ function collectReturns(node, found) {
|
|
|
5656
6623
|
}
|
|
5657
6624
|
return found;
|
|
5658
6625
|
}
|
|
5659
|
-
function readingOfCall(call, declaration, names,
|
|
6626
|
+
function readingOfCall(call, declaration, names, options) {
|
|
5660
6627
|
const argument = statusArgumentOf(call, declaration);
|
|
5661
6628
|
if (argument === null) {
|
|
5662
|
-
return declaration.defaultStatusCode === void 0 ?
|
|
6629
|
+
return declaration.defaultStatusCode === void 0 ? import_extractor6.absentReading : (0, import_extractor6.writtenReading)(declaration.defaultStatusCode, rangeOf(call));
|
|
5663
6630
|
}
|
|
5664
|
-
const status = statusNumberOf(
|
|
6631
|
+
const status = statusNumberOf(
|
|
6632
|
+
argument,
|
|
6633
|
+
names,
|
|
6634
|
+
options.facts,
|
|
6635
|
+
options.boundStatuses
|
|
6636
|
+
);
|
|
5665
6637
|
if (status === null) {
|
|
5666
|
-
return (0,
|
|
6638
|
+
return (0, import_extractor6.unreadableReading)(
|
|
5667
6639
|
"This response writes a status that does not settle on a number here, so this outcome claims none",
|
|
5668
6640
|
rangeOf(argument)
|
|
5669
6641
|
);
|
|
5670
6642
|
}
|
|
5671
|
-
return (0,
|
|
6643
|
+
return (0, import_extractor6.writtenReading)(status, rangeOf(argument));
|
|
5672
6644
|
}
|
|
5673
6645
|
function effectsReaching(effects, conditions) {
|
|
5674
6646
|
return effects.filter(
|
|
5675
|
-
(effect) => (0,
|
|
6647
|
+
(effect) => (0, import_extractor6.guardsHoldOn)(
|
|
5676
6648
|
effect.type === "invocation" ? effect.preconditions : void 0,
|
|
5677
6649
|
conditions
|
|
5678
6650
|
)
|
|
@@ -5697,6 +6669,45 @@ function conditionInputs(method, paths, facts) {
|
|
|
5697
6669
|
);
|
|
5698
6670
|
return operands.length === 0 ? void 0 : guardInputs(operands, { facts, unit: method });
|
|
5699
6671
|
}
|
|
6672
|
+
function boundStatusArguments(helper, call, pattern, facts) {
|
|
6673
|
+
const parameters = children(field(helper, "parameters")).filter(
|
|
6674
|
+
(child) => child.type === "identifier"
|
|
6675
|
+
);
|
|
6676
|
+
const args = call.type === "call" ? readCallArgs(field(call, "arguments")).positional : [];
|
|
6677
|
+
const bound = /* @__PURE__ */ new Map();
|
|
6678
|
+
parameters.forEach((parameter, index) => {
|
|
6679
|
+
const arg = args[index];
|
|
6680
|
+
const status = arg === void 0 ? null : statusNumberOf(arg, pattern.statusCodeNames ?? {}, facts);
|
|
6681
|
+
if (status !== null) {
|
|
6682
|
+
bound.set(parameter.text, status);
|
|
6683
|
+
}
|
|
6684
|
+
});
|
|
6685
|
+
return bound;
|
|
6686
|
+
}
|
|
6687
|
+
function helperResponse(helper, pattern, facts, boundStatuses = /* @__PURE__ */ new Map()) {
|
|
6688
|
+
const branches = responseBranches(helper, pattern, [], void 0, {
|
|
6689
|
+
fallthrough: "handOn",
|
|
6690
|
+
facts,
|
|
6691
|
+
boundStatuses
|
|
6692
|
+
});
|
|
6693
|
+
if (branches === null || branches.some((branch) => branch.terminal.kind !== "response")) {
|
|
6694
|
+
return null;
|
|
6695
|
+
}
|
|
6696
|
+
const statuses = new Set(
|
|
6697
|
+
branches.map((branch) => {
|
|
6698
|
+
const reading = branch.statusCodeReading?.reading;
|
|
6699
|
+
if (reading?.kind === "absent") {
|
|
6700
|
+
return branch.statusCodeReading?.libraryDefault ?? null;
|
|
6701
|
+
}
|
|
6702
|
+
return reading?.kind === "written" ? reading.value : null;
|
|
6703
|
+
})
|
|
6704
|
+
);
|
|
6705
|
+
const [only] = [...statuses];
|
|
6706
|
+
return statuses.size === 1 && typeof only === "number" ? (0, import_extractor6.writtenReading)(only, rangeOf(helper)) : (0, import_extractor6.unreadableReading)(
|
|
6707
|
+
"This response is sent by a helper whose status does not settle on one number here, so this outcome claims none",
|
|
6708
|
+
rangeOf(helper)
|
|
6709
|
+
);
|
|
6710
|
+
}
|
|
5700
6711
|
function branchOf(outcome, pattern, effects, extraEffects, options) {
|
|
5701
6712
|
if (outcome.fellThrough === true && options.fallthrough === "handOn") {
|
|
5702
6713
|
return handsOnBranch(outcome, effects, extraEffects);
|
|
@@ -5719,6 +6730,7 @@ function branchOf(outcome, pattern, effects, extraEffects, options) {
|
|
|
5719
6730
|
reading: outcome.reading,
|
|
5720
6731
|
libraryDefault: pattern.defaultStatusCode
|
|
5721
6732
|
},
|
|
6733
|
+
...outcome.body === void 0 ? {} : { bodyShapeReading: { reading: outcome.body } },
|
|
5722
6734
|
effects: effectsReaching(effects, outcome.conditions),
|
|
5723
6735
|
...extraEffects === void 0 ? {} : { extraEffects },
|
|
5724
6736
|
location: outcome.location,
|
|
@@ -5746,20 +6758,26 @@ function handsOnBranch(outcome, effects, extraEffects) {
|
|
|
5746
6758
|
isDefault: outcome.conditions.length === 0
|
|
5747
6759
|
};
|
|
5748
6760
|
}
|
|
5749
|
-
function returnPathBranches(method, effects, exits = [], facts) {
|
|
6761
|
+
function returnPathBranches(method, effects, exits = [], facts, keepsArms, raises2 = []) {
|
|
5750
6762
|
const body = field(method, "body");
|
|
5751
6763
|
if (body === null) {
|
|
5752
6764
|
return null;
|
|
5753
6765
|
}
|
|
5754
6766
|
const returns = collectReturns(body, []);
|
|
5755
6767
|
const exitCalls = exits.map((exit) => exit.call);
|
|
5756
|
-
const
|
|
5757
|
-
|
|
6768
|
+
const terminals = [
|
|
6769
|
+
...returns,
|
|
6770
|
+
...exitCalls,
|
|
6771
|
+
...raises2.map((raise) => raise.call)
|
|
6772
|
+
];
|
|
6773
|
+
const lowered = lowerRubyBody(body, terminals, exitCalls);
|
|
6774
|
+
const enumerated = (0, import_extractor6.enumerateOrDegrade)(
|
|
5758
6775
|
{
|
|
5759
6776
|
statements: lowered.statements,
|
|
5760
|
-
terminalsByStmt: lowered.terminalsByStmt
|
|
6777
|
+
terminalsByStmt: lowered.terminalsByStmt,
|
|
6778
|
+
...keepsArms === void 0 ? {} : { keepsArms }
|
|
5761
6779
|
},
|
|
5762
|
-
|
|
6780
|
+
terminals
|
|
5763
6781
|
);
|
|
5764
6782
|
const inputs = conditionInputs(
|
|
5765
6783
|
method,
|
|
@@ -5787,8 +6805,8 @@ function returnPathBranches(method, effects, exits = [], facts) {
|
|
|
5787
6805
|
returnTerminal(rangeOf(statement))
|
|
5788
6806
|
);
|
|
5789
6807
|
}
|
|
5790
|
-
for (const
|
|
5791
|
-
push(enumerated.byTerminal.get(
|
|
6808
|
+
for (const ending of [...exits, ...raises2]) {
|
|
6809
|
+
push(enumerated.byTerminal.get(ending.call) ?? [], ending.terminal);
|
|
5792
6810
|
}
|
|
5793
6811
|
push(enumerated.fallthrough, returnTerminal(rangeOf(method)));
|
|
5794
6812
|
return branches.length === 0 ? null : branches;
|
|
@@ -5813,21 +6831,30 @@ function responseBranches(method, pattern, effects, extraEffects, options = {})
|
|
|
5813
6831
|
if (declarations.length === 0 || body === null) {
|
|
5814
6832
|
return null;
|
|
5815
6833
|
}
|
|
5816
|
-
const
|
|
5817
|
-
|
|
5818
|
-
|
|
6834
|
+
const responders = {
|
|
6835
|
+
byName: declarationsByName(declarations),
|
|
6836
|
+
locals: localNamesIn(method),
|
|
6837
|
+
helper: options.respondingHelper
|
|
6838
|
+
};
|
|
6839
|
+
const responses = collectResponseCalls(body, responders, []);
|
|
5819
6840
|
const returns = collectReturns(body, []);
|
|
5820
|
-
const
|
|
6841
|
+
const raises2 = options.raises === void 0 ? [] : escapingRaises(method);
|
|
6842
|
+
const lowered = lowerRubyBody(
|
|
6843
|
+
body,
|
|
6844
|
+
[...returns, ...raises2],
|
|
6845
|
+
responses,
|
|
6846
|
+
pattern.formatSwitch
|
|
6847
|
+
);
|
|
5821
6848
|
const bareReturns = returns.filter(
|
|
5822
|
-
(node) => lowered.terminalHome.has(node) && collectResponseCalls(node,
|
|
6849
|
+
(node) => lowered.terminalHome.has(node) && collectResponseCalls(node, responders, []).length === 0
|
|
5823
6850
|
);
|
|
5824
6851
|
const terminals = [...responses, ...bareReturns];
|
|
5825
|
-
const enumerated = (0,
|
|
6852
|
+
const enumerated = (0, import_extractor6.enumerateOrDegrade)(
|
|
5826
6853
|
{
|
|
5827
6854
|
statements: lowered.statements,
|
|
5828
6855
|
terminalsByStmt: lowered.terminalsByStmt
|
|
5829
6856
|
},
|
|
5830
|
-
terminals
|
|
6857
|
+
[...terminals, ...raises2]
|
|
5831
6858
|
);
|
|
5832
6859
|
const statusNames = pattern.statusCodeNames ?? {};
|
|
5833
6860
|
const inputs = conditionInputs(
|
|
@@ -5838,30 +6865,58 @@ function responseBranches(method, pattern, effects, extraEffects, options = {})
|
|
|
5838
6865
|
const conditionsOf = (path7) => path7.map((condition) => conditionOf(condition, inputs));
|
|
5839
6866
|
const outcomes = [];
|
|
5840
6867
|
for (const terminal of terminals) {
|
|
5841
|
-
const
|
|
5842
|
-
const reading =
|
|
6868
|
+
const responder = responderOf(terminal, responders);
|
|
6869
|
+
const reading = responder === void 0 ? import_extractor6.absentReading : readingOfResponder(terminal, responder, statusNames, options);
|
|
6870
|
+
const body2 = responder?.kind === "declared" ? bodyReadingOfCall(terminal, responder.declaration, options.facts) : void 0;
|
|
5843
6871
|
for (const path7 of enumerated.byTerminal.get(terminal) ?? []) {
|
|
5844
6872
|
outcomes.push({
|
|
5845
6873
|
conditions: conditionsOf(path7),
|
|
5846
6874
|
reading,
|
|
5847
|
-
|
|
6875
|
+
...body2 === void 0 ? {} : { body: body2 },
|
|
6876
|
+
location: rangeOf(terminal),
|
|
6877
|
+
// A bare `return` wrote no response, so a filter that takes it
|
|
6878
|
+
// hands the request on the same as one that reaches its end.
|
|
6879
|
+
...responder === void 0 ? { fellThrough: true } : {}
|
|
5848
6880
|
});
|
|
5849
6881
|
}
|
|
5850
6882
|
}
|
|
5851
6883
|
for (const path7 of enumerated.fallthrough) {
|
|
5852
6884
|
outcomes.push({
|
|
5853
6885
|
conditions: conditionsOf(path7),
|
|
5854
|
-
reading:
|
|
6886
|
+
reading: import_extractor6.absentReading,
|
|
5855
6887
|
location: rangeOf(method),
|
|
5856
6888
|
fellThrough: true
|
|
5857
6889
|
});
|
|
5858
6890
|
}
|
|
5859
|
-
|
|
6891
|
+
const read = options.raises;
|
|
6892
|
+
const raised = raises2.flatMap((call) => {
|
|
6893
|
+
const terminal = raisedTerminal(
|
|
6894
|
+
pattern,
|
|
6895
|
+
read?.classes.get(call) ?? null,
|
|
6896
|
+
read?.handlers ?? [],
|
|
6897
|
+
rangeOf(call)
|
|
6898
|
+
);
|
|
6899
|
+
return (enumerated.byTerminal.get(call) ?? []).map((path7) => {
|
|
6900
|
+
const conditions = conditionsOf(path7);
|
|
6901
|
+
return {
|
|
6902
|
+
conditions,
|
|
6903
|
+
terminal,
|
|
6904
|
+
effects: effectsReaching(effects, conditions),
|
|
6905
|
+
...extraEffects === void 0 ? {} : { extraEffects },
|
|
6906
|
+
location: terminal.location,
|
|
6907
|
+
isDefault: false
|
|
6908
|
+
};
|
|
6909
|
+
});
|
|
6910
|
+
});
|
|
6911
|
+
if (outcomes.length === 0 && raised.length === 0) {
|
|
5860
6912
|
return null;
|
|
5861
6913
|
}
|
|
5862
|
-
return
|
|
5863
|
-
(
|
|
5864
|
-
|
|
6914
|
+
return [
|
|
6915
|
+
...outcomes.map(
|
|
6916
|
+
(outcome) => branchOf(outcome, pattern, effects, extraEffects, options)
|
|
6917
|
+
),
|
|
6918
|
+
...raised
|
|
6919
|
+
];
|
|
5865
6920
|
}
|
|
5866
6921
|
|
|
5867
6922
|
// src/clientCalls.ts
|
|
@@ -5874,7 +6929,16 @@ function clientCallUnits(root, pack, pattern, options) {
|
|
|
5874
6929
|
}
|
|
5875
6930
|
for (const call of callsUnder2(method)) {
|
|
5876
6931
|
for (const request of requestCalls(call, pattern, options)) {
|
|
5877
|
-
units.push(
|
|
6932
|
+
units.push(
|
|
6933
|
+
clientUnit(
|
|
6934
|
+
method,
|
|
6935
|
+
name,
|
|
6936
|
+
{ ...request, call },
|
|
6937
|
+
pattern,
|
|
6938
|
+
pack,
|
|
6939
|
+
options
|
|
6940
|
+
)
|
|
6941
|
+
);
|
|
5878
6942
|
}
|
|
5879
6943
|
}
|
|
5880
6944
|
}
|
|
@@ -5932,10 +6996,7 @@ function requestArgument(call, called, pattern) {
|
|
|
5932
6996
|
return pattern.requestObject?.attribute === called ? args.positional[0] : void 0;
|
|
5933
6997
|
}
|
|
5934
6998
|
function methodDefinitions(node, found = []) {
|
|
5935
|
-
for (const child of node
|
|
5936
|
-
if (child === null) {
|
|
5937
|
-
continue;
|
|
5938
|
-
}
|
|
6999
|
+
for (const child of children(node)) {
|
|
5939
7000
|
if (child.type === "method" || child.type === "singleton_method") {
|
|
5940
7001
|
found.push(child);
|
|
5941
7002
|
}
|
|
@@ -5944,10 +7005,7 @@ function methodDefinitions(node, found = []) {
|
|
|
5944
7005
|
return found;
|
|
5945
7006
|
}
|
|
5946
7007
|
function callsUnder2(node, found = []) {
|
|
5947
|
-
for (const child of node
|
|
5948
|
-
if (child === null) {
|
|
5949
|
-
continue;
|
|
5950
|
-
}
|
|
7008
|
+
for (const child of children(node)) {
|
|
5951
7009
|
if (child.type === "call") {
|
|
5952
7010
|
found.push(child);
|
|
5953
7011
|
}
|
|
@@ -5964,20 +7022,23 @@ function requestCalls(call, pattern, options) {
|
|
|
5964
7022
|
const read = (site) => requestCall(
|
|
5965
7023
|
call,
|
|
5966
7024
|
called,
|
|
5967
|
-
|
|
7025
|
+
receiverBase(receiver, pattern, options, site),
|
|
5968
7026
|
pattern,
|
|
5969
7027
|
options,
|
|
5970
7028
|
site
|
|
5971
7029
|
);
|
|
5972
7030
|
const plain = read();
|
|
5973
|
-
if (plain !== null && !(0,
|
|
7031
|
+
if (plain !== null && !(0, import_behavioral_ir2.hasNameHole)(plain.path)) {
|
|
5974
7032
|
return [plain];
|
|
5975
7033
|
}
|
|
5976
7034
|
const byBoundary = /* @__PURE__ */ new Map();
|
|
5977
7035
|
for (const site of constructionSitesOf(call, options.facts)) {
|
|
5978
7036
|
const stated = read(site);
|
|
5979
7037
|
if (stated !== null) {
|
|
5980
|
-
byBoundary.set(
|
|
7038
|
+
byBoundary.set(
|
|
7039
|
+
`${stated.method} ${stated.host ?? ""} ${stated.path}`,
|
|
7040
|
+
stated
|
|
7041
|
+
);
|
|
5981
7042
|
}
|
|
5982
7043
|
}
|
|
5983
7044
|
if (byBoundary.size > 0) {
|
|
@@ -5985,12 +7046,12 @@ function requestCalls(call, pattern, options) {
|
|
|
5985
7046
|
}
|
|
5986
7047
|
return plain === null ? [] : [plain];
|
|
5987
7048
|
}
|
|
5988
|
-
function requestCall(call, called,
|
|
7049
|
+
function requestCall(call, called, base, pattern, options, site) {
|
|
5989
7050
|
const args = readCallArgs(field(call, "arguments"));
|
|
5990
7051
|
const verb = pattern.verbMethodNames[called];
|
|
5991
7052
|
if (verb !== void 0) {
|
|
5992
|
-
const
|
|
5993
|
-
return
|
|
7053
|
+
const target2 = targetAt(urlNodeIn(args, pattern), options, site);
|
|
7054
|
+
return target2 === null ? null : { method: verb, ...underBase(base, target2) };
|
|
5994
7055
|
}
|
|
5995
7056
|
const sent = pattern.requestObject;
|
|
5996
7057
|
if (sent === void 0 || sent.attribute !== called) {
|
|
@@ -6000,8 +7061,14 @@ function requestCall(call, called, prefix, pattern, options, site) {
|
|
|
6000
7061
|
if (built === null) {
|
|
6001
7062
|
return null;
|
|
6002
7063
|
}
|
|
6003
|
-
const
|
|
6004
|
-
return
|
|
7064
|
+
const target = targetAt(built.url, options, site);
|
|
7065
|
+
return target === null ? null : { method: built.method, ...underBase(base, target) };
|
|
7066
|
+
}
|
|
7067
|
+
function underBase(base, target) {
|
|
7068
|
+
if (base === null || target.host !== void 0) {
|
|
7069
|
+
return target;
|
|
7070
|
+
}
|
|
7071
|
+
return { path: base.path + target.path, host: base.host };
|
|
6005
7072
|
}
|
|
6006
7073
|
function requestBuilt(argument, sent, options, site) {
|
|
6007
7074
|
if (argument === void 0) {
|
|
@@ -6022,16 +7089,19 @@ function requestBuilt(argument, sent, options, site) {
|
|
|
6022
7089
|
function isLibraryReceiver(receiver, pattern, options) {
|
|
6023
7090
|
return namesConstant2(receiver, pattern.constantName) || builderCallBehind(receiver, pattern, options.facts) !== null;
|
|
6024
7091
|
}
|
|
6025
|
-
function
|
|
7092
|
+
function receiverBase(receiver, pattern, options, site) {
|
|
6026
7093
|
const built = builderCallBehind(receiver, pattern, options.facts);
|
|
6027
7094
|
if (built === null) {
|
|
6028
|
-
return
|
|
7095
|
+
return null;
|
|
6029
7096
|
}
|
|
6030
7097
|
const args = readCallArgs(field(built, "arguments"));
|
|
6031
7098
|
const keyword = pattern.builderUrlKeyword;
|
|
6032
7099
|
const base = (keyword === void 0 ? void 0 : args.keyword[keyword]) ?? args.positional[0];
|
|
6033
|
-
|
|
6034
|
-
|
|
7100
|
+
if (base === void 0) {
|
|
7101
|
+
return null;
|
|
7102
|
+
}
|
|
7103
|
+
const value = evaluatedValue(base, options.facts, void 0, site);
|
|
7104
|
+
return { path: trimmed((0, import_values14.pathOf)(value) ?? ""), host: (0, import_values14.hostOf)(value) };
|
|
6035
7105
|
}
|
|
6036
7106
|
function trimmed(path7) {
|
|
6037
7107
|
return path7 === "/" ? "" : path7.replace(/\/+$/, "");
|
|
@@ -6054,22 +7124,32 @@ function builderCallBehind(receiver, pattern, facts) {
|
|
|
6054
7124
|
const constant2 = field(written, "receiver");
|
|
6055
7125
|
return constant2 !== null && namesConstant2(constant2, pattern.constantName) ? written : null;
|
|
6056
7126
|
}
|
|
6057
|
-
function urlIn(args, pattern, options, site) {
|
|
6058
|
-
return pathAt(urlNodeIn(args, pattern), options, site);
|
|
6059
|
-
}
|
|
6060
7127
|
function urlNodeIn(args, pattern) {
|
|
6061
7128
|
const keyword = pattern.url.keyword;
|
|
6062
7129
|
return (keyword === void 0 ? void 0 : args.keyword[keyword]) ?? args.positional[pattern.url.position];
|
|
6063
7130
|
}
|
|
6064
|
-
function
|
|
7131
|
+
function targetAt(written, options, site) {
|
|
6065
7132
|
if (written === void 0) {
|
|
6066
7133
|
return null;
|
|
6067
7134
|
}
|
|
6068
|
-
const
|
|
6069
|
-
|
|
7135
|
+
const value = evaluatedValue(written, options.facts, void 0, site);
|
|
7136
|
+
const path7 = (0, import_values14.pathOf)(value);
|
|
7137
|
+
return path7 === void 0 || (0, import_behavioral_ir2.namesNothing)(path7) ? null : { path: path7, host: (0, import_values14.hostOf)(value) };
|
|
6070
7138
|
}
|
|
6071
7139
|
function clientUnit(method, name, request, pattern, pack, options) {
|
|
6072
7140
|
const range = rangeOf(method);
|
|
7141
|
+
const accessors = responseAccessors(pattern);
|
|
7142
|
+
const statusMembers = (0, import_behavioral_ir2.statusMembersOf)(accessors);
|
|
7143
|
+
const reading = {
|
|
7144
|
+
facts: options.facts,
|
|
7145
|
+
statusMembers,
|
|
7146
|
+
handOff: {
|
|
7147
|
+
request: request.call,
|
|
7148
|
+
bodyMethods: accessors.bodyAccessors ?? [],
|
|
7149
|
+
facts: options.facts,
|
|
7150
|
+
readHelper: (helper) => callerBranches(helper, { facts: options.facts, statusMembers })
|
|
7151
|
+
}
|
|
7152
|
+
};
|
|
6073
7153
|
return {
|
|
6074
7154
|
identity: {
|
|
6075
7155
|
name,
|
|
@@ -6081,25 +7161,34 @@ function clientUnit(method, name, request, pattern, pack, options) {
|
|
|
6081
7161
|
exportName: name,
|
|
6082
7162
|
exportPath: [name]
|
|
6083
7163
|
},
|
|
6084
|
-
boundaryBinding: (0,
|
|
7164
|
+
boundaryBinding: (0, import_behavioral_ir2.restBinding)({
|
|
6085
7165
|
transport: pack.protocol,
|
|
6086
7166
|
method: request.method,
|
|
6087
7167
|
path: request.path,
|
|
7168
|
+
host: request.host,
|
|
6088
7169
|
recognition: pack.name
|
|
6089
7170
|
}),
|
|
6090
7171
|
parameters: [],
|
|
6091
|
-
branches: callerBranches(method,
|
|
6092
|
-
...
|
|
7172
|
+
branches: callerBranches(method, reading),
|
|
7173
|
+
...accessors,
|
|
6093
7174
|
bodyContent: "statements",
|
|
6094
7175
|
dependencyCalls: [],
|
|
6095
7176
|
declaredContract: null
|
|
6096
7177
|
};
|
|
6097
7178
|
}
|
|
6098
|
-
function callerBranches(method,
|
|
6099
|
-
const
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
7179
|
+
function callerBranches(method, reading) {
|
|
7180
|
+
const sites = invocationSites(method, void 0, void 0, reading.facts);
|
|
7181
|
+
const effects = sites.map((site) => site.effect);
|
|
7182
|
+
const keepsArms = (condition) => (0, import_behavioral_ir2.testsStatus)(predicateOf(condition), reading.statusMembers);
|
|
7183
|
+
const found = returnPathBranches(
|
|
7184
|
+
method,
|
|
7185
|
+
effects,
|
|
7186
|
+
[],
|
|
7187
|
+
reading.facts,
|
|
7188
|
+
keepsArms,
|
|
7189
|
+
raiseEndings(method)
|
|
7190
|
+
) ?? [returnBranch(rangeOf(method), effects)];
|
|
7191
|
+
return reading.handOff === void 0 ? found : throughResponseHelpers(found, sites, reading.handOff);
|
|
6103
7192
|
}
|
|
6104
7193
|
function responseAccessors(pattern) {
|
|
6105
7194
|
const response = pattern.response;
|
|
@@ -6110,7 +7199,8 @@ function responseAccessors(pattern) {
|
|
|
6110
7199
|
...response.body === void 0 ? {} : { bodyAccessors: response.body },
|
|
6111
7200
|
...response.statusCode === void 0 ? {} : { statusAccessors: response.statusCode },
|
|
6112
7201
|
...response.success === void 0 ? {} : { successAccessors: response.success },
|
|
6113
|
-
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery }
|
|
7202
|
+
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery },
|
|
7203
|
+
...response.redirectDelivery === void 0 ? {} : { redirectDelivery: response.redirectDelivery }
|
|
6114
7204
|
};
|
|
6115
7205
|
}
|
|
6116
7206
|
function returnBranch(range, effects) {
|
|
@@ -6135,8 +7225,8 @@ function returnBranch(range, effects) {
|
|
|
6135
7225
|
}
|
|
6136
7226
|
|
|
6137
7227
|
// src/envReads.ts
|
|
6138
|
-
var
|
|
6139
|
-
var
|
|
7228
|
+
var import_behavioral_ir3 = require("@suss/behavioral-ir");
|
|
7229
|
+
var import_extractor7 = require("@suss/extractor");
|
|
6140
7230
|
var import_resolution9 = require("@suss/resolution");
|
|
6141
7231
|
|
|
6142
7232
|
// src/envSpellings.ts
|
|
@@ -6161,9 +7251,7 @@ function elementSite(node) {
|
|
|
6161
7251
|
if (object === null || !isEnv(object) || isAssignedTo(node)) {
|
|
6162
7252
|
return null;
|
|
6163
7253
|
}
|
|
6164
|
-
const index = node.
|
|
6165
|
-
(child) => child !== null && child.id !== object.id
|
|
6166
|
-
);
|
|
7254
|
+
const index = children(node).find((child) => child.id !== object.id);
|
|
6167
7255
|
if (index === void 0) {
|
|
6168
7256
|
return null;
|
|
6169
7257
|
}
|
|
@@ -6344,7 +7432,7 @@ function followsExitWhenAbsent(parent, child, subject) {
|
|
|
6344
7432
|
if (!STATEMENT_LIST_TYPES.has(parent.type)) {
|
|
6345
7433
|
return false;
|
|
6346
7434
|
}
|
|
6347
|
-
const statements = parent
|
|
7435
|
+
const statements = children(parent);
|
|
6348
7436
|
const at = statements.findIndex((statement) => statement?.id === child.id);
|
|
6349
7437
|
return statements.slice(0, at).some(
|
|
6350
7438
|
(statement) => statement !== null && leavesWhenAbsent(statement, subject)
|
|
@@ -6396,7 +7484,7 @@ function continuationRaises(from) {
|
|
|
6396
7484
|
let parent = current.parent;
|
|
6397
7485
|
while (parent !== null) {
|
|
6398
7486
|
if (STATEMENT_LIST_TYPES.has(parent.type)) {
|
|
6399
|
-
const statements = parent
|
|
7487
|
+
const statements = children(parent);
|
|
6400
7488
|
const at = statements.findIndex((one) => one?.id === current.id);
|
|
6401
7489
|
const exit = firstExit(statements.slice(at + 1));
|
|
6402
7490
|
if (exit !== null) {
|
|
@@ -6430,20 +7518,13 @@ function firstExit(statements) {
|
|
|
6430
7518
|
return null;
|
|
6431
7519
|
}
|
|
6432
7520
|
function exitOf2(statement) {
|
|
6433
|
-
if (
|
|
7521
|
+
if (isRaiseCall(statement)) {
|
|
6434
7522
|
return "raise";
|
|
6435
7523
|
}
|
|
6436
7524
|
if (LEAVING_TYPES.has(statement.type)) {
|
|
6437
7525
|
return "leave";
|
|
6438
7526
|
}
|
|
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 ?? "");
|
|
7527
|
+
return STATEMENT_LIST_TYPES.has(statement.type) ? firstExit(children(statement)) : null;
|
|
6447
7528
|
}
|
|
6448
7529
|
function isPresentWhen(test, outcome, subject) {
|
|
6449
7530
|
const expression = peelParens(test);
|
|
@@ -6511,7 +7592,7 @@ function isNilCheckOn(call, receiver) {
|
|
|
6511
7592
|
return call.type === "call" && field(call, "method")?.text === "nil?" && field(call, "receiver")?.id === receiver.id;
|
|
6512
7593
|
}
|
|
6513
7594
|
function peelParens(node) {
|
|
6514
|
-
const inner = node.type === "parenthesized_statements" && node.namedChildCount === 1 ? node.
|
|
7595
|
+
const inner = node.type === "parenthesized_statements" && node.namedChildCount === 1 ? node.namedChild(0) : null;
|
|
6515
7596
|
return inner === null || inner === void 0 ? node : peelParens(inner);
|
|
6516
7597
|
}
|
|
6517
7598
|
function climbParens(node) {
|
|
@@ -6556,7 +7637,7 @@ var DEFERRED_BODY_TYPES = /* @__PURE__ */ new Set(["method", "singleton_method",
|
|
|
6556
7637
|
function envReadEffects(root, facts) {
|
|
6557
7638
|
const helpers = helperFactsOf(facts);
|
|
6558
7639
|
const slots = [];
|
|
6559
|
-
(0,
|
|
7640
|
+
(0, import_extractor7.walkDescendants)(root, null, children, {
|
|
6560
7641
|
at: (node) => {
|
|
6561
7642
|
const read = envReadAt(node);
|
|
6562
7643
|
if (read !== null) {
|
|
@@ -6567,7 +7648,7 @@ function envReadEffects(root, facts) {
|
|
|
6567
7648
|
slots.push({ call: node });
|
|
6568
7649
|
}
|
|
6569
7650
|
},
|
|
6570
|
-
into: (node) => DEFERRED_BODY_TYPES.has(node.type) ?
|
|
7651
|
+
into: (node) => DEFERRED_BODY_TYPES.has(node.type) ? import_extractor7.SKIP_CHILDREN : null
|
|
6571
7652
|
});
|
|
6572
7653
|
const calls = slots.flatMap((slot) => "call" in slot ? [slot.call] : []);
|
|
6573
7654
|
const throughHelpers = helpers === null ? new NodeMap() : helperReads(calls, helpers);
|
|
@@ -6636,7 +7717,7 @@ function namedParameters(db) {
|
|
|
6636
7717
|
return named2;
|
|
6637
7718
|
}
|
|
6638
7719
|
function emitEnvFacts(db, file, root) {
|
|
6639
|
-
(0,
|
|
7720
|
+
(0, import_extractor7.walkDescendants)(root, null, children, {
|
|
6640
7721
|
at: (node) => {
|
|
6641
7722
|
if (isEnv(node) && handsOnward(node)) {
|
|
6642
7723
|
db.add("environmentObject", [
|
|
@@ -6734,7 +7815,7 @@ function readsAtCall(db, call, args) {
|
|
|
6734
7815
|
function configReadEffect(read) {
|
|
6735
7816
|
return {
|
|
6736
7817
|
type: "interaction",
|
|
6737
|
-
binding: (0,
|
|
7818
|
+
binding: (0, import_behavioral_ir3.runtimeConfigBinding)({ recognition: RUBY_ENV_RECOGNITION }),
|
|
6738
7819
|
callee: `ENV["${read.name}"]`,
|
|
6739
7820
|
interaction: {
|
|
6740
7821
|
class: "config-read",
|
|
@@ -6764,7 +7845,8 @@ function envSiteAt(node) {
|
|
|
6764
7845
|
}
|
|
6765
7846
|
|
|
6766
7847
|
// src/filters.ts
|
|
6767
|
-
|
|
7848
|
+
var RESCUES_NOTHING = { refs: [], someUnread: false };
|
|
7849
|
+
function controllerFilterChain(pattern, ancestry, read = {}) {
|
|
6768
7850
|
const forms = pattern.filters ?? [];
|
|
6769
7851
|
if (forms.length === 0) {
|
|
6770
7852
|
return [];
|
|
@@ -6777,18 +7859,29 @@ function controllerFilters(pattern, ancestry, read = {}) {
|
|
|
6777
7859
|
}
|
|
6778
7860
|
}
|
|
6779
7861
|
let declared = [];
|
|
6780
|
-
|
|
7862
|
+
const inlineSeen = /* @__PURE__ */ new Map();
|
|
7863
|
+
for (const { block, statement } of inheritedStatements(ancestry)) {
|
|
6781
7864
|
const called = calledName(statement);
|
|
6782
7865
|
if (called === null) {
|
|
6783
7866
|
continue;
|
|
6784
7867
|
}
|
|
6785
7868
|
const form = byName.get(called);
|
|
6786
7869
|
if (form !== void 0) {
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
7870
|
+
const inlineKey = `${block.file}\0${block.info.qualifiedName}\0${form.name}`;
|
|
7871
|
+
const ordinal = inlineSeen.get(inlineKey) ?? 0;
|
|
7872
|
+
const declarations = declarationsOf(
|
|
7873
|
+
statement,
|
|
7874
|
+
form,
|
|
7875
|
+
block,
|
|
7876
|
+
read.facts,
|
|
7877
|
+
ordinal
|
|
7878
|
+
);
|
|
7879
|
+
if (declarations.some((one) => one.inline !== void 0)) {
|
|
7880
|
+
inlineSeen.set(inlineKey, ordinal + 1);
|
|
7881
|
+
}
|
|
7882
|
+
for (const declaration of declarations) {
|
|
7883
|
+
const earlier = declaration.filter.onThrow === true ? void 0 : declared.find((one) => sameFilter(one, declaration));
|
|
7884
|
+
declared = [...declared.filter((one) => one !== earlier), declaration];
|
|
6792
7885
|
}
|
|
6793
7886
|
continue;
|
|
6794
7887
|
}
|
|
@@ -6797,26 +7890,78 @@ function controllerFilters(pattern, ancestry, read = {}) {
|
|
|
6797
7890
|
declared = applySkips(declared, skipsOf(statement, skipped, read.facts));
|
|
6798
7891
|
}
|
|
6799
7892
|
}
|
|
6800
|
-
const resolved =
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
7893
|
+
const resolved = declared.map(
|
|
7894
|
+
(declaration) => linkFor(
|
|
7895
|
+
declaration,
|
|
7896
|
+
writtenAt(
|
|
7897
|
+
declaration,
|
|
7898
|
+
filterMethod(ancestry, declaration.methodName, read)
|
|
7899
|
+
)
|
|
7900
|
+
)
|
|
7901
|
+
);
|
|
7902
|
+
return [
|
|
7903
|
+
...resolved.filter((one) => !runsAfterARaise(one)),
|
|
7904
|
+
...resolved.filter(runsAfterARaise).reverse()
|
|
7905
|
+
];
|
|
7906
|
+
}
|
|
7907
|
+
function linkFor(declaration, written) {
|
|
7908
|
+
if (written === null) {
|
|
7909
|
+
return {
|
|
7910
|
+
unread: {
|
|
7911
|
+
filter: declaration.filter,
|
|
7912
|
+
methodName: declaration.methodName,
|
|
7913
|
+
declaredIn: declaration.declaredIn,
|
|
7914
|
+
only: declaration.only,
|
|
7915
|
+
except: declaration.except
|
|
7916
|
+
}
|
|
7917
|
+
};
|
|
7918
|
+
}
|
|
7919
|
+
return {
|
|
7920
|
+
read: {
|
|
6807
7921
|
filter: declaration.filter,
|
|
7922
|
+
...written,
|
|
7923
|
+
only: declaration.only,
|
|
7924
|
+
except: declaration.except,
|
|
7925
|
+
rescues: declaration.rescues
|
|
7926
|
+
}
|
|
7927
|
+
};
|
|
7928
|
+
}
|
|
7929
|
+
function filterOf(link) {
|
|
7930
|
+
return "read" in link ? link.read : link.unread;
|
|
7931
|
+
}
|
|
7932
|
+
function runsAfterARaise(link) {
|
|
7933
|
+
return filterOf(link).filter.onThrow === true;
|
|
7934
|
+
}
|
|
7935
|
+
function writtenAt(declaration, found) {
|
|
7936
|
+
if (found.type === "found") {
|
|
7937
|
+
return {
|
|
6808
7938
|
methodName: declaration.methodName,
|
|
7939
|
+
nameKind: "binding",
|
|
6809
7940
|
method: found.method,
|
|
6810
7941
|
file: found.block.file,
|
|
6811
7942
|
enclosingQualifiedName: found.block.info.qualifiedName,
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
});
|
|
7943
|
+
nesting: found.block.info.bodyNesting
|
|
7944
|
+
};
|
|
6815
7945
|
}
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
7946
|
+
const inline = declaration.inline;
|
|
7947
|
+
if (inline === void 0) {
|
|
7948
|
+
return null;
|
|
7949
|
+
}
|
|
7950
|
+
return {
|
|
7951
|
+
methodName: inline.label,
|
|
7952
|
+
nameKind: "label",
|
|
7953
|
+
method: inline.block,
|
|
7954
|
+
file: inline.declaredIn.file,
|
|
7955
|
+
enclosingQualifiedName: inline.declaredIn.info.qualifiedName,
|
|
7956
|
+
nesting: inline.declaredIn.info.bodyNesting
|
|
7957
|
+
};
|
|
7958
|
+
}
|
|
7959
|
+
function filterMethod(ancestry, name, read) {
|
|
7960
|
+
const found = methodInAncestry(ancestry, name, read);
|
|
7961
|
+
if (found.type === "unsettled" && found.cause === "unreadAncestor") {
|
|
7962
|
+
return methodPastUnreadAncestors(ancestry, name, read);
|
|
7963
|
+
}
|
|
7964
|
+
return found;
|
|
6820
7965
|
}
|
|
6821
7966
|
function filterCoversAction(filter, actionName) {
|
|
6822
7967
|
if (filter.except.has(actionName)) {
|
|
@@ -6824,37 +7969,55 @@ function filterCoversAction(filter, actionName) {
|
|
|
6824
7969
|
}
|
|
6825
7970
|
return filter.only === null || filter.only.has(actionName);
|
|
6826
7971
|
}
|
|
6827
|
-
function filterReference(filter, displayPath) {
|
|
7972
|
+
function filterReference(filter, displayPath, caught) {
|
|
7973
|
+
return {
|
|
7974
|
+
file: displayPath,
|
|
7975
|
+
name: filter.methodName,
|
|
7976
|
+
...filter.filter.onThrow === true ? { onThrow: true } : {},
|
|
7977
|
+
...caught === void 0 ? {} : {
|
|
7978
|
+
catches: caught.classes.map((one) => one.name),
|
|
7979
|
+
...caught.classes.some((one) => one.inheritableByUnread) ? { mayCatchUnreadClasses: true } : {},
|
|
7980
|
+
...caught.someUnread ? { mayCatchAny: true } : {}
|
|
7981
|
+
}
|
|
7982
|
+
};
|
|
7983
|
+
}
|
|
7984
|
+
function unreadFilterReference(filter, displayPath) {
|
|
6828
7985
|
return {
|
|
6829
7986
|
file: displayPath,
|
|
6830
7987
|
name: filter.methodName,
|
|
6831
7988
|
...filter.filter.onThrow === true ? { onThrow: true } : {}
|
|
6832
7989
|
};
|
|
6833
7990
|
}
|
|
6834
|
-
function filterUnit(filter, pattern, displayPath, body,
|
|
7991
|
+
function filterUnit(filter, pattern, displayPath, body, reading = {}) {
|
|
6835
7992
|
const range = rangeOf(filter.method);
|
|
7993
|
+
const { respondingHelper, raises: raises2 } = reading;
|
|
6836
7994
|
const branches = responseBranches(
|
|
6837
7995
|
filter.method,
|
|
6838
7996
|
pattern,
|
|
6839
7997
|
body.effects ?? [],
|
|
6840
7998
|
body.extraEffects,
|
|
6841
|
-
{
|
|
7999
|
+
{
|
|
8000
|
+
fallthrough: "handOn",
|
|
8001
|
+
facts: reading.facts,
|
|
8002
|
+
...respondingHelper === void 0 ? {} : { respondingHelper },
|
|
8003
|
+
...raises2 === void 0 ? {} : { raises: raises2 }
|
|
8004
|
+
}
|
|
6842
8005
|
);
|
|
6843
8006
|
return {
|
|
6844
8007
|
identity: {
|
|
6845
8008
|
name: filter.methodName,
|
|
6846
|
-
nameKind:
|
|
8009
|
+
nameKind: filter.nameKind,
|
|
6847
8010
|
kind: "middleware",
|
|
6848
8011
|
file: displayPath,
|
|
6849
8012
|
range,
|
|
6850
8013
|
span: spanOf(filter.method),
|
|
6851
|
-
exportName: filter.methodName,
|
|
8014
|
+
exportName: filter.nameKind === "binding" ? filter.methodName : null,
|
|
6852
8015
|
exportPath: [filter.enclosingQualifiedName, filter.methodName]
|
|
6853
8016
|
},
|
|
6854
8017
|
boundaryBinding: null,
|
|
6855
8018
|
parameters: [],
|
|
6856
8019
|
branches: withSlotSources(
|
|
6857
|
-
branches ?? [handsOn(range, body)],
|
|
8020
|
+
[...branches ?? [handsOn(range, body)], ...reading.raised ?? []],
|
|
6858
8021
|
body.provenance
|
|
6859
8022
|
),
|
|
6860
8023
|
bodyContent: body.bodyContent ?? "absent",
|
|
@@ -6889,25 +8052,93 @@ function calledName(statement) {
|
|
|
6889
8052
|
}
|
|
6890
8053
|
return field(statement, "method")?.text ?? null;
|
|
6891
8054
|
}
|
|
6892
|
-
function declarationsOf(statement, filter, facts) {
|
|
8055
|
+
function declarationsOf(statement, filter, declaredIn, facts, inlineOrdinal) {
|
|
6893
8056
|
const args = readCallArgs(field(statement, "arguments"));
|
|
6894
8057
|
const keywords = filter.actionKeywords;
|
|
6895
8058
|
const only = keywords === void 0 ? null : actionsUnder(args.keyword[keywords.include], facts);
|
|
6896
8059
|
const except = keywords === void 0 ? null : actionsUnder(args.keyword[keywords.exclude], facts);
|
|
6897
|
-
|
|
8060
|
+
const rescues2 = filter.onThrow === true ? rescuedClasses(args, declaredIn.info.bodyNesting, facts) : RESCUES_NOTHING;
|
|
8061
|
+
const inline = inlineHandler(
|
|
8062
|
+
statement,
|
|
8063
|
+
args,
|
|
8064
|
+
filter,
|
|
8065
|
+
declaredIn,
|
|
8066
|
+
inlineOrdinal
|
|
8067
|
+
);
|
|
8068
|
+
return methodNamesOf(args, filter, facts, inline).map((methodName) => ({
|
|
6898
8069
|
filter,
|
|
6899
8070
|
methodName,
|
|
6900
8071
|
only,
|
|
6901
|
-
except: except ?? /* @__PURE__ */ new Set()
|
|
8072
|
+
except: except ?? /* @__PURE__ */ new Set(),
|
|
8073
|
+
rescues: rescues2,
|
|
8074
|
+
declaredIn: declaredIn.file,
|
|
8075
|
+
...inline === void 0 ? {} : { inline }
|
|
6902
8076
|
}));
|
|
6903
8077
|
}
|
|
6904
|
-
function
|
|
8078
|
+
function inlineHandler(statement, args, filter, declaredIn, ordinal) {
|
|
8079
|
+
const block = blockInPlaceOfMethod(statement, args, filter);
|
|
8080
|
+
if (block === null || blockStatements2(block).length === 0) {
|
|
8081
|
+
return void 0;
|
|
8082
|
+
}
|
|
8083
|
+
return { block, label: `${filter.name}#${ordinal}`, declaredIn };
|
|
8084
|
+
}
|
|
8085
|
+
function rescuedClasses(args, nesting, facts) {
|
|
8086
|
+
const refs = [];
|
|
8087
|
+
let someUnread = args.positional.length === 0;
|
|
8088
|
+
for (const arg of args.positional) {
|
|
8089
|
+
const candidates = constantRefCandidates(arg, nesting);
|
|
8090
|
+
const named2 = candidates.length === 0 ? stringValueOf(arg, facts) : null;
|
|
8091
|
+
if (candidates.length === 0 && named2 === null) {
|
|
8092
|
+
someUnread = true;
|
|
8093
|
+
continue;
|
|
8094
|
+
}
|
|
8095
|
+
refs.push({
|
|
8096
|
+
text: arg.text,
|
|
8097
|
+
candidates: named2 === null ? candidates : [named2]
|
|
8098
|
+
});
|
|
8099
|
+
}
|
|
8100
|
+
return { refs, someUnread };
|
|
8101
|
+
}
|
|
8102
|
+
function methodNamesOf(args, filter, facts, inline) {
|
|
8103
|
+
const named2 = filter.methodFrom === "withKeyword" ? withKeywordName(args, facts) : symbolArgumentNames(args, facts);
|
|
8104
|
+
if (named2.length > 0 || inline === void 0) {
|
|
8105
|
+
return named2;
|
|
8106
|
+
}
|
|
8107
|
+
return [blockHandlerName(inline.block) ?? inline.label];
|
|
8108
|
+
}
|
|
8109
|
+
function withKeywordName(args, facts) {
|
|
8110
|
+
const named2 = args.keyword.with;
|
|
8111
|
+
const value = named2 === void 0 ? null : stringValueOf(named2, facts);
|
|
8112
|
+
return value === null ? [] : [value];
|
|
8113
|
+
}
|
|
8114
|
+
function blockInPlaceOfMethod(statement, args, filter) {
|
|
6905
8115
|
if (filter.methodFrom === "withKeyword") {
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
8116
|
+
return args.keyword.with === void 0 ? field(statement, "block") : null;
|
|
8117
|
+
}
|
|
8118
|
+
const lambda = args.positional.find((arg) => arg.type === "lambda");
|
|
8119
|
+
if (lambda !== void 0) {
|
|
8120
|
+
return field(lambda, "body");
|
|
8121
|
+
}
|
|
8122
|
+
return args.positional.length === 0 ? field(statement, "block") : null;
|
|
8123
|
+
}
|
|
8124
|
+
function blockStatements2(block) {
|
|
8125
|
+
return children(field(block, "body")).filter(
|
|
8126
|
+
(child) => child.type !== "comment"
|
|
8127
|
+
);
|
|
8128
|
+
}
|
|
8129
|
+
function blockHandlerName(block) {
|
|
8130
|
+
const statements = blockStatements2(block);
|
|
8131
|
+
const only = statements.length === 1 ? statements[0] : void 0;
|
|
8132
|
+
if (only === void 0) {
|
|
8133
|
+
return null;
|
|
8134
|
+
}
|
|
8135
|
+
const parameters = new Set(
|
|
8136
|
+
children(field(block, "parameters")).map((parameter) => parameter.text)
|
|
8137
|
+
);
|
|
8138
|
+
if (only.type === "identifier") {
|
|
8139
|
+
return parameters.has(only.text) ? null : only.text;
|
|
6909
8140
|
}
|
|
6910
|
-
return
|
|
8141
|
+
return calledName(only);
|
|
6911
8142
|
}
|
|
6912
8143
|
function symbolArgumentNames(args, facts) {
|
|
6913
8144
|
return args.positional.map((arg) => stringValueOf(arg, facts)).filter((name) => name !== null);
|
|
@@ -6918,13 +8149,16 @@ function skipsOf(statement, filterName, facts) {
|
|
|
6918
8149
|
return args.positional.map((arg) => stringValueOf(arg, facts)).filter((name) => name !== null).map((methodName) => ({ filterName, methodName, actions }));
|
|
6919
8150
|
}
|
|
6920
8151
|
function sameFilter(one, other) {
|
|
6921
|
-
return one.filter.name === other.filter.name && one.methodName === other.methodName;
|
|
8152
|
+
return namedBySymbol(one) && namedBySymbol(other) && one.filter.name === other.filter.name && one.methodName === other.methodName;
|
|
8153
|
+
}
|
|
8154
|
+
function namedBySymbol(declaration) {
|
|
8155
|
+
return declaration.inline === void 0;
|
|
6922
8156
|
}
|
|
6923
8157
|
function applySkips(declared, skips) {
|
|
6924
8158
|
const left = [];
|
|
6925
8159
|
for (const declaration of declared) {
|
|
6926
8160
|
const reaching = skips.filter(
|
|
6927
|
-
(skip) => skip.filterName === declaration.filter.name && skip.methodName === declaration.methodName
|
|
8161
|
+
(skip) => namedBySymbol(declaration) && skip.filterName === declaration.filter.name && skip.methodName === declaration.methodName
|
|
6928
8162
|
);
|
|
6929
8163
|
if (reaching.some((skip) => skip.actions === null)) {
|
|
6930
8164
|
continue;
|
|
@@ -6948,8 +8182,8 @@ function actionsUnder(node, facts) {
|
|
|
6948
8182
|
}
|
|
6949
8183
|
|
|
6950
8184
|
// src/streamWrites.ts
|
|
6951
|
-
var
|
|
6952
|
-
var
|
|
8185
|
+
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
8186
|
+
var import_extractor8 = require("@suss/extractor");
|
|
6953
8187
|
var RUBY_STREAM_RECOGNITION = "ruby-stdlib";
|
|
6954
8188
|
var KERNEL_WRITES = /* @__PURE__ */ new Map([
|
|
6955
8189
|
["puts", "stdout"],
|
|
@@ -6967,14 +8201,14 @@ var STREAM_METHODS = /* @__PURE__ */ new Set(["puts", "print", "write", "<<"]);
|
|
|
6967
8201
|
var DEFERRED_BODY_TYPES2 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
6968
8202
|
function streamWriteEffects(root) {
|
|
6969
8203
|
const found = [];
|
|
6970
|
-
(0,
|
|
8204
|
+
(0, import_extractor8.walkDescendants)(root, null, children, {
|
|
6971
8205
|
at: (node) => {
|
|
6972
8206
|
const write = node.type === "call" ? streamWriteAt(node) : null;
|
|
6973
8207
|
if (write !== null) {
|
|
6974
8208
|
found.push(write);
|
|
6975
8209
|
}
|
|
6976
8210
|
},
|
|
6977
|
-
into: (node) => DEFERRED_BODY_TYPES2.has(node.type) ?
|
|
8211
|
+
into: (node) => DEFERRED_BODY_TYPES2.has(node.type) ? import_extractor8.SKIP_CHILDREN : null
|
|
6978
8212
|
});
|
|
6979
8213
|
return found;
|
|
6980
8214
|
}
|
|
@@ -7005,7 +8239,7 @@ function writeEffect(call, target, args) {
|
|
|
7005
8239
|
const method = field(call, "method")?.text ?? "";
|
|
7006
8240
|
return {
|
|
7007
8241
|
type: "interaction",
|
|
7008
|
-
binding: (0,
|
|
8242
|
+
binding: (0, import_behavioral_ir4.ioBinding)({ recognition: RUBY_STREAM_RECOGNITION, target }),
|
|
7009
8243
|
callee: receiver === null ? method : `${receiver.text}.${method}`,
|
|
7010
8244
|
groupId: `${call.startPosition.row + 1}:${call.startPosition.column + 1}`,
|
|
7011
8245
|
interaction: { class: "stream-write", ...payloadOf(args) }
|
|
@@ -7058,7 +8292,7 @@ function writtenShapeOf(node) {
|
|
|
7058
8292
|
return hashShape(node);
|
|
7059
8293
|
}
|
|
7060
8294
|
if (node.type === "array") {
|
|
7061
|
-
const first = node.
|
|
8295
|
+
const first = children(node).find((child) => child !== null);
|
|
7062
8296
|
return {
|
|
7063
8297
|
type: "array",
|
|
7064
8298
|
items: first ? writtenShapeOf(first) : { type: "unknown" }
|
|
@@ -7068,7 +8302,7 @@ function writtenShapeOf(node) {
|
|
|
7068
8302
|
}
|
|
7069
8303
|
function hashShape(node) {
|
|
7070
8304
|
const properties = {};
|
|
7071
|
-
for (const pair of node
|
|
8305
|
+
for (const pair of children(node)) {
|
|
7072
8306
|
if (pair?.type !== "pair") {
|
|
7073
8307
|
continue;
|
|
7074
8308
|
}
|
|
@@ -7086,10 +8320,10 @@ function keyName(key) {
|
|
|
7086
8320
|
}
|
|
7087
8321
|
|
|
7088
8322
|
// src/testCases.ts
|
|
7089
|
-
var
|
|
7090
|
-
var
|
|
8323
|
+
var import_behavioral_ir5 = require("@suss/behavioral-ir");
|
|
8324
|
+
var import_extractor9 = require("@suss/extractor");
|
|
7091
8325
|
var import_resolution10 = require("@suss/resolution");
|
|
7092
|
-
var
|
|
8326
|
+
var import_values17 = require("@suss/values");
|
|
7093
8327
|
var BLOCK_TYPES6 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
7094
8328
|
function testPatternsIn(packs) {
|
|
7095
8329
|
return packs.flatMap((pack) => pack.tests ?? []);
|
|
@@ -7273,7 +8507,7 @@ function groupStatements(group) {
|
|
|
7273
8507
|
}
|
|
7274
8508
|
function patternForFile(file, patterns) {
|
|
7275
8509
|
return patterns.find(
|
|
7276
|
-
(pattern) => (0,
|
|
8510
|
+
(pattern) => (0, import_extractor9.matchesTestFileName)(file, pattern.filePatterns) && (0, import_extractor9.isListedTestFile)(file, pattern.files)
|
|
7277
8511
|
) ?? null;
|
|
7278
8512
|
}
|
|
7279
8513
|
function groupNamesIn(pattern) {
|
|
@@ -7431,14 +8665,14 @@ var NodesSeen = class {
|
|
|
7431
8665
|
};
|
|
7432
8666
|
function exampleRun(example, pattern, shared) {
|
|
7433
8667
|
const byName = /* @__PURE__ */ new Map();
|
|
7434
|
-
const
|
|
8668
|
+
const always3 = [];
|
|
7435
8669
|
for (const group of withInlineIncludes(example.groups, pattern, shared)) {
|
|
7436
8670
|
for (const one of groupBlocks(group, pattern)) {
|
|
7437
8671
|
for (const name of one.names) {
|
|
7438
8672
|
byName.set(name, one.block);
|
|
7439
8673
|
}
|
|
7440
8674
|
if (one.always) {
|
|
7441
|
-
|
|
8675
|
+
always3.push(one.block);
|
|
7442
8676
|
}
|
|
7443
8677
|
}
|
|
7444
8678
|
}
|
|
@@ -7457,7 +8691,7 @@ function exampleRun(example, pattern, shared) {
|
|
|
7457
8691
|
}
|
|
7458
8692
|
};
|
|
7459
8693
|
include(example.block);
|
|
7460
|
-
for (const block of
|
|
8694
|
+
for (const block of always3) {
|
|
7461
8695
|
include(block);
|
|
7462
8696
|
}
|
|
7463
8697
|
const valueNames = /* @__PURE__ */ new Set([
|
|
@@ -7565,7 +8799,7 @@ function exampleCalls(run, inherited) {
|
|
|
7565
8799
|
}
|
|
7566
8800
|
function testCaseUnits(root, patterns, options) {
|
|
7567
8801
|
return patterns.flatMap((pattern) => {
|
|
7568
|
-
if (!(0,
|
|
8802
|
+
if (!(0, import_extractor9.matchesTestFileName)(options.absoluteFile, pattern.filePatterns) || !(0, import_extractor9.isListedTestFile)(options.absoluteFile, pattern.files)) {
|
|
7569
8803
|
return [];
|
|
7570
8804
|
}
|
|
7571
8805
|
return examplesIn(root, options.absoluteFile, pattern, options.shared).map(
|
|
@@ -7638,7 +8872,7 @@ function testUnitOf(parts) {
|
|
|
7638
8872
|
const range = rangeOf(anchor);
|
|
7639
8873
|
return {
|
|
7640
8874
|
identity: {
|
|
7641
|
-
name: (0,
|
|
8875
|
+
name: (0, import_behavioral_ir5.testUnitName)(titles.map((title) => title.text)),
|
|
7642
8876
|
nameKind: "label",
|
|
7643
8877
|
kind: "test",
|
|
7644
8878
|
file: options.filePath,
|
|
@@ -7684,7 +8918,7 @@ function titleOf(call, facts) {
|
|
|
7684
8918
|
if (first.type === "constant" || first.type === "scope_resolution") {
|
|
7685
8919
|
return { text: first.text, unresolved: false };
|
|
7686
8920
|
}
|
|
7687
|
-
const read = (0,
|
|
8921
|
+
const read = (0, import_values17.literalOf)(evaluatedValue(first, facts));
|
|
7688
8922
|
return read === null ? { text: first.text, unresolved: true } : { text: read, unresolved: false };
|
|
7689
8923
|
}
|
|
7690
8924
|
function isSkipped(example, pattern) {
|
|
@@ -7825,18 +9059,18 @@ function moduleOfConstant(node, options) {
|
|
|
7825
9059
|
const key = classBehind(facts, options.absoluteFile, node);
|
|
7826
9060
|
return key === void 0 ? null : options.displayPathOf((0, import_resolution10.fileOfKey)(key));
|
|
7827
9061
|
}
|
|
7828
|
-
const name = (0,
|
|
9062
|
+
const name = (0, import_values17.literalOf)(evaluatedValue(node, facts));
|
|
7829
9063
|
const keys = name === null ? [] : facts.lookup("rbConstantName", 1, name.replace(/^::/, "")).map((row) => String(row[0]));
|
|
7830
9064
|
const files = [...new Set(keys.map(import_resolution10.fileOfKey))];
|
|
7831
9065
|
return files.length === 1 ? options.displayPathOf(files[0]) : null;
|
|
7832
9066
|
}
|
|
7833
|
-
function oneLine(
|
|
7834
|
-
return
|
|
9067
|
+
function oneLine(text3) {
|
|
9068
|
+
return text3.replace(/\s*\n\s*/g, " ").trim();
|
|
7835
9069
|
}
|
|
7836
9070
|
|
|
7837
9071
|
// src/testClasses.ts
|
|
7838
|
-
var
|
|
7839
|
-
var
|
|
9072
|
+
var import_extractor10 = require("@suss/extractor");
|
|
9073
|
+
var import_values19 = require("@suss/values");
|
|
7840
9074
|
var BLOCK_TYPES7 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
7841
9075
|
function testClassPatternsIn(packs) {
|
|
7842
9076
|
return packs.flatMap((pack) => pack.testClasses ?? []);
|
|
@@ -7879,7 +9113,7 @@ function testClassUnits(root, patterns, options) {
|
|
|
7879
9113
|
});
|
|
7880
9114
|
}
|
|
7881
9115
|
function readsFile(file, pattern) {
|
|
7882
|
-
return (0,
|
|
9116
|
+
return (0, import_extractor10.matchesTestFileName)(file, pattern.filePatterns) && (0, import_extractor10.isListedTestFile)(file, pattern.files);
|
|
7883
9117
|
}
|
|
7884
9118
|
function testClassesIn(root, file, pattern, facts) {
|
|
7885
9119
|
const found = [];
|
|
@@ -7925,7 +9159,7 @@ function testBlockOf(statement, pattern) {
|
|
|
7925
9159
|
}
|
|
7926
9160
|
function descriptionOf(call, facts) {
|
|
7927
9161
|
const first = firstArgument(call);
|
|
7928
|
-
return first === null ? null : (0,
|
|
9162
|
+
return first === null ? null : (0, import_values19.literalOf)(evaluatedValue(first, facts));
|
|
7929
9163
|
}
|
|
7930
9164
|
function anchorOf2(node) {
|
|
7931
9165
|
return BLOCK_TYPES7.has(node.type) ? node.parent ?? node : node;
|
|
@@ -8102,6 +9336,7 @@ function fieldReadContext(pattern, cache, fileBlocks, bodyRead, facts) {
|
|
|
8102
9336
|
},
|
|
8103
9337
|
lookup: {
|
|
8104
9338
|
root: pattern.root,
|
|
9339
|
+
autoloadRoots: pattern.autoloadRoots ?? [],
|
|
8105
9340
|
pathConvention: pattern.pathConvention,
|
|
8106
9341
|
acronyms: pattern.acronyms ?? [],
|
|
8107
9342
|
ancestryRootClassNames: pattern.ancestryRootClassNames,
|
|
@@ -8210,7 +9445,7 @@ function unitsFor(pattern, pack, info, ownBlocks, fileBlocks, options) {
|
|
|
8210
9445
|
graphqlObjectFields: (p) => graphqlObjectFieldUnits(p, pack, info, ownBlocks, fileBlocks, options),
|
|
8211
9446
|
controllerActions: (p) => controllerActionUnits(p, pack, info, ownBlocks, fileBlocks, options)
|
|
8212
9447
|
};
|
|
8213
|
-
return (0,
|
|
9448
|
+
return (0, import_behavioral_ir6.dispatchByType)(table, pattern);
|
|
8214
9449
|
}
|
|
8215
9450
|
async function graphqlObjectFieldUnits(pattern, pack, info, ownBlocks, fileBlocks, options) {
|
|
8216
9451
|
if (info.bodyNode === null || pattern.baseClassNames.includes(info.qualifiedName)) {
|
|
@@ -8257,6 +9492,7 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
8257
9492
|
}
|
|
8258
9493
|
const lookup = {
|
|
8259
9494
|
root: pattern.root,
|
|
9495
|
+
autoloadRoots: pattern.autoloadRoots ?? [],
|
|
8260
9496
|
pathConvention: pattern.pathConvention,
|
|
8261
9497
|
acronyms: pattern.acronyms ?? [],
|
|
8262
9498
|
ancestryRootClassNames: pattern.ancestryRootClassNames,
|
|
@@ -8271,11 +9507,12 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
8271
9507
|
])) {
|
|
8272
9508
|
return [];
|
|
8273
9509
|
}
|
|
8274
|
-
const
|
|
9510
|
+
const chain = controllerFilterChain(pattern, ancestry, {
|
|
8275
9511
|
facts: options.facts,
|
|
8276
9512
|
bodyBlocks: options.bodyBlocks,
|
|
8277
9513
|
dynamicNames: options.dynamicNames
|
|
8278
9514
|
});
|
|
9515
|
+
const filters = chain.flatMap((link) => "read" in link ? [link.read] : []);
|
|
8279
9516
|
const units = [];
|
|
8280
9517
|
const actions = controllerActions(
|
|
8281
9518
|
pattern,
|
|
@@ -8295,15 +9532,41 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
8295
9532
|
options.facts,
|
|
8296
9533
|
options.storage
|
|
8297
9534
|
);
|
|
9535
|
+
const respondingHelper = respondingHelpersOf(ancestry, pattern, options);
|
|
9536
|
+
const exceptions = new ExceptionReader(
|
|
9537
|
+
lookup,
|
|
9538
|
+
pattern.libraryExceptions ?? {}
|
|
9539
|
+
);
|
|
9540
|
+
const caught = await handlerClasses(filters, exceptions);
|
|
9541
|
+
const handlersAround = (actionName) => filters.filter((filter) => filterCoversAction(filter, actionName)).flatMap((filter) => {
|
|
9542
|
+
const classes = caught.get(filter);
|
|
9543
|
+
return classes === void 0 ? [] : [classes];
|
|
9544
|
+
});
|
|
8298
9545
|
for (const filter of filters) {
|
|
8299
|
-
const
|
|
8300
|
-
const
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
9546
|
+
const displayPath2 = options.displayPathOf?.(filter.file) ?? filter.file;
|
|
9547
|
+
const body = bodyOfMethod(filter.method, filter.file, options);
|
|
9548
|
+
const handler = filter.filter.onThrow === true;
|
|
9549
|
+
const raw = filterUnit(filter, pattern, displayPath2, body, {
|
|
9550
|
+
facts: options.facts,
|
|
9551
|
+
respondingHelper,
|
|
9552
|
+
...handler ? {} : {
|
|
9553
|
+
raises: {
|
|
9554
|
+
classes: await raisedClasses(
|
|
9555
|
+
filter.method,
|
|
9556
|
+
filter.nesting,
|
|
9557
|
+
exceptions
|
|
9558
|
+
),
|
|
9559
|
+
handlers: "eachRoute"
|
|
9560
|
+
},
|
|
9561
|
+
raised: raisedStatusBranches(
|
|
9562
|
+
pattern,
|
|
9563
|
+
options.storage?.patterns ?? [],
|
|
9564
|
+
body.extraEffects,
|
|
9565
|
+
"eachRoute",
|
|
9566
|
+
rangeOf(filter.method)
|
|
9567
|
+
)
|
|
9568
|
+
}
|
|
9569
|
+
});
|
|
8307
9570
|
units.push(raw);
|
|
8308
9571
|
options.onReachSeed?.(raw, {
|
|
8309
9572
|
file: filter.file,
|
|
@@ -8311,38 +9574,71 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
8311
9574
|
enclosingQualifiedName: filter.enclosingQualifiedName
|
|
8312
9575
|
});
|
|
8313
9576
|
}
|
|
8314
|
-
const
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
const
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
9577
|
+
const displayPath = (file) => options.displayPathOf?.(file) ?? file;
|
|
9578
|
+
const referenceTo = (link) => "read" in link ? filterReference(
|
|
9579
|
+
link.read,
|
|
9580
|
+
displayPath(link.read.file),
|
|
9581
|
+
caught.get(link.read)
|
|
9582
|
+
) : unreadFilterReference(link.unread, displayPath(link.unread.declaredIn));
|
|
9583
|
+
const emitAction = async (actionName, method, block, routes) => {
|
|
9584
|
+
const around = chain.filter((link) => filterCoversAction(filterOf(link), actionName)).map((link) => referenceTo(link));
|
|
9585
|
+
const raises2 = {
|
|
9586
|
+
classes: await raisedClasses(method, block.info.bodyNesting, exceptions),
|
|
9587
|
+
handlers: handlersAround(actionName)
|
|
9588
|
+
};
|
|
9589
|
+
for (const route of routes.length === 0 ? [null] : routes) {
|
|
9590
|
+
const raw = buildControllerActionUnit(
|
|
9591
|
+
pack,
|
|
9592
|
+
pattern,
|
|
9593
|
+
info.qualifiedName,
|
|
9594
|
+
actionName,
|
|
9595
|
+
route,
|
|
9596
|
+
method,
|
|
9597
|
+
{
|
|
9598
|
+
display: block.file === (options.absoluteFile ?? options.filePath) ? options.filePath : options.displayPathOf?.(block.file) ?? block.file,
|
|
9599
|
+
absolute: block.file
|
|
9600
|
+
},
|
|
9601
|
+
options,
|
|
9602
|
+
around,
|
|
9603
|
+
respondingHelper,
|
|
9604
|
+
raises2
|
|
9605
|
+
);
|
|
9606
|
+
units.push(raw);
|
|
9607
|
+
options.onReachSeed?.(raw, {
|
|
9608
|
+
file: block.file,
|
|
9609
|
+
node: method,
|
|
9610
|
+
enclosingQualifiedName: block.info.qualifiedName
|
|
9611
|
+
});
|
|
9612
|
+
}
|
|
8340
9613
|
};
|
|
8341
9614
|
for (const [actionName, method, block] of actions) {
|
|
8342
|
-
|
|
9615
|
+
const routes = pattern.routesFor(info.qualifiedName, actionName);
|
|
9616
|
+
await emitAction(actionName, method, block, routes);
|
|
8343
9617
|
}
|
|
8344
9618
|
return units;
|
|
8345
9619
|
}
|
|
9620
|
+
async function handlerClasses(filters, exceptions) {
|
|
9621
|
+
const caught = /* @__PURE__ */ new Map();
|
|
9622
|
+
for (const filter of filters) {
|
|
9623
|
+
if (filter.filter.onThrow !== true) {
|
|
9624
|
+
continue;
|
|
9625
|
+
}
|
|
9626
|
+
const classes = [];
|
|
9627
|
+
for (const ref of filter.rescues.refs) {
|
|
9628
|
+
classes.push(await exceptions.read(ref));
|
|
9629
|
+
}
|
|
9630
|
+
caught.set(filter, { classes, someUnread: filter.rescues.someUnread });
|
|
9631
|
+
}
|
|
9632
|
+
return caught;
|
|
9633
|
+
}
|
|
9634
|
+
async function raisedClasses(method, nesting, exceptions) {
|
|
9635
|
+
const classes = new NodeMap();
|
|
9636
|
+
for (const call of escapingRaises(method)) {
|
|
9637
|
+
const ref = raisedClassRef(call, nesting);
|
|
9638
|
+
classes.set(call, ref === null ? null : await exceptions.read(ref));
|
|
9639
|
+
}
|
|
9640
|
+
return classes;
|
|
9641
|
+
}
|
|
8346
9642
|
function controllerActions(pattern, info, ownBlocks, ancestry, options) {
|
|
8347
9643
|
const actions = publicInstanceMethods(ownBlocks, options.bodyBlocks);
|
|
8348
9644
|
const seen = new Set(actions.map(([actionName]) => actionName));
|
|
@@ -8359,7 +9655,7 @@ function controllerActions(pattern, info, ownBlocks, ancestry, options) {
|
|
|
8359
9655
|
continue;
|
|
8360
9656
|
}
|
|
8361
9657
|
seen.add(actionName);
|
|
8362
|
-
if (pattern.
|
|
9658
|
+
if (pattern.routesFor(info.qualifiedName, actionName).length > 0) {
|
|
8363
9659
|
actions.push(action);
|
|
8364
9660
|
}
|
|
8365
9661
|
}
|
|
@@ -8384,16 +9680,52 @@ function publicInstanceMethods(blocks, bodyBlocks) {
|
|
|
8384
9680
|
}
|
|
8385
9681
|
return found;
|
|
8386
9682
|
}
|
|
8387
|
-
function
|
|
9683
|
+
function respondingHelpersOf(ancestry, pattern, options) {
|
|
9684
|
+
const methods = /* @__PURE__ */ new Map();
|
|
9685
|
+
const known = /* @__PURE__ */ new Map();
|
|
9686
|
+
const declared = new Set(
|
|
9687
|
+
(pattern.responseStatusCalls ?? []).map((call) => call.name)
|
|
9688
|
+
);
|
|
9689
|
+
const methodNamed = (name) => {
|
|
9690
|
+
if (!methods.has(name)) {
|
|
9691
|
+
const found = methodInAncestry(ancestry, name, {
|
|
9692
|
+
facts: options.facts,
|
|
9693
|
+
bodyBlocks: options.bodyBlocks,
|
|
9694
|
+
dynamicNames: options.dynamicNames
|
|
9695
|
+
});
|
|
9696
|
+
methods.set(name, found.type === "found" ? found.method : null);
|
|
9697
|
+
}
|
|
9698
|
+
return methods.get(name) ?? null;
|
|
9699
|
+
};
|
|
9700
|
+
return (name, call) => {
|
|
9701
|
+
const method = declared.has(name) ? null : methodNamed(name);
|
|
9702
|
+
if (method === null) {
|
|
9703
|
+
return null;
|
|
9704
|
+
}
|
|
9705
|
+
const bound = boundStatusArguments(method, call, pattern, options.facts);
|
|
9706
|
+
const key = `${name}(${[...bound].join(",")})`;
|
|
9707
|
+
if (!known.has(key)) {
|
|
9708
|
+
known.set(key, helperResponse(method, pattern, options.facts, bound));
|
|
9709
|
+
}
|
|
9710
|
+
return known.get(key) ?? null;
|
|
9711
|
+
};
|
|
9712
|
+
}
|
|
9713
|
+
function servesFormat(pattern, route) {
|
|
9714
|
+
return pattern.optionalFormat === true && route.formatless !== true && !route.path.endsWith("/");
|
|
9715
|
+
}
|
|
9716
|
+
function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actionName, route, method, file, bodyRead, wrappers, respondingHelper, raises2) {
|
|
8388
9717
|
const range = rangeOf(method);
|
|
8389
|
-
const route = pattern.routeFor(controllerQualifiedName, actionName);
|
|
8390
9718
|
const body = bodyOfMethod(method, file.absolute, bodyRead);
|
|
8391
9719
|
const perResponse = responseBranches(
|
|
8392
9720
|
method,
|
|
8393
9721
|
pattern,
|
|
8394
9722
|
body.effects ?? [],
|
|
8395
9723
|
body.extraEffects,
|
|
8396
|
-
{
|
|
9724
|
+
{
|
|
9725
|
+
facts: bodyRead.facts,
|
|
9726
|
+
respondingHelper,
|
|
9727
|
+
raises: raises2
|
|
9728
|
+
}
|
|
8397
9729
|
);
|
|
8398
9730
|
return {
|
|
8399
9731
|
identity: {
|
|
@@ -8406,11 +9738,12 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
8406
9738
|
exportName: actionName,
|
|
8407
9739
|
exportPath: [controllerQualifiedName, actionName]
|
|
8408
9740
|
},
|
|
8409
|
-
boundaryBinding: route === null ? null : (0,
|
|
9741
|
+
boundaryBinding: route === null ? null : (0, import_behavioral_ir6.restBinding)({
|
|
8410
9742
|
transport: pack.protocol,
|
|
8411
9743
|
method: route.method,
|
|
8412
9744
|
path: route.path,
|
|
8413
|
-
recognition: pack.name
|
|
9745
|
+
recognition: pack.name,
|
|
9746
|
+
optionalFormat: servesFormat(pattern, route)
|
|
8414
9747
|
}),
|
|
8415
9748
|
parameters: [],
|
|
8416
9749
|
branches: withSlotSources(
|
|
@@ -8430,7 +9763,7 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
8430
9763
|
location: range
|
|
8431
9764
|
},
|
|
8432
9765
|
statusCodeReading: {
|
|
8433
|
-
reading:
|
|
9766
|
+
reading: import_extractor11.absentReading,
|
|
8434
9767
|
libraryDefault: pattern.defaultStatusCode
|
|
8435
9768
|
},
|
|
8436
9769
|
effects: body.effects ?? [],
|
|
@@ -8440,6 +9773,14 @@ function buildControllerActionUnit(pack, pattern, controllerQualifiedName, actio
|
|
|
8440
9773
|
}
|
|
8441
9774
|
],
|
|
8442
9775
|
body.provenance
|
|
9776
|
+
).concat(
|
|
9777
|
+
raisedStatusBranches(
|
|
9778
|
+
pattern,
|
|
9779
|
+
bodyRead.storage?.patterns ?? [],
|
|
9780
|
+
body.extraEffects,
|
|
9781
|
+
raises2.handlers,
|
|
9782
|
+
range
|
|
9783
|
+
)
|
|
8443
9784
|
),
|
|
8444
9785
|
bodyContent: body.bodyContent ?? "absent",
|
|
8445
9786
|
dependencyCalls: [],
|
|
@@ -8481,7 +9822,7 @@ function routingGapUnit(pattern, gaps) {
|
|
|
8481
9822
|
isDefault: true
|
|
8482
9823
|
}
|
|
8483
9824
|
],
|
|
8484
|
-
readings: gaps.map((gap) => (0,
|
|
9825
|
+
readings: gaps.map((gap) => (0, import_extractor11.unreadableReading)(gap, range)),
|
|
8485
9826
|
dependencyCalls: [],
|
|
8486
9827
|
declaredContract: null
|
|
8487
9828
|
};
|
|
@@ -8554,7 +9895,7 @@ var NO_METHOD_BEHIND_IT = {
|
|
|
8554
9895
|
readings: []
|
|
8555
9896
|
};
|
|
8556
9897
|
function methodNotSettled(reason, range) {
|
|
8557
|
-
return { readings: [(0,
|
|
9898
|
+
return { readings: [(0, import_extractor11.unreadableReading)(reason, range)] };
|
|
8558
9899
|
}
|
|
8559
9900
|
function bodyFromLookup(found, range, subject, nothingThere, bodyRead) {
|
|
8560
9901
|
const table = {
|
|
@@ -8572,7 +9913,7 @@ function bodyFromLookup(found, range, subject, nothingThere, bodyRead) {
|
|
|
8572
9913
|
),
|
|
8573
9914
|
none: () => nothingThere
|
|
8574
9915
|
};
|
|
8575
|
-
return (0,
|
|
9916
|
+
return (0, import_behavioral_ir6.dispatchByType)(table, found);
|
|
8576
9917
|
}
|
|
8577
9918
|
async function readFieldCall(stmt, scope, ctx, ancestry) {
|
|
8578
9919
|
if (stmt.type !== "call" || field(stmt, "receiver") !== null) {
|
|
@@ -8615,7 +9956,7 @@ function computedNameDeclaration(stmt, nameArg) {
|
|
|
8615
9956
|
contract: null,
|
|
8616
9957
|
body: {
|
|
8617
9958
|
readings: [
|
|
8618
|
-
(0,
|
|
9959
|
+
(0, import_extractor11.unreadableReading)(
|
|
8619
9960
|
`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
9961
|
range
|
|
8621
9962
|
)
|
|
@@ -8846,7 +10187,7 @@ function buildFieldUnit(pack, typeName, decl, filePath) {
|
|
|
8846
10187
|
exportName: null,
|
|
8847
10188
|
exportPath: null
|
|
8848
10189
|
},
|
|
8849
|
-
boundaryBinding: decl.namedOnTheWire ? (0,
|
|
10190
|
+
boundaryBinding: decl.namedOnTheWire ? (0, import_behavioral_ir6.graphqlResolverBinding)({
|
|
8850
10191
|
transport: pack.protocol,
|
|
8851
10192
|
recognition: pack.name,
|
|
8852
10193
|
typeName,
|
|
@@ -9262,15 +10603,15 @@ function parseWith(language, source) {
|
|
|
9262
10603
|
// src/project.ts
|
|
9263
10604
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
9264
10605
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
9265
|
-
var
|
|
10606
|
+
var import_behavioral_ir9 = require("@suss/behavioral-ir");
|
|
9266
10607
|
var import_datalog3 = require("@suss/datalog");
|
|
9267
|
-
var
|
|
10608
|
+
var import_extractor19 = require("@suss/extractor");
|
|
9268
10609
|
var import_resolution16 = require("@suss/resolution");
|
|
9269
10610
|
|
|
9270
10611
|
// src/diagnostics.ts
|
|
9271
|
-
var
|
|
10612
|
+
var import_extractor12 = require("@suss/extractor");
|
|
9272
10613
|
function buildRubyExtractionReport(args) {
|
|
9273
|
-
return (0,
|
|
10614
|
+
return (0, import_extractor12.buildUngatedExtractionReport)({
|
|
9274
10615
|
packs: args.packs.map((pack) => ({
|
|
9275
10616
|
name: pack.name,
|
|
9276
10617
|
version: pack.version ?? null,
|
|
@@ -9283,9 +10624,9 @@ function buildRubyExtractionReport(args) {
|
|
|
9283
10624
|
}
|
|
9284
10625
|
|
|
9285
10626
|
// src/exits.ts
|
|
9286
|
-
var
|
|
10627
|
+
var import_extractor13 = require("@suss/extractor");
|
|
9287
10628
|
var import_resolution11 = require("@suss/resolution");
|
|
9288
|
-
var
|
|
10629
|
+
var import_values22 = require("@suss/values");
|
|
9289
10630
|
var EXIT_METHODS = /* @__PURE__ */ new Map([
|
|
9290
10631
|
["exit", 0],
|
|
9291
10632
|
["exit!", 1],
|
|
@@ -9294,14 +10635,14 @@ var EXIT_METHODS = /* @__PURE__ */ new Map([
|
|
|
9294
10635
|
var DEFERRED_BODY_TYPES3 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
9295
10636
|
function exitSites(root) {
|
|
9296
10637
|
const found = [];
|
|
9297
|
-
(0,
|
|
10638
|
+
(0, import_extractor13.walkDescendants)(root, null, children, {
|
|
9298
10639
|
at: (node) => {
|
|
9299
10640
|
const site = node.type === "call" ? exitSiteAt(node) : null;
|
|
9300
10641
|
if (site !== null) {
|
|
9301
10642
|
found.push(site);
|
|
9302
10643
|
}
|
|
9303
10644
|
},
|
|
9304
|
-
into: (node) => DEFERRED_BODY_TYPES3.has(node.type) ?
|
|
10645
|
+
into: (node) => DEFERRED_BODY_TYPES3.has(node.type) ? import_extractor13.SKIP_CHILDREN : null
|
|
9305
10646
|
});
|
|
9306
10647
|
return found;
|
|
9307
10648
|
}
|
|
@@ -9338,7 +10679,7 @@ function exitCodeOf(site, facts) {
|
|
|
9338
10679
|
if (written !== void 0) {
|
|
9339
10680
|
return { type: "literal", value: written };
|
|
9340
10681
|
}
|
|
9341
|
-
const value = (0,
|
|
10682
|
+
const value = (0, import_values22.constantOf)(evaluatedValue(code, facts));
|
|
9342
10683
|
return typeof value === "number" ? { type: "literal", value } : { type: "dynamic", sourceText: code.text };
|
|
9343
10684
|
}
|
|
9344
10685
|
function exitingBranches(method, effects, facts) {
|
|
@@ -9359,7 +10700,7 @@ function markExitCodeFunctions(summaries, exits, facts, workspaceRoot) {
|
|
|
9359
10700
|
(site) => site.code === null ? [] : [nodeId(file, site.code)]
|
|
9360
10701
|
)
|
|
9361
10702
|
);
|
|
9362
|
-
(0,
|
|
10703
|
+
(0, import_extractor13.markReturnsAsExitCode)(
|
|
9363
10704
|
summaries,
|
|
9364
10705
|
(0, import_resolution11.exitCodeFunctions)(facts, sinks),
|
|
9365
10706
|
workspaceRoot
|
|
@@ -9409,9 +10750,9 @@ function eventsOf(args, called, callbacks, db) {
|
|
|
9409
10750
|
|
|
9410
10751
|
// src/facts.ts
|
|
9411
10752
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
9412
|
-
var
|
|
10753
|
+
var import_extractor14 = require("@suss/extractor");
|
|
9413
10754
|
function emitRequireFacts(db, filePath, root, known) {
|
|
9414
|
-
(0,
|
|
10755
|
+
(0, import_extractor14.walkDescendants)(root, null, children, {
|
|
9415
10756
|
at: (node) => {
|
|
9416
10757
|
const target = requiredRelativePath(node);
|
|
9417
10758
|
if (target === null) {
|
|
@@ -9425,7 +10766,7 @@ function emitRequireFacts(db, filePath, root, known) {
|
|
|
9425
10766
|
db.add("importsFile", [filePath, resolved]);
|
|
9426
10767
|
}
|
|
9427
10768
|
},
|
|
9428
|
-
into: (node) => node.type === "argument_list" ?
|
|
10769
|
+
into: (node) => node.type === "argument_list" ? import_extractor14.SKIP_CHILDREN : null
|
|
9429
10770
|
});
|
|
9430
10771
|
}
|
|
9431
10772
|
function requiredRelativePath(node) {
|
|
@@ -9437,17 +10778,17 @@ function requiredRelativePath(node) {
|
|
|
9437
10778
|
}
|
|
9438
10779
|
|
|
9439
10780
|
// src/moduleSurface.ts
|
|
9440
|
-
var
|
|
9441
|
-
var
|
|
10781
|
+
var import_behavioral_ir8 = require("@suss/behavioral-ir");
|
|
10782
|
+
var import_extractor17 = require("@suss/extractor");
|
|
9442
10783
|
|
|
9443
10784
|
// src/reach/closure.ts
|
|
9444
|
-
var
|
|
10785
|
+
var import_behavioral_ir7 = require("@suss/behavioral-ir");
|
|
9445
10786
|
var import_datalog2 = require("@suss/datalog");
|
|
9446
|
-
var
|
|
10787
|
+
var import_extractor16 = require("@suss/extractor");
|
|
9447
10788
|
var import_resolution13 = require("@suss/resolution");
|
|
9448
10789
|
|
|
9449
10790
|
// src/flags.ts
|
|
9450
|
-
var
|
|
10791
|
+
var import_extractor15 = require("@suss/extractor");
|
|
9451
10792
|
var PARSE_METHODS = /* @__PURE__ */ new Set(["parse", "parse!", "permute", "permute!"]);
|
|
9452
10793
|
var DEFERRED_BODY_TYPES4 = /* @__PURE__ */ new Set(["method", "singleton_method", "lambda"]);
|
|
9453
10794
|
function optionParserFlagReads(method, parameterNames3) {
|
|
@@ -9476,9 +10817,9 @@ function optionParserFlagReads(method, parameterNames3) {
|
|
|
9476
10817
|
return reads;
|
|
9477
10818
|
}
|
|
9478
10819
|
function walkBody2(body, at) {
|
|
9479
|
-
(0,
|
|
10820
|
+
(0, import_extractor15.walkDescendants)(body, null, children, {
|
|
9480
10821
|
at,
|
|
9481
|
-
into: (node) => DEFERRED_BODY_TYPES4.has(node.type) ?
|
|
10822
|
+
into: (node) => DEFERRED_BODY_TYPES4.has(node.type) ? import_extractor15.SKIP_CHILDREN : null
|
|
9482
10823
|
});
|
|
9483
10824
|
}
|
|
9484
10825
|
var OPTION_PARSER_SPELLINGS = /* @__PURE__ */ new Set(["OptionParser", "::OptionParser"]);
|
|
@@ -9492,7 +10833,7 @@ function flagsDeclaredIn(construction) {
|
|
|
9492
10833
|
return [];
|
|
9493
10834
|
}
|
|
9494
10835
|
const flags = [];
|
|
9495
|
-
(0,
|
|
10836
|
+
(0, import_extractor15.walkDescendants)(block, null, children, {
|
|
9496
10837
|
at: (node) => {
|
|
9497
10838
|
if (node.type !== "call" || field(node, "method")?.text !== "on") {
|
|
9498
10839
|
return;
|
|
@@ -9507,8 +10848,8 @@ function flagsDeclaredIn(construction) {
|
|
|
9507
10848
|
return flags;
|
|
9508
10849
|
}
|
|
9509
10850
|
function flagOf(args) {
|
|
9510
|
-
const written = args.map((arg) => stringLiteralValue(arg)).filter((
|
|
9511
|
-
const chosen = written.find((
|
|
10851
|
+
const written = args.map((arg) => stringLiteralValue(arg)).filter((text3) => text3 !== null && text3.startsWith("-"));
|
|
10852
|
+
const chosen = written.find((text3) => text3.startsWith("--")) ?? written[0] ?? null;
|
|
9512
10853
|
if (chosen === null) {
|
|
9513
10854
|
return null;
|
|
9514
10855
|
}
|
|
@@ -9546,8 +10887,6 @@ function parserCalledOn(receiver, parserNamed) {
|
|
|
9546
10887
|
|
|
9547
10888
|
// src/reach/resolveCallee.ts
|
|
9548
10889
|
var import_resolution12 = require("@suss/resolution");
|
|
9549
|
-
var DYNAMIC_SEND_NAMES = /* @__PURE__ */ new Set(["send", "public_send", "__send__"]);
|
|
9550
|
-
var INVOKES_RECEIVER = "call";
|
|
9551
10890
|
var STOP_FOR = {
|
|
9552
10891
|
severalSources: "multipleSources",
|
|
9553
10892
|
outsideRun: "outsideRun",
|
|
@@ -9564,6 +10903,11 @@ var UNSETTLED_ON_SELF = {
|
|
|
9564
10903
|
reason: "noDeclaration",
|
|
9565
10904
|
matchByName: true
|
|
9566
10905
|
};
|
|
10906
|
+
var SELF_CALL_IN_MIXIN = {
|
|
10907
|
+
kind: "stopped",
|
|
10908
|
+
reason: "selfCallInMixin",
|
|
10909
|
+
matchByName: true
|
|
10910
|
+
};
|
|
9567
10911
|
function followed(target) {
|
|
9568
10912
|
return { kind: "followed", target };
|
|
9569
10913
|
}
|
|
@@ -9625,6 +10969,57 @@ function loaderSourceCallee(call, site, ctx) {
|
|
|
9625
10969
|
}
|
|
9626
10970
|
return null;
|
|
9627
10971
|
}
|
|
10972
|
+
function dispatchedCalls(calls, ctx) {
|
|
10973
|
+
const byKey = new Map(
|
|
10974
|
+
calls.map((one) => [nodeId(one.site.file, one.call), one])
|
|
10975
|
+
);
|
|
10976
|
+
const found = /* @__PURE__ */ new Map();
|
|
10977
|
+
const outcomes = (0, import_resolution12.dispatchOutcomes)(ctx.facts, [...byKey.keys()], RUBY_PROGRAM);
|
|
10978
|
+
for (const [key, outcome] of outcomes) {
|
|
10979
|
+
const asked = byKey.get(key);
|
|
10980
|
+
if (asked === void 0) {
|
|
10981
|
+
continue;
|
|
10982
|
+
}
|
|
10983
|
+
const fits = sendFits(asked.call, asked.site, ctx);
|
|
10984
|
+
const targets = /* @__PURE__ */ new Map();
|
|
10985
|
+
for (const fn of outcome.functions) {
|
|
10986
|
+
for (const target of reachedThrough(fn, outcome.through, ctx)) {
|
|
10987
|
+
if (fits(target)) {
|
|
10988
|
+
targets.set(nodeId(target.file, target.node), target);
|
|
10989
|
+
}
|
|
10990
|
+
}
|
|
10991
|
+
}
|
|
10992
|
+
found.set(asked.call.id, {
|
|
10993
|
+
targets: [...targets.values()],
|
|
10994
|
+
certain: outcome.certain && outcome.functions.every((fn) => ctx.definitions.has(fn)),
|
|
10995
|
+
unresolved: outcome.unresolved
|
|
10996
|
+
});
|
|
10997
|
+
}
|
|
10998
|
+
return found;
|
|
10999
|
+
}
|
|
11000
|
+
function reachedThrough(key, through, ctx) {
|
|
11001
|
+
const own = ctx.definitions.get(key);
|
|
11002
|
+
if (own !== void 0) {
|
|
11003
|
+
return [own];
|
|
11004
|
+
}
|
|
11005
|
+
return (through.get(key) ?? []).flatMap((inner) => {
|
|
11006
|
+
const target = ctx.definitions.get(inner);
|
|
11007
|
+
return target === void 0 ? [] : [target];
|
|
11008
|
+
});
|
|
11009
|
+
}
|
|
11010
|
+
function sendFits(call, site, ctx) {
|
|
11011
|
+
const method = calleeMethodName(call);
|
|
11012
|
+
if (method === void 0 || !SENDING_METHODS.has(method)) {
|
|
11013
|
+
return () => true;
|
|
11014
|
+
}
|
|
11015
|
+
const receiver = field(call, "receiver");
|
|
11016
|
+
const toClass = receiver === null || receiver.type === "self" ? inClassMethod(site, ctx) : readsOffClassItself(
|
|
11017
|
+
receiver,
|
|
11018
|
+
readKey(site.file, receiver, site.method),
|
|
11019
|
+
classLocalsFor(call, site)
|
|
11020
|
+
);
|
|
11021
|
+
return (target) => definesClassMethod(target.node, ctx.bodyBlocks) === toClass;
|
|
11022
|
+
}
|
|
9628
11023
|
function outcomeFor(key, ctx, read) {
|
|
9629
11024
|
return read?.outcomes.get(key) ?? (0, import_resolution12.calleeOutcomeOf)(ctx.facts, key, RUBY_PROGRAM);
|
|
9630
11025
|
}
|
|
@@ -9638,14 +11033,16 @@ function readsAsACall(call, site, ctx, read) {
|
|
|
9638
11033
|
return false;
|
|
9639
11034
|
}
|
|
9640
11035
|
const outcome = outcomeFor(spelling.key, ctx, read);
|
|
9641
|
-
return outcome.kind === "function" || outcome.kind === "object"
|
|
11036
|
+
return outcome.kind === "function" || outcome.kind === "object" || objectsBehind(ctx.facts, spelling.key).some(
|
|
11037
|
+
(key) => ctx.classNames.has(key)
|
|
11038
|
+
);
|
|
9642
11039
|
}
|
|
9643
11040
|
function spellingFor2(call, site) {
|
|
9644
11041
|
const methodName = calleeMethodName(call);
|
|
9645
11042
|
if (methodName === void 0) {
|
|
9646
11043
|
return { kind: "stopped", reason: "noDeclaration" };
|
|
9647
11044
|
}
|
|
9648
|
-
if (
|
|
11045
|
+
if (SENDING_METHODS.has(methodName)) {
|
|
9649
11046
|
return { kind: "stopped", reason: "unsettledValue" };
|
|
9650
11047
|
}
|
|
9651
11048
|
const receiver = field(call, "receiver");
|
|
@@ -9691,7 +11088,7 @@ function asCallee(spelling, outcome, site, ctx) {
|
|
|
9691
11088
|
return methodOnObject(spelling, objectKey, ctx);
|
|
9692
11089
|
}
|
|
9693
11090
|
if (outcome.kind === "function") {
|
|
9694
|
-
return spelling.method ===
|
|
11091
|
+
return spelling.method === INVOKE_METHOD ? functionCallee(outcome.key, ctx) : NO_DECLARATION;
|
|
9695
11092
|
}
|
|
9696
11093
|
return stop(STOP_FOR[outcome.kind] ?? "noDeclaration");
|
|
9697
11094
|
}
|
|
@@ -9735,7 +11132,7 @@ function scopeOn(qualifiedName, method, ctx) {
|
|
|
9735
11132
|
return null;
|
|
9736
11133
|
}
|
|
9737
11134
|
function fromCaller(spelling, parameterKey, site) {
|
|
9738
|
-
if (!parameterKey.startsWith(`${site.owner}#`) || spelling.method !==
|
|
11135
|
+
if (!parameterKey.startsWith(`${site.owner}#`) || spelling.method !== INVOKE_METHOD) {
|
|
9739
11136
|
return stop("unsettledValue");
|
|
9740
11137
|
}
|
|
9741
11138
|
return stop("callerSupplied");
|
|
@@ -9752,22 +11149,27 @@ function leavesRoomForATopLevelMethod(reason) {
|
|
|
9752
11149
|
return reason === "noDeclaration" || reason === "outsideRun";
|
|
9753
11150
|
}
|
|
9754
11151
|
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
|
-
}
|
|
11152
|
+
const onClass = site.enclosingQualifiedName === null ? null : methodOnSelf(site, site.enclosingQualifiedName, methodName, ctx);
|
|
11153
|
+
if (onClass !== null && (onClass.kind === "followed" || !leavesRoomForATopLevelMethod(onClass.reason))) {
|
|
11154
|
+
return onClass;
|
|
9765
11155
|
}
|
|
11156
|
+
const readWholeAncestry = onClass?.kind === "stopped" && onClass.reason === "noDeclaration";
|
|
9766
11157
|
const topLevel = resolveTopLevelName(methodName, ctx);
|
|
9767
11158
|
if (topLevel.kind === "followed" || topLevel.reason !== "noDeclaration") {
|
|
9768
11159
|
return topLevel;
|
|
9769
11160
|
}
|
|
9770
|
-
|
|
11161
|
+
if (declaredForTheOtherSelf(site, methodName, ctx)) {
|
|
11162
|
+
return NO_DECLARATION;
|
|
11163
|
+
}
|
|
11164
|
+
return readWholeAncestry && !OBJECT_METHODS.has(methodName) && inModuleInstanceMethod(site, ctx) ? SELF_CALL_IN_MIXIN : UNSETTLED_ON_SELF;
|
|
11165
|
+
}
|
|
11166
|
+
function inModuleInstanceMethod(site, ctx) {
|
|
11167
|
+
const qualifiedName = site.enclosingQualifiedName;
|
|
11168
|
+
if (qualifiedName === null || site.method === null || inClassMethod(site, ctx)) {
|
|
11169
|
+
return false;
|
|
11170
|
+
}
|
|
11171
|
+
const own = ctx.ancestries.get(qualifiedName)?.[0];
|
|
11172
|
+
return own?.type === "bodies" && own.blocks.every((block) => block.info.kind === "module");
|
|
9771
11173
|
}
|
|
9772
11174
|
function declaredForTheOtherSelf(site, methodName, ctx) {
|
|
9773
11175
|
const qualifiedName = site.enclosingQualifiedName;
|
|
@@ -9810,12 +11212,16 @@ function methodOnAncestryOf(qualifiedName, methodName, ctx) {
|
|
|
9810
11212
|
return followed(reachedMethod(found.method, found.block, methodName));
|
|
9811
11213
|
}
|
|
9812
11214
|
if (found.type === "unsettled") {
|
|
9813
|
-
return stop(
|
|
9814
|
-
found.cause === "dynamicDefine" ? "definedAtLoadTime" : "outsideRun"
|
|
9815
|
-
);
|
|
11215
|
+
return stop(unsettledReason(found));
|
|
9816
11216
|
}
|
|
9817
11217
|
return NO_DECLARATION;
|
|
9818
11218
|
}
|
|
11219
|
+
function unsettledReason(found) {
|
|
11220
|
+
if (found.cause === "dynamicDefine") {
|
|
11221
|
+
return "definedAtLoadTime";
|
|
11222
|
+
}
|
|
11223
|
+
return found.definedLater === true ? "behindUnreadAncestor" : "outsideRun";
|
|
11224
|
+
}
|
|
9819
11225
|
function reachedMethod(node, block, name) {
|
|
9820
11226
|
return {
|
|
9821
11227
|
file: block.file,
|
|
@@ -9862,6 +11268,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
9862
11268
|
const targetsByKey = /* @__PURE__ */ new Map();
|
|
9863
11269
|
const stopsByKey = /* @__PURE__ */ new Map();
|
|
9864
11270
|
const argTargetsByKey = /* @__PURE__ */ new Map();
|
|
11271
|
+
const possibleTargetsByKey = /* @__PURE__ */ new Map();
|
|
9865
11272
|
const parameterCallsByKey = /* @__PURE__ */ new Map();
|
|
9866
11273
|
const propertyReadsByKey = /* @__PURE__ */ new Map();
|
|
9867
11274
|
const receiverClassesByKey = /* @__PURE__ */ new Map();
|
|
@@ -9920,6 +11327,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
9920
11327
|
}
|
|
9921
11328
|
targetsByKey.set(key, scan.targets);
|
|
9922
11329
|
argTargetsByKey.set(key, scan.argTargets);
|
|
11330
|
+
possibleTargetsByKey.set(key, scan.possibleTargets);
|
|
9923
11331
|
if (scan.propertyReads.size > 0) {
|
|
9924
11332
|
propertyReadsByKey.set(key, scan.propertyReads);
|
|
9925
11333
|
}
|
|
@@ -9975,15 +11383,16 @@ async function reachedFunctions(seeds, options) {
|
|
|
9975
11383
|
const build = () => {
|
|
9976
11384
|
const raw = libraryUnit(target, options);
|
|
9977
11385
|
dropPropertyReads(raw, propertyReadsByKey.get(key));
|
|
9978
|
-
const summary2 = (0,
|
|
11386
|
+
const summary2 = (0, import_extractor16.assembleSummary)(raw, { gapHandling });
|
|
9979
11387
|
if (gapHandling !== "silent") {
|
|
9980
11388
|
summary2.gaps.push(
|
|
9981
|
-
...(stopsByKey.get(key) ?? []).map(
|
|
11389
|
+
...(stopsByKey.get(key) ?? []).map(import_behavioral_ir7.unfollowedCallGap)
|
|
9982
11390
|
);
|
|
9983
11391
|
}
|
|
9984
|
-
(0,
|
|
9985
|
-
(0,
|
|
9986
|
-
(0,
|
|
11392
|
+
(0, import_behavioral_ir7.placeCalls)(summary2, targetsByKey.get(key));
|
|
11393
|
+
(0, import_behavioral_ir7.placeArgTargets)(summary2, argTargetsByKey.get(key));
|
|
11394
|
+
(0, import_behavioral_ir7.placePossibleCalls)(summary2, possibleTargetsByKey.get(key));
|
|
11395
|
+
(0, import_behavioral_ir7.placeCalleeParameters)(summary2, parameterCallsByKey.get(key));
|
|
9987
11396
|
return summary2;
|
|
9988
11397
|
};
|
|
9989
11398
|
const summary = ledger === void 0 ? build() : ledger.charging(chargeOf(charges, key), () => {
|
|
@@ -9998,13 +11407,14 @@ async function reachedFunctions(seeds, options) {
|
|
|
9998
11407
|
summaries.push(summary);
|
|
9999
11408
|
}
|
|
10000
11409
|
if (gapHandling !== "silent") {
|
|
10001
|
-
(0,
|
|
11410
|
+
(0, import_behavioral_ir7.recordParameterGaps)(parameterCallsByKey, summariesByKey, passedPositions);
|
|
10002
11411
|
}
|
|
10003
11412
|
return {
|
|
10004
11413
|
summaries,
|
|
10005
11414
|
targetsByKey,
|
|
10006
11415
|
stopsByKey,
|
|
10007
11416
|
argTargetsByKey,
|
|
11417
|
+
possibleTargetsByKey,
|
|
10008
11418
|
parameterCallsByKey,
|
|
10009
11419
|
propertyReadsByKey,
|
|
10010
11420
|
receiverClassesByKey,
|
|
@@ -10034,36 +11444,70 @@ function batchedReads(round, options) {
|
|
|
10034
11444
|
const bodies = round.flatMap(
|
|
10035
11445
|
(entry) => "source" in entry ? [{ key: entry.key, ...bodyOf2(entry.source, options) }] : []
|
|
10036
11446
|
);
|
|
10037
|
-
const
|
|
10038
|
-
|
|
10039
|
-
|
|
11447
|
+
const written = bodies.flatMap((body) => body.written);
|
|
11448
|
+
const spellings = calleeSpellings(written, options.context);
|
|
11449
|
+
const dispatched = dispatchedAmong(written, spellings, options.context);
|
|
11450
|
+
return new Map(
|
|
11451
|
+
bodies.map((body) => [body.key, { ...body, spellings, dispatched }])
|
|
11452
|
+
);
|
|
11453
|
+
}
|
|
11454
|
+
function dispatchedAmong(written, spellings, ctx) {
|
|
11455
|
+
return dispatchedCalls(
|
|
11456
|
+
written.filter(({ call, site }) => {
|
|
11457
|
+
if (!mayRunAnEntry(call)) {
|
|
11458
|
+
return false;
|
|
11459
|
+
}
|
|
11460
|
+
const outcome = resolveCallee(call, site, ctx, spellings);
|
|
11461
|
+
return outcome.kind === "stopped" && outcome.reason !== "callerSupplied";
|
|
11462
|
+
}),
|
|
11463
|
+
ctx
|
|
10040
11464
|
);
|
|
10041
|
-
|
|
11465
|
+
}
|
|
11466
|
+
function mayRunAnEntry(call) {
|
|
11467
|
+
const sent = calleeMethodName(call);
|
|
11468
|
+
if (sent !== void 0 && SENDING_METHODS.has(sent)) {
|
|
11469
|
+
return true;
|
|
11470
|
+
}
|
|
11471
|
+
if (call.type !== "call" || field(call, "receiver") === null) {
|
|
11472
|
+
return false;
|
|
11473
|
+
}
|
|
11474
|
+
const method = field(call, "method");
|
|
11475
|
+
return method === null || method.text === INVOKE_METHOD;
|
|
10042
11476
|
}
|
|
10043
11477
|
function scanOnce(source, key, options, read, charges) {
|
|
10044
11478
|
const ledger = options.ledger;
|
|
10045
11479
|
if (ledger === void 0) {
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
11480
|
+
return scanBody(
|
|
11481
|
+
source,
|
|
11482
|
+
options.context,
|
|
11483
|
+
options,
|
|
11484
|
+
read ?? ownReads(source, options)
|
|
11485
|
+
);
|
|
10051
11486
|
}
|
|
10052
11487
|
return ledger.charging(chargeOf(charges, key), () => {
|
|
10053
11488
|
forgetEvaluations(options.context.facts);
|
|
10054
11489
|
ledger.readFile(source.file);
|
|
10055
|
-
const
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
11490
|
+
const scan = scanBody(
|
|
11491
|
+
source,
|
|
11492
|
+
options.context,
|
|
11493
|
+
options,
|
|
11494
|
+
ownReads(source, options)
|
|
11495
|
+
);
|
|
10061
11496
|
for (const target of scan.followed) {
|
|
10062
11497
|
ledger.touchKey(keyOf(target));
|
|
10063
11498
|
}
|
|
10064
11499
|
return scan;
|
|
10065
11500
|
});
|
|
10066
11501
|
}
|
|
11502
|
+
function ownReads(source, options) {
|
|
11503
|
+
const body = bodyOf2(source, options);
|
|
11504
|
+
const spellings = calleeSpellings(body.written, options.context);
|
|
11505
|
+
return {
|
|
11506
|
+
...body,
|
|
11507
|
+
spellings,
|
|
11508
|
+
dispatched: dispatchedAmong(body.written, spellings, options.context)
|
|
11509
|
+
};
|
|
11510
|
+
}
|
|
10067
11511
|
function storedScan(scan) {
|
|
10068
11512
|
return {
|
|
10069
11513
|
followed: scan.followed.map((target) => ({
|
|
@@ -10079,6 +11523,10 @@ function storedScan(scan) {
|
|
|
10079
11523
|
callee,
|
|
10080
11524
|
[...byPosition]
|
|
10081
11525
|
]),
|
|
11526
|
+
possibleTargets: [...scan.possibleTargets].map(([callee, places]) => [
|
|
11527
|
+
callee,
|
|
11528
|
+
[...places]
|
|
11529
|
+
]),
|
|
10082
11530
|
parameterCalls: [...scan.parameterCalls],
|
|
10083
11531
|
passedPositions: [...scan.passedPositions],
|
|
10084
11532
|
propertyReads: [...scan.propertyReads],
|
|
@@ -10096,6 +11544,7 @@ function scanFromStored(stored, functionFor) {
|
|
|
10096
11544
|
new Map(byPosition)
|
|
10097
11545
|
])
|
|
10098
11546
|
),
|
|
11547
|
+
possibleTargets: new Map(stored.possibleTargets),
|
|
10099
11548
|
parameterCalls: stored.parameterCalls,
|
|
10100
11549
|
passedPositions: new Set(stored.passedPositions),
|
|
10101
11550
|
propertyReads: new Set(stored.propertyReads),
|
|
@@ -10124,6 +11573,7 @@ var EMPTY_SCAN = {
|
|
|
10124
11573
|
stops: [],
|
|
10125
11574
|
targets: /* @__PURE__ */ new Map(),
|
|
10126
11575
|
argTargets: /* @__PURE__ */ new Map(),
|
|
11576
|
+
possibleTargets: /* @__PURE__ */ new Map(),
|
|
10127
11577
|
parameterCalls: [],
|
|
10128
11578
|
passedPositions: /* @__PURE__ */ new Set(),
|
|
10129
11579
|
propertyReads: /* @__PURE__ */ new Set(),
|
|
@@ -10145,7 +11595,7 @@ function bodyOf2(source, options) {
|
|
|
10145
11595
|
const file = run?.fileOf(call) ?? source.file;
|
|
10146
11596
|
return file === source.file ? site : { ...site, file, method: enclosingDefinition(call) };
|
|
10147
11597
|
};
|
|
10148
|
-
const written =
|
|
11598
|
+
const written = callsWrittenIn2(source.node, run, options);
|
|
10149
11599
|
const calls = callsReported(
|
|
10150
11600
|
written,
|
|
10151
11601
|
(call) => mightReadAsACall(call, siteFor(call), options.context)
|
|
@@ -10159,7 +11609,7 @@ function bodyOf2(source, options) {
|
|
|
10159
11609
|
written: calls.map((call) => ({ call, site: siteFor(call) }))
|
|
10160
11610
|
};
|
|
10161
11611
|
}
|
|
10162
|
-
function
|
|
11612
|
+
function callsWrittenIn2(node, run, options) {
|
|
10163
11613
|
if (run !== null) {
|
|
10164
11614
|
return exampleCalls(run, options.inheritedMethods).filter(
|
|
10165
11615
|
(call) => !run.isRunnerCall(call)
|
|
@@ -10211,9 +11661,9 @@ function scanBody(source, ctx, options, read) {
|
|
|
10211
11661
|
);
|
|
10212
11662
|
const ownParameters = positionalParameters(source.node).map((p) => p.name);
|
|
10213
11663
|
const followed2 = [];
|
|
10214
|
-
const stops =
|
|
10215
|
-
const placements = new
|
|
10216
|
-
const receiverClasses = new
|
|
11664
|
+
const stops = new import_behavioral_ir7.StopList();
|
|
11665
|
+
const placements = new import_behavioral_ir7.TargetPlacements();
|
|
11666
|
+
const receiverClasses = new import_behavioral_ir7.ReceiverClasses();
|
|
10217
11667
|
const parameterCalls = [];
|
|
10218
11668
|
const passedPositions = /* @__PURE__ */ new Set();
|
|
10219
11669
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -10226,6 +11676,12 @@ function scanBody(source, ctx, options, read) {
|
|
|
10226
11676
|
}
|
|
10227
11677
|
const argNodes = bodyStatements(args);
|
|
10228
11678
|
for (let position = 0; position < argNodes.length; position += 1) {
|
|
11679
|
+
if (argNodes[position]?.type === LAMBDA_TYPE) {
|
|
11680
|
+
if (calleeKey !== null) {
|
|
11681
|
+
passedPositions.add(`${calleeKey}#${position}`);
|
|
11682
|
+
}
|
|
11683
|
+
continue;
|
|
11684
|
+
}
|
|
10229
11685
|
const symbol = methodReferenceSymbol(argNodes[position]);
|
|
10230
11686
|
if (symbol === null) {
|
|
10231
11687
|
continue;
|
|
@@ -10263,11 +11719,35 @@ function scanBody(source, ctx, options, read) {
|
|
|
10263
11719
|
span: spanOf(target.node)
|
|
10264
11720
|
});
|
|
10265
11721
|
};
|
|
11722
|
+
const follow = (target) => {
|
|
11723
|
+
const key = keyOf(target);
|
|
11724
|
+
if (!seen.has(key)) {
|
|
11725
|
+
seen.add(key);
|
|
11726
|
+
followed2.push(target);
|
|
11727
|
+
}
|
|
11728
|
+
};
|
|
10266
11729
|
for (const call of calls) {
|
|
10267
11730
|
const callee = calleeText(call);
|
|
10268
11731
|
const callSite = read.siteFor(call);
|
|
10269
11732
|
const predicate = read.predicateOf(call);
|
|
10270
|
-
const
|
|
11733
|
+
const settled = predicate === null ? resolveCallee(call, callSite, ctx, read.spellings) : resolveMethodOn(predicate.target, predicate.method, callSite, ctx);
|
|
11734
|
+
const dispatched = settled.kind === "stopped" ? read.dispatched.get(call.id) : void 0;
|
|
11735
|
+
const [only] = dispatched?.targets ?? [];
|
|
11736
|
+
if (dispatched !== void 0 && only !== void 0 && !dispatched.certain) {
|
|
11737
|
+
dispatched.targets.forEach(follow);
|
|
11738
|
+
placements.placePossible(
|
|
11739
|
+
callee,
|
|
11740
|
+
dispatched.targets.map((target) => ({
|
|
11741
|
+
file: displayPathOf(target.file),
|
|
11742
|
+
span: spanOf(target.node)
|
|
11743
|
+
}))
|
|
11744
|
+
);
|
|
11745
|
+
if (dispatched.unresolved > 0) {
|
|
11746
|
+
stops.add({ callee, reason: "unsettledValue" });
|
|
11747
|
+
}
|
|
11748
|
+
continue;
|
|
11749
|
+
}
|
|
11750
|
+
const outcome = only === void 0 ? settled : { kind: "followed", target: only };
|
|
10271
11751
|
if (options.storage !== void 0) {
|
|
10272
11752
|
for (const callback of callbacksReached(
|
|
10273
11753
|
call,
|
|
@@ -10295,11 +11775,13 @@ function scanBody(source, ctx, options, read) {
|
|
|
10295
11775
|
outcome.kind === "followed" ? keyOf(outcome.target) : null
|
|
10296
11776
|
);
|
|
10297
11777
|
if (outcome.kind === "stopped") {
|
|
10298
|
-
const stopKey = `${outcome.reason}:${callee}`;
|
|
10299
11778
|
const claimed = options.storage !== void 0 && storageClaims(call, callSite.file, options.storage, callSite.method);
|
|
10300
|
-
if (!
|
|
10301
|
-
|
|
10302
|
-
|
|
11779
|
+
if (!claimed && (0, import_behavioral_ir7.worthRecording)(outcome.reason)) {
|
|
11780
|
+
stops.add({
|
|
11781
|
+
callee,
|
|
11782
|
+
reason: outcome.reason,
|
|
11783
|
+
...resultUsedAsValue(call) ? { usedAsValue: true } : {}
|
|
11784
|
+
});
|
|
10303
11785
|
}
|
|
10304
11786
|
if (outcome.reason === "callerSupplied" && !parameterCallsSeen.has(callee)) {
|
|
10305
11787
|
const receiverName = field(call, "receiver")?.text;
|
|
@@ -10314,17 +11796,14 @@ function scanBody(source, ctx, options, read) {
|
|
|
10314
11796
|
if (isArglessReceiverCall(call)) {
|
|
10315
11797
|
keptArgless.add(call.id);
|
|
10316
11798
|
}
|
|
10317
|
-
|
|
10318
|
-
if (!seen.has(key)) {
|
|
10319
|
-
seen.add(key);
|
|
10320
|
-
followed2.push(outcome.target);
|
|
10321
|
-
}
|
|
11799
|
+
follow(outcome.target);
|
|
10322
11800
|
}
|
|
10323
11801
|
return {
|
|
10324
11802
|
followed: followed2,
|
|
10325
|
-
stops,
|
|
11803
|
+
stops: stops.stops,
|
|
10326
11804
|
targets: placements.targets,
|
|
10327
11805
|
argTargets: placements.argTargets,
|
|
11806
|
+
possibleTargets: placements.possibleTargets,
|
|
10328
11807
|
parameterCalls,
|
|
10329
11808
|
passedPositions,
|
|
10330
11809
|
propertyReads: propertyReadsAmong(read.argless, calls, keptArgless),
|
|
@@ -10356,14 +11835,14 @@ function propertyReadsAmong(argless, made, keptArgless) {
|
|
|
10356
11835
|
);
|
|
10357
11836
|
const reads = /* @__PURE__ */ new Set();
|
|
10358
11837
|
for (const call of argless) {
|
|
10359
|
-
const
|
|
10360
|
-
if (!kept.has(
|
|
10361
|
-
reads.add(
|
|
11838
|
+
const text3 = calleeText(call);
|
|
11839
|
+
if (!kept.has(text3)) {
|
|
11840
|
+
reads.add(text3);
|
|
10362
11841
|
}
|
|
10363
11842
|
}
|
|
10364
11843
|
return reads;
|
|
10365
11844
|
}
|
|
10366
|
-
function libraryUnit(target, options, binding = (0,
|
|
11845
|
+
function libraryUnit(target, options, binding = (0, import_behavioral_ir7.functionCallBinding)({
|
|
10367
11846
|
transport: "in-process",
|
|
10368
11847
|
recognition: "reachable"
|
|
10369
11848
|
})) {
|
|
@@ -10448,10 +11927,10 @@ function parameterName(param) {
|
|
|
10448
11927
|
|
|
10449
11928
|
// src/moduleSurface.ts
|
|
10450
11929
|
function settleRubyModules(modules) {
|
|
10451
|
-
return (0,
|
|
11930
|
+
return (0, import_extractor17.settleModules)(modules, ["{name}.rb", "../{name}.rb"]);
|
|
10452
11931
|
}
|
|
10453
11932
|
function moduleExportUnits(root, file, options) {
|
|
10454
|
-
const module2 = (0,
|
|
11933
|
+
const module2 = (0, import_extractor17.moduleOfFile)(options.modules, file);
|
|
10455
11934
|
if (module2 === void 0 || !module2.public.includes(file)) {
|
|
10456
11935
|
return [];
|
|
10457
11936
|
}
|
|
@@ -10478,8 +11957,8 @@ function moduleExportUnits(root, file, options) {
|
|
|
10478
11957
|
exportPath: [info.qualifiedName, method]
|
|
10479
11958
|
},
|
|
10480
11959
|
options,
|
|
10481
|
-
(0,
|
|
10482
|
-
recognition:
|
|
11960
|
+
(0, import_behavioral_ir8.moduleExportBinding)({
|
|
11961
|
+
recognition: import_extractor17.MODULE_SURFACE_RECOGNITION,
|
|
10483
11962
|
module: module2.name,
|
|
10484
11963
|
exportName: name
|
|
10485
11964
|
})
|
|
@@ -10787,11 +12266,11 @@ var WalkReplay = class {
|
|
|
10787
12266
|
};
|
|
10788
12267
|
|
|
10789
12268
|
// src/testFactories.ts
|
|
10790
|
-
var
|
|
12269
|
+
var import_values29 = require("@suss/values");
|
|
10791
12270
|
function factoriesIn(packs) {
|
|
10792
12271
|
return packs.flatMap((pack) => pack.factories ?? []);
|
|
10793
12272
|
}
|
|
10794
|
-
function emitFactoryFacts(db, files,
|
|
12273
|
+
function emitFactoryFacts(db, files, isTestFile2, patterns, inflections) {
|
|
10795
12274
|
for (const pattern of patterns) {
|
|
10796
12275
|
const definitions = /* @__PURE__ */ new Map();
|
|
10797
12276
|
for (const { file, root } of files) {
|
|
@@ -10799,7 +12278,7 @@ function emitFactoryFacts(db, files, isTestFile, patterns, inflections) {
|
|
|
10799
12278
|
}
|
|
10800
12279
|
const classes = new FactoryClasses(db, definitions, inflections);
|
|
10801
12280
|
for (const { file, root } of files) {
|
|
10802
|
-
if (!
|
|
12281
|
+
if (!isTestFile2(file)) {
|
|
10803
12282
|
continue;
|
|
10804
12283
|
}
|
|
10805
12284
|
for (const [call, name] of buildsIn(db, root, pattern)) {
|
|
@@ -10849,7 +12328,7 @@ function classRefOf(db, file, node) {
|
|
|
10849
12328
|
if (node.type === "constant" || node.type === "scope_resolution") {
|
|
10850
12329
|
return { key: readKey(file, node, null) };
|
|
10851
12330
|
}
|
|
10852
|
-
const written = (0,
|
|
12331
|
+
const written = (0, import_values29.literalOf)(evaluatedValue(node, db));
|
|
10853
12332
|
if (written === null) {
|
|
10854
12333
|
return null;
|
|
10855
12334
|
}
|
|
@@ -10858,7 +12337,7 @@ function classRefOf(db, file, node) {
|
|
|
10858
12337
|
};
|
|
10859
12338
|
}
|
|
10860
12339
|
function nameOf(db, node) {
|
|
10861
|
-
return symbolValue(node) ?? (0,
|
|
12340
|
+
return symbolValue(node) ?? (0, import_values29.literalOf)(evaluatedValue(node, db));
|
|
10862
12341
|
}
|
|
10863
12342
|
var FactoryClasses = class {
|
|
10864
12343
|
constructor(db, definitions, inflections) {
|
|
@@ -10930,7 +12409,7 @@ function builtAt(db, call, pattern) {
|
|
|
10930
12409
|
|
|
10931
12410
|
// src/testSharedGroups.ts
|
|
10932
12411
|
var import_resolution15 = require("@suss/resolution");
|
|
10933
|
-
var
|
|
12412
|
+
var import_values31 = require("@suss/values");
|
|
10934
12413
|
var ByNode = class {
|
|
10935
12414
|
byTree = /* @__PURE__ */ new WeakMap();
|
|
10936
12415
|
set(node, value) {
|
|
@@ -11034,7 +12513,7 @@ var SharedGroupIndex = class {
|
|
|
11034
12513
|
}
|
|
11035
12514
|
nameOf(call) {
|
|
11036
12515
|
const first = firstArgument(call);
|
|
11037
|
-
return first === null ? null : (0,
|
|
12516
|
+
return first === null ? null : (0, import_values31.literalOf)(evaluatedValue(first, this.db));
|
|
11038
12517
|
}
|
|
11039
12518
|
noteRead(definition) {
|
|
11040
12519
|
if (definition !== null) {
|
|
@@ -11111,16 +12590,16 @@ function visibleAt(index, site, pattern) {
|
|
|
11111
12590
|
}
|
|
11112
12591
|
|
|
11113
12592
|
// src/version.ts
|
|
11114
|
-
var
|
|
12593
|
+
var import_extractor18 = require("@suss/extractor");
|
|
11115
12594
|
var ADAPTER_VERSION = "0.1.0";
|
|
11116
|
-
var adapterStamp = (0,
|
|
12595
|
+
var adapterStamp = (0, import_extractor18.createAdapterStamp)({
|
|
11117
12596
|
moduleUrl: importMetaUrl,
|
|
11118
12597
|
version: ADAPTER_VERSION
|
|
11119
12598
|
});
|
|
11120
12599
|
|
|
11121
12600
|
// src/project.ts
|
|
11122
12601
|
function keptRubyParses() {
|
|
11123
|
-
return new
|
|
12602
|
+
return new import_extractor19.KeptParses((root) => root.tree.delete());
|
|
11124
12603
|
}
|
|
11125
12604
|
async function parseRubyAhead(files, kept) {
|
|
11126
12605
|
for (const file of files) {
|
|
@@ -11225,7 +12704,7 @@ var RunFacts = class {
|
|
|
11225
12704
|
...this.testFiles.map(({ file }) => file),
|
|
11226
12705
|
...this.parsed.map(({ file }) => file).filter(
|
|
11227
12706
|
(file) => classTests.some(
|
|
11228
|
-
(one) => (0,
|
|
12707
|
+
(one) => (0, import_extractor19.matchesTestFileName)(file, one.filePatterns)
|
|
11229
12708
|
)
|
|
11230
12709
|
)
|
|
11231
12710
|
]);
|
|
@@ -11260,7 +12739,7 @@ function factsForFile(options) {
|
|
|
11260
12739
|
return facts.db;
|
|
11261
12740
|
}
|
|
11262
12741
|
function moduleInitUnit(options) {
|
|
11263
|
-
const raw = (0,
|
|
12742
|
+
const raw = (0, import_extractor19.moduleInitStructure)({
|
|
11264
12743
|
name: options.name,
|
|
11265
12744
|
file: options.file,
|
|
11266
12745
|
range: options.range,
|
|
@@ -11274,7 +12753,7 @@ function moduleInitUnit(options) {
|
|
|
11274
12753
|
}
|
|
11275
12754
|
function discoveredAs(raw) {
|
|
11276
12755
|
const reported = raw.identity.exportPath?.join(".") ?? raw.identity.name;
|
|
11277
|
-
const boundary = raw.boundaryBinding === null ? "" : (0,
|
|
12756
|
+
const boundary = raw.boundaryBinding === null ? "" : (0, import_behavioral_ir9.boundaryKey)(raw.boundaryBinding) ?? "";
|
|
11278
12757
|
return `${raw.identity.file}::${reported}::${raw.identity.range.start}::${boundary}`;
|
|
11279
12758
|
}
|
|
11280
12759
|
function replaysCleanly(units, discovered) {
|
|
@@ -11291,16 +12770,16 @@ function replaysCleanly(units, discovered) {
|
|
|
11291
12770
|
return true;
|
|
11292
12771
|
}
|
|
11293
12772
|
async function extractRubyProject(options) {
|
|
11294
|
-
const timer = options.onTiming !== void 0 ? (0,
|
|
12773
|
+
const timer = options.onTiming !== void 0 ? (0, import_extractor19.createTimer)() : (0, import_extractor19.noopTimer)();
|
|
11295
12774
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
11296
|
-
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ?
|
|
12775
|
+
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? (0, import_extractor19.extractionCacheDirFor)(options.projectRoot) : null)
|
|
11297
12776
|
);
|
|
11298
|
-
const layer = (0,
|
|
12777
|
+
const layer = (0, import_extractor19.createCacheLayer)(cacheDir);
|
|
11299
12778
|
const packsDigest = `${adapterStamp.packsDigest(
|
|
11300
12779
|
options.packs.map(
|
|
11301
12780
|
(pack) => pack.version !== void 0 ? { name: pack.name, version: pack.version } : { name: pack.name }
|
|
11302
12781
|
)
|
|
11303
|
-
)}|${(0,
|
|
12782
|
+
)}|${(0, import_extractor19.extractionConfigStamp)({
|
|
11304
12783
|
gapHandling: options.gapHandling,
|
|
11305
12784
|
workspaceRoot: options.workspaceRoot,
|
|
11306
12785
|
projectRoot: options.projectRoot,
|
|
@@ -11308,16 +12787,19 @@ async function extractRubyProject(options) {
|
|
|
11308
12787
|
})}`;
|
|
11309
12788
|
const input = {
|
|
11310
12789
|
files: cacheDir === null ? [] : options.files,
|
|
11311
|
-
adapterPacksDigest: cacheDir === null ? packsDigest : (0,
|
|
12790
|
+
adapterPacksDigest: cacheDir === null ? packsDigest : (0, import_extractor19.runDigest)(packsDigest, options.packs, options.files)
|
|
11312
12791
|
};
|
|
11313
12792
|
const lookup = await timer.timeAsync(
|
|
11314
12793
|
"cache.lookup",
|
|
11315
12794
|
() => layer.lookup(input)
|
|
11316
12795
|
);
|
|
12796
|
+
const composed = (stored) => (0, import_extractor19.composeWrappers)(stored, {
|
|
12797
|
+
gapHandling: options.gapHandling ?? "permissive"
|
|
12798
|
+
});
|
|
11317
12799
|
if (lookup.kind === "hit") {
|
|
11318
12800
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
11319
12801
|
options.onTiming?.(timer.report());
|
|
11320
|
-
return { summaries: lookup.summaries, facts: new import_datalog3.Database() };
|
|
12802
|
+
return { summaries: composed(lookup.summaries), facts: new import_datalog3.Database() };
|
|
11321
12803
|
}
|
|
11322
12804
|
const plan = lookup.diagnostic.missReason === "files-changed" ? await timer.timeAsync("cache.plan", () => layer.plan(input)) : null;
|
|
11323
12805
|
if (plan !== null && plan.changed.size === 0 && plan.removed.size === 0) {
|
|
@@ -11327,7 +12809,7 @@ async function extractRubyProject(options) {
|
|
|
11327
12809
|
}
|
|
11328
12810
|
options.onCacheDiagnostic?.({ kind: "hit" });
|
|
11329
12811
|
options.onTiming?.(timer.report());
|
|
11330
|
-
return { summaries: plan.allSummaries(), facts: new import_datalog3.Database() };
|
|
12812
|
+
return { summaries: composed(plan.allSummaries()), facts: new import_datalog3.Database() };
|
|
11331
12813
|
}
|
|
11332
12814
|
const cache = { timer, cacheDir, layer, input };
|
|
11333
12815
|
const records = plan === null ? null : (0, import_resolution16.recordsToReplay)(plan.roots, plan.changed, plan.removed);
|
|
@@ -11363,7 +12845,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11363
12845
|
const db = new import_datalog3.Database();
|
|
11364
12846
|
const summaries = [];
|
|
11365
12847
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
11366
|
-
const tallies = (0,
|
|
12848
|
+
const tallies = (0, import_extractor12.createPackTallies)(options.packs);
|
|
11367
12849
|
const ledger = cacheDir === null ? null : new import_resolution16.DependencyLedger(options.files);
|
|
11368
12850
|
const log = ledger === null ? null : new import_resolution16.FactLog(db, ledger);
|
|
11369
12851
|
if (ledger !== null) {
|
|
@@ -11465,7 +12947,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11465
12947
|
continue;
|
|
11466
12948
|
}
|
|
11467
12949
|
discovered.add(unit.dedup);
|
|
11468
|
-
(0,
|
|
12950
|
+
(0, import_extractor12.tallyUnit)(tallies, unit.recognition);
|
|
11469
12951
|
found.push({
|
|
11470
12952
|
replayed: unit.summary ?? null,
|
|
11471
12953
|
seedKey: unit.seed?.key ?? null
|
|
@@ -11546,7 +13028,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11546
13028
|
continue;
|
|
11547
13029
|
}
|
|
11548
13030
|
discovered.add(dedup);
|
|
11549
|
-
(0,
|
|
13031
|
+
(0, import_extractor12.tallyUnit)(tallies, recognition);
|
|
11550
13032
|
found.push({ raw, seedKey, draft: units[units.length - 1] });
|
|
11551
13033
|
if (seed !== void 0 && seedKey !== null && !seedKeys.has(seedKey)) {
|
|
11552
13034
|
seedKeys.add(seedKey);
|
|
@@ -11609,7 +13091,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11609
13091
|
}
|
|
11610
13092
|
const summary = timer.time(
|
|
11611
13093
|
"summarize",
|
|
11612
|
-
() => (0,
|
|
13094
|
+
() => (0, import_extractor19.assembleSummary)(routingGapUnit(pattern, gaps), { gapHandling })
|
|
11613
13095
|
);
|
|
11614
13096
|
summary.confidence = { source: "inferred_static", level: "low" };
|
|
11615
13097
|
found.push({ summary });
|
|
@@ -11665,7 +13147,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11665
13147
|
}
|
|
11666
13148
|
const summary = timer.time(
|
|
11667
13149
|
"summarize",
|
|
11668
|
-
() => (0,
|
|
13150
|
+
() => (0, import_extractor19.assembleSummary)(raw, { gapHandling })
|
|
11669
13151
|
);
|
|
11670
13152
|
summaries.push(summary);
|
|
11671
13153
|
assembledHere.add(summary);
|
|
@@ -11683,13 +13165,14 @@ async function runRuby(options, cache, previous) {
|
|
|
11683
13165
|
}
|
|
11684
13166
|
if (gapHandling !== "silent") {
|
|
11685
13167
|
summary.gaps.push(
|
|
11686
|
-
...(reached.stopsByKey.get(key) ?? []).map(
|
|
13168
|
+
...(reached.stopsByKey.get(key) ?? []).map(import_behavioral_ir9.unfollowedCallGap)
|
|
11687
13169
|
);
|
|
11688
13170
|
}
|
|
11689
|
-
(0,
|
|
11690
|
-
(0,
|
|
11691
|
-
(0,
|
|
11692
|
-
(0,
|
|
13171
|
+
(0, import_behavioral_ir9.placeCalls)(summary, reached.targetsByKey.get(key));
|
|
13172
|
+
(0, import_behavioral_ir9.placeArgTargets)(summary, reached.argTargetsByKey.get(key));
|
|
13173
|
+
(0, import_behavioral_ir9.placePossibleCalls)(summary, reached.possibleTargetsByKey.get(key));
|
|
13174
|
+
(0, import_behavioral_ir9.placeCalleeParameters)(summary, reached.parameterCallsByKey.get(key));
|
|
13175
|
+
(0, import_behavioral_ir9.placeReceiverClasses)(summary, reached.receiverClassesByKey.get(key));
|
|
11693
13176
|
}
|
|
11694
13177
|
}
|
|
11695
13178
|
if (ledger !== null) {
|
|
@@ -11698,7 +13181,7 @@ async function runRuby(options, cache, previous) {
|
|
|
11698
13181
|
}
|
|
11699
13182
|
}
|
|
11700
13183
|
if (gapHandling !== "silent") {
|
|
11701
|
-
(0,
|
|
13184
|
+
(0, import_behavioral_ir9.recordParameterGaps)(
|
|
11702
13185
|
reached.parameterCallsByKey,
|
|
11703
13186
|
summariesBySeed,
|
|
11704
13187
|
reached.passedPositions
|
|
@@ -11711,20 +13194,20 @@ async function runRuby(options, cache, previous) {
|
|
|
11711
13194
|
throw new ReplayFailed("");
|
|
11712
13195
|
}
|
|
11713
13196
|
const dependencies = (0, import_resolution16.importedFilesByFile)(db, displayPathOf);
|
|
11714
|
-
(0,
|
|
11715
|
-
(0,
|
|
13197
|
+
(0, import_extractor19.stampModuleImports)(summaries, (file) => dependencies.get(file) ?? []);
|
|
13198
|
+
(0, import_extractor19.stampModules)(summaries, declaredModules, options.workspaceRoot);
|
|
11716
13199
|
const idRoot = options.projectRoot ?? options.workspaceRoot;
|
|
11717
13200
|
for (const summary of summaries) {
|
|
11718
13201
|
const absoluteFile = options.workspaceRoot === void 0 ? summary.location.file : import_node_path4.default.resolve(options.workspaceRoot, summary.location.file);
|
|
11719
|
-
summary.identity.id = (0,
|
|
13202
|
+
summary.identity.id = (0, import_behavioral_ir9.summaryIdFromParts)({
|
|
11720
13203
|
workspace: void 0,
|
|
11721
13204
|
file: idRoot === void 0 ? absoluteFile : import_node_path4.default.relative(idRoot, absoluteFile),
|
|
11722
13205
|
name: summary.identity.name,
|
|
11723
13206
|
exportPath: summary.identity.exportPath
|
|
11724
13207
|
});
|
|
11725
13208
|
}
|
|
11726
|
-
(0,
|
|
11727
|
-
(0,
|
|
13209
|
+
(0, import_behavioral_ir9.disambiguateSummaryIds)(summaries);
|
|
13210
|
+
(0, import_behavioral_ir9.linkCallsToSummaries)(summaries);
|
|
11728
13211
|
const composed = timer.time("summarize", () => {
|
|
11729
13212
|
markExitCodeFunctions(
|
|
11730
13213
|
summaries,
|
|
@@ -11732,18 +13215,22 @@ async function runRuby(options, cache, previous) {
|
|
|
11732
13215
|
db,
|
|
11733
13216
|
options.workspaceRoot
|
|
11734
13217
|
);
|
|
11735
|
-
return (0,
|
|
13218
|
+
return (0, import_extractor19.composeWrappers)(summaries, { gapHandling });
|
|
11736
13219
|
});
|
|
13220
|
+
const walkedFiles = new Map(
|
|
13221
|
+
parsed.map(({ file }) => [displayPathOf(file), file])
|
|
13222
|
+
);
|
|
11737
13223
|
await timer.timeAsync("cache.write", async () => {
|
|
11738
|
-
if (cacheDir === null ||
|
|
13224
|
+
if (cacheDir === null || summaries.length === 0) {
|
|
11739
13225
|
return;
|
|
11740
13226
|
}
|
|
11741
13227
|
try {
|
|
11742
13228
|
await cache.layer.write(
|
|
11743
13229
|
cache.input,
|
|
11744
|
-
|
|
13230
|
+
summaries,
|
|
11745
13231
|
log === null || ledger === null || overBudget ? void 0 : rubyAttribution({
|
|
11746
|
-
|
|
13232
|
+
summaries,
|
|
13233
|
+
walkedFileOf: (locationFile) => walkedFiles.get(locationFile),
|
|
11747
13234
|
discoveries,
|
|
11748
13235
|
reached,
|
|
11749
13236
|
reuse,
|
|
@@ -11818,7 +13305,10 @@ function rubyAttribution(args) {
|
|
|
11818
13305
|
facts: args.facts.get(file) ?? { own: "", joined: "" }
|
|
11819
13306
|
}
|
|
11820
13307
|
}));
|
|
11821
|
-
return {
|
|
13308
|
+
return {
|
|
13309
|
+
roots,
|
|
13310
|
+
owners: (0, import_extractor19.ownersWhereWritten)(args.summaries, args.walkedFileOf)
|
|
13311
|
+
};
|
|
11822
13312
|
}
|
|
11823
13313
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["vendor", "node_modules", "tmp", ".git"]);
|
|
11824
13314
|
function findRubyFiles(root) {
|
|
@@ -11892,8 +13382,8 @@ function displayNameOf(node) {
|
|
|
11892
13382
|
if (node.type === "class" || node.type === "module") {
|
|
11893
13383
|
return field(node, "name")?.text ?? node.text;
|
|
11894
13384
|
}
|
|
11895
|
-
const
|
|
11896
|
-
return
|
|
13385
|
+
const text3 = node.text.split("\n")[0].trim();
|
|
13386
|
+
return text3.length > 40 ? `${text3.slice(0, 40)}...` : text3;
|
|
11897
13387
|
}
|
|
11898
13388
|
function width(node) {
|
|
11899
13389
|
return node.endIndex - node.startIndex;
|
|
@@ -11923,14 +13413,14 @@ var RubyWhySession = class {
|
|
|
11923
13413
|
* The smallest expression on `line` of `file` whose text is exactly
|
|
11924
13414
|
* `text`, or null.
|
|
11925
13415
|
*/
|
|
11926
|
-
findExpression(file, line,
|
|
13416
|
+
findExpression(file, line, text3) {
|
|
11927
13417
|
const root = this.rootOf(file);
|
|
11928
13418
|
if (root === null) {
|
|
11929
13419
|
return null;
|
|
11930
13420
|
}
|
|
11931
13421
|
let found = null;
|
|
11932
13422
|
const visit = (node) => {
|
|
11933
|
-
if (node.startPosition.row + 1 === line && node.text ===
|
|
13423
|
+
if (node.startPosition.row + 1 === line && node.text === text3) {
|
|
11934
13424
|
if (found === null || width(node) <= width(found)) {
|
|
11935
13425
|
found = node;
|
|
11936
13426
|
}
|
|
@@ -12011,7 +13501,7 @@ var RubyWhySession = class {
|
|
|
12011
13501
|
// src/stubEvidence.ts
|
|
12012
13502
|
var import_node_fs5 = __toESM(require("fs"), 1);
|
|
12013
13503
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
12014
|
-
var
|
|
13504
|
+
var import_extractor20 = require("@suss/extractor");
|
|
12015
13505
|
function bareLetters(name) {
|
|
12016
13506
|
return name.replaceAll(/[-_]/g, "").toLowerCase();
|
|
12017
13507
|
}
|
|
@@ -12035,14 +13525,14 @@ function requireTarget(node) {
|
|
|
12035
13525
|
}
|
|
12036
13526
|
function requireSitesIn(root, file) {
|
|
12037
13527
|
const found = [];
|
|
12038
|
-
(0,
|
|
13528
|
+
(0, import_extractor20.walkDescendants)(root, null, children, {
|
|
12039
13529
|
at: (node) => {
|
|
12040
13530
|
const target = requireTarget(node);
|
|
12041
13531
|
if (target !== null) {
|
|
12042
13532
|
found.push({ target, file, line: rangeOf(node).start });
|
|
12043
13533
|
}
|
|
12044
13534
|
},
|
|
12045
|
-
into: (node) => node.type === "argument_list" ?
|
|
13535
|
+
into: (node) => node.type === "argument_list" ? import_extractor20.SKIP_CHILDREN : null
|
|
12046
13536
|
});
|
|
12047
13537
|
return found;
|
|
12048
13538
|
}
|
|
@@ -12086,6 +13576,7 @@ async function rubyStubEvidence(options) {
|
|
|
12086
13576
|
bindEvaluator,
|
|
12087
13577
|
bodyStatements,
|
|
12088
13578
|
booleanLiteralValue,
|
|
13579
|
+
children,
|
|
12089
13580
|
collectFileConstants,
|
|
12090
13581
|
createConstantFileCache,
|
|
12091
13582
|
createFileCache,
|