@suss/adapter-ruby 0.34.1 → 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 +574 -160
- package/dist/index.d.cts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +586 -163
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -350,8 +350,8 @@ var VISIBILITY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
350
350
|
"protected",
|
|
351
351
|
"public"
|
|
352
352
|
]);
|
|
353
|
-
function visibilityKeyword(
|
|
354
|
-
return VISIBILITY_KEYWORDS.has(
|
|
353
|
+
function visibilityKeyword(text3) {
|
|
354
|
+
return VISIBILITY_KEYWORDS.has(text3) ? text3 : null;
|
|
355
355
|
}
|
|
356
356
|
function setVisibility(visibility, name, keyword) {
|
|
357
357
|
if (keyword === "public") {
|
|
@@ -621,8 +621,8 @@ function lowerAcronyms(word, acronyms) {
|
|
|
621
621
|
(_match, before, acronym) => `${before === void 0 ? "" : "_"}${acronym.toLowerCase()}`
|
|
622
622
|
);
|
|
623
623
|
}
|
|
624
|
-
function escapeRegExp(
|
|
625
|
-
return
|
|
624
|
+
function escapeRegExp(text3) {
|
|
625
|
+
return text3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
626
626
|
}
|
|
627
627
|
var PATH_CONVENTIONS = {
|
|
628
628
|
railsUnderscore: underscoreConstantPath
|
|
@@ -775,6 +775,15 @@ var OBJECT_METHODS = /* @__PURE__ */ new Set([
|
|
|
775
775
|
"warn",
|
|
776
776
|
"yield_self"
|
|
777
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";
|
|
778
787
|
var CONSTRUCTOR = "new";
|
|
779
788
|
|
|
780
789
|
// src/facts/resolve.ts
|
|
@@ -1376,6 +1385,9 @@ function add(emitter, relation, ...tuple) {
|
|
|
1376
1385
|
}
|
|
1377
1386
|
emitter.db.add(relation, tuple);
|
|
1378
1387
|
}
|
|
1388
|
+
function rowsOf(emitter) {
|
|
1389
|
+
return (relation, row) => add(emitter, relation, ...row);
|
|
1390
|
+
}
|
|
1379
1391
|
function valueKey(emitter, written, parent) {
|
|
1380
1392
|
return readKey(emitter.filePath, written, emitter.enclosing, parent);
|
|
1381
1393
|
}
|
|
@@ -1459,6 +1471,97 @@ function emitCall(emitter, site) {
|
|
|
1459
1471
|
}
|
|
1460
1472
|
emitCallArguments(emitter, site);
|
|
1461
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
|
+
}
|
|
1462
1565
|
}
|
|
1463
1566
|
function emitConversion(emitter, site) {
|
|
1464
1567
|
const { method, receiver, node } = site;
|
|
@@ -1532,7 +1635,6 @@ var SELF_READS = {
|
|
|
1532
1635
|
function classSpelling(name) {
|
|
1533
1636
|
return name === CONSTRUCTOR ? name : (0, import_resolution4.classMemberName)(name);
|
|
1534
1637
|
}
|
|
1535
|
-
var INVOKE_METHOD = "call";
|
|
1536
1638
|
function invokedValueOf(call) {
|
|
1537
1639
|
if (call.type !== "call") {
|
|
1538
1640
|
return null;
|
|
@@ -1578,6 +1680,7 @@ function emitArray(emitter, array) {
|
|
|
1578
1680
|
const objectKey = nodeId(emitter.filePath, array);
|
|
1579
1681
|
add(emitter, "objectValue", objectKey);
|
|
1580
1682
|
let position = 0;
|
|
1683
|
+
const entries = [];
|
|
1581
1684
|
for (const element of children(array)) {
|
|
1582
1685
|
add(
|
|
1583
1686
|
emitter,
|
|
@@ -1587,12 +1690,24 @@ function emitArray(emitter, array) {
|
|
|
1587
1690
|
valueKey(emitter, element, array)
|
|
1588
1691
|
);
|
|
1589
1692
|
position += 1;
|
|
1693
|
+
entries.push(writtenEntry(emitter, element, array));
|
|
1590
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 };
|
|
1591
1701
|
}
|
|
1592
1702
|
function emitHash(emitter, hash) {
|
|
1593
1703
|
const objectKey = nodeId(emitter.filePath, hash);
|
|
1594
1704
|
add(emitter, "objectValue", objectKey);
|
|
1705
|
+
const entries = [];
|
|
1595
1706
|
for (const pair of children(hash)) {
|
|
1707
|
+
if (SPREAD_TYPES.has(pair.type)) {
|
|
1708
|
+
entries.push(writtenEntry(emitter, pair, hash));
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1596
1711
|
if (pair.type !== "pair") {
|
|
1597
1712
|
continue;
|
|
1598
1713
|
}
|
|
@@ -1601,6 +1716,7 @@ function emitHash(emitter, hash) {
|
|
|
1601
1716
|
if (key === null || value === null) {
|
|
1602
1717
|
continue;
|
|
1603
1718
|
}
|
|
1719
|
+
entries.push(writtenEntry(emitter, value, pair));
|
|
1604
1720
|
const keyText = pairKeyText(key);
|
|
1605
1721
|
if (keyText === null) {
|
|
1606
1722
|
add(emitter, "holdsUnderKey", objectKey, valueKey(emitter, value, pair));
|
|
@@ -1614,32 +1730,66 @@ function emitHash(emitter, hash) {
|
|
|
1614
1730
|
valueKey(emitter, value, pair)
|
|
1615
1731
|
);
|
|
1616
1732
|
}
|
|
1733
|
+
(0, import_resolution4.addEntryRows)(rowsOf(emitter), objectKey, entries);
|
|
1617
1734
|
}
|
|
1618
1735
|
var BLOCK_TYPES3 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
1619
1736
|
var LOOP_METHODS = /* @__PURE__ */ new Set(["each", "each_with_index", "map"]);
|
|
1620
|
-
var
|
|
1621
|
-
function
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
}
|
|
1625
|
-
const receiver = field(call, "receiver");
|
|
1626
|
-
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");
|
|
1627
1741
|
if (receiver === null || method === null || !LOOP_METHODS.has(method.text)) {
|
|
1628
|
-
return
|
|
1742
|
+
return;
|
|
1629
1743
|
}
|
|
1630
|
-
const
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
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;
|
|
1751
|
+
}
|
|
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
|
+
);
|
|
1635
1771
|
}
|
|
1636
|
-
return {
|
|
1637
|
-
element,
|
|
1638
|
-
index: names[1] ?? "",
|
|
1639
|
-
overKey: nodeId(emitter.filePath, receiver)
|
|
1640
|
-
};
|
|
1641
1772
|
}
|
|
1642
|
-
function
|
|
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;
|
|
1790
|
+
}
|
|
1791
|
+
var DEFINE_METHOD_CALL = "define_method";
|
|
1792
|
+
function emitDynamicDefinition(emitter, call, type) {
|
|
1643
1793
|
if (emitter.selfKey === null || // A call inside a method runs when the method runs, not when the class loads.
|
|
1644
1794
|
emitter.enclosing !== null || type !== "call" || field(call, "receiver") !== null || field(call, "method")?.text !== DEFINE_METHOD_CALL) {
|
|
1645
1795
|
return;
|
|
@@ -1648,33 +1798,16 @@ function emitDynamicDefinition(emitter, call, type, turns) {
|
|
|
1648
1798
|
const first = args === null ? void 0 : children(args)[0];
|
|
1649
1799
|
const nameKey2 = nodeId(emitter.filePath, first ?? call);
|
|
1650
1800
|
add(emitter, "definesMethodFrom", emitter.selfKey, nameKey2);
|
|
1651
|
-
for (const turn of turns) {
|
|
1652
|
-
add(
|
|
1653
|
-
emitter,
|
|
1654
|
-
"nameTurnsOn",
|
|
1655
|
-
nameKey2,
|
|
1656
|
-
turn.element,
|
|
1657
|
-
turn.index,
|
|
1658
|
-
turn.overKey
|
|
1659
|
-
);
|
|
1660
|
-
}
|
|
1661
1801
|
}
|
|
1662
|
-
function walkExpressions(node,
|
|
1802
|
+
function walkExpressions(node, visit, nested = null) {
|
|
1663
1803
|
for (const child of children(node)) {
|
|
1664
1804
|
const type = child.type;
|
|
1665
1805
|
if (OWN_BODY_TYPES.has(type)) {
|
|
1666
1806
|
nested?.push(child);
|
|
1667
1807
|
continue;
|
|
1668
1808
|
}
|
|
1669
|
-
visit(child, type, node
|
|
1670
|
-
|
|
1671
|
-
walkExpressions(
|
|
1672
|
-
child,
|
|
1673
|
-
emitter,
|
|
1674
|
-
visit,
|
|
1675
|
-
nested,
|
|
1676
|
-
opened === null ? turns : [...turns, opened]
|
|
1677
|
-
);
|
|
1809
|
+
visit(child, type, node);
|
|
1810
|
+
walkExpressions(child, visit, nested);
|
|
1678
1811
|
}
|
|
1679
1812
|
}
|
|
1680
1813
|
var WRITTEN_KEY_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -1688,13 +1821,16 @@ function emitKeyedRead(emitter, site, container, key, keyParent) {
|
|
|
1688
1821
|
if (WRITTEN_KEY_TYPES.has(key.type)) {
|
|
1689
1822
|
return;
|
|
1690
1823
|
}
|
|
1824
|
+
const siteKey = nodeId(emitter.filePath, site);
|
|
1825
|
+
const containerKey = valueKey(emitter, container, site);
|
|
1691
1826
|
add(
|
|
1692
1827
|
emitter,
|
|
1693
1828
|
"readsKeyed",
|
|
1694
|
-
|
|
1695
|
-
|
|
1829
|
+
siteKey,
|
|
1830
|
+
containerKey,
|
|
1696
1831
|
valueKey(emitter, key, keyParent)
|
|
1697
1832
|
);
|
|
1833
|
+
add(emitter, "choosesEntry", siteKey, containerKey);
|
|
1698
1834
|
}
|
|
1699
1835
|
function emitKeyedElement(emitter, node, parent) {
|
|
1700
1836
|
const object = field(node, "object");
|
|
@@ -1755,14 +1891,14 @@ function raises(written, enclosing) {
|
|
|
1755
1891
|
return RAISING_METHODS2.has(field(node, "method")?.text ?? "") && (receiver === null || receiver.text === "Kernel");
|
|
1756
1892
|
}
|
|
1757
1893
|
function emitExpressionFacts(emitter, node) {
|
|
1758
|
-
emitDynamicDefinition(emitter, node, node.type
|
|
1759
|
-
walkExpressions(node,
|
|
1894
|
+
emitDynamicDefinition(emitter, node, node.type);
|
|
1895
|
+
walkExpressions(node, (child, type, parent) => {
|
|
1760
1896
|
const site = callSiteAt(emitter, child, type, parent);
|
|
1761
|
-
emitExpressionFact(emitter, child, type, parent,
|
|
1897
|
+
emitExpressionFact(emitter, child, type, parent, site);
|
|
1762
1898
|
});
|
|
1763
1899
|
}
|
|
1764
|
-
function emitExpressionFact(emitter, child, type, parent,
|
|
1765
|
-
emitDynamicDefinition(emitter, child, type
|
|
1900
|
+
function emitExpressionFact(emitter, child, type, parent, site) {
|
|
1901
|
+
emitDynamicDefinition(emitter, child, type);
|
|
1766
1902
|
if (site !== null) {
|
|
1767
1903
|
emitCall(emitter, site);
|
|
1768
1904
|
emitKeyedFetch(emitter, site);
|
|
@@ -1803,6 +1939,11 @@ function emitExpressionFact(emitter, child, type, parent, turns, site) {
|
|
|
1803
1939
|
}
|
|
1804
1940
|
if (BLOCK_TYPES3.has(type)) {
|
|
1805
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);
|
|
1806
1947
|
}
|
|
1807
1948
|
for (const branch of BRANCHES_OF[type]?.(child) ?? []) {
|
|
1808
1949
|
add(
|
|
@@ -1822,6 +1963,29 @@ function emitExpressionFact(emitter, child, type, parent, turns, site) {
|
|
|
1822
1963
|
emitParameterDefault(emitter, child);
|
|
1823
1964
|
}
|
|
1824
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
|
+
};
|
|
1825
1989
|
function emitBlockArgument(emitter, argument) {
|
|
1826
1990
|
const [handed] = children(argument);
|
|
1827
1991
|
if (handed !== void 0) {
|
|
@@ -2244,11 +2408,10 @@ function emitMethodFacts(emitter, method) {
|
|
|
2244
2408
|
const collecting = { ...inside, heldRows: expressionFacts };
|
|
2245
2409
|
walkExpressions(
|
|
2246
2410
|
body,
|
|
2247
|
-
|
|
2248
|
-
(child, type, parent, turns) => {
|
|
2411
|
+
(child, type, parent) => {
|
|
2249
2412
|
const site = callSiteAt(inside, child, type, parent);
|
|
2250
2413
|
emitBodyFact(bodyFacts, inside, funcKey, child, type, site);
|
|
2251
|
-
emitExpressionFact(collecting, child, type, parent,
|
|
2414
|
+
emitExpressionFact(collecting, child, type, parent, site);
|
|
2252
2415
|
},
|
|
2253
2416
|
nested
|
|
2254
2417
|
);
|
|
@@ -3728,8 +3891,24 @@ function literalElementsIn(value) {
|
|
|
3728
3891
|
}
|
|
3729
3892
|
return elements;
|
|
3730
3893
|
}
|
|
3731
|
-
function
|
|
3732
|
-
|
|
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
|
+
};
|
|
3733
3912
|
}
|
|
3734
3913
|
function namesOf(node, db) {
|
|
3735
3914
|
const value = evaluatedValue(node, db);
|
|
@@ -3751,13 +3930,16 @@ function definedNamesOf(dynamic, classKey) {
|
|
|
3751
3930
|
}
|
|
3752
3931
|
function readDynamicNames(db, rootsByFile) {
|
|
3753
3932
|
const byClass = /* @__PURE__ */ new Map();
|
|
3754
|
-
|
|
3933
|
+
const definitions = db.facts("definesMethodFrom");
|
|
3934
|
+
const loops = definitions.length === 0 ? /* @__PURE__ */ new Map() : loopsByFile(db);
|
|
3935
|
+
for (const [classKey, nameKey2] of definitions) {
|
|
3755
3936
|
const key = String(classKey);
|
|
3937
|
+
const around = loopsAround(loops, key, String(nameKey2));
|
|
3756
3938
|
byClass.set(
|
|
3757
3939
|
key,
|
|
3758
3940
|
foldReading(
|
|
3759
3941
|
byClass.get(key) ?? NOTHING,
|
|
3760
|
-
readOne(db, rootsByFile, String(nameKey2))
|
|
3942
|
+
readOne(db, rootsByFile, String(nameKey2), around)
|
|
3761
3943
|
)
|
|
3762
3944
|
);
|
|
3763
3945
|
}
|
|
@@ -3778,11 +3960,11 @@ function foldReading(soFar, reading) {
|
|
|
3778
3960
|
unreadable: soFar.unreadable
|
|
3779
3961
|
};
|
|
3780
3962
|
}
|
|
3781
|
-
function readOne(db, rootsByFile, nameKey2) {
|
|
3963
|
+
function readOne(db, rootsByFile, nameKey2, loops) {
|
|
3782
3964
|
const node = (0, import_resolution6.nodeOfKey)(rootsByFile, nameKey2);
|
|
3783
3965
|
const names = [];
|
|
3784
3966
|
const patterns = [];
|
|
3785
|
-
for (const bindings of loopTurns(db, rootsByFile,
|
|
3967
|
+
for (const bindings of loopTurns(db, rootsByFile, loops)) {
|
|
3786
3968
|
const value = node === null ? (0, import_values5.hole)(nameKey2) : evaluatedValue(node, db, bindings.size === 0 ? void 0 : bindings);
|
|
3787
3969
|
const name = (0, import_values5.literalOf)(value);
|
|
3788
3970
|
if (name !== null) {
|
|
@@ -3815,38 +3997,105 @@ function patternOf(value) {
|
|
|
3815
3997
|
}
|
|
3816
3998
|
return readSomething ? new RegExp(`${source}$`) : null;
|
|
3817
3999
|
}
|
|
3818
|
-
function escapeForPattern(
|
|
3819
|
-
return
|
|
4000
|
+
function escapeForPattern(text3) {
|
|
4001
|
+
return text3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3820
4002
|
}
|
|
3821
|
-
function loopTurns(db, rootsByFile,
|
|
4003
|
+
function loopTurns(db, rootsByFile, loops) {
|
|
3822
4004
|
let turns = [/* @__PURE__ */ new Map()];
|
|
3823
|
-
for (const
|
|
4005
|
+
for (const loop of loops) {
|
|
4006
|
+
const bindings = bindingsOf(db, rootsByFile, loop);
|
|
4007
|
+
if (bindings === null) {
|
|
4008
|
+
continue;
|
|
4009
|
+
}
|
|
3824
4010
|
turns = turns.flatMap(
|
|
3825
|
-
(base) =>
|
|
3826
|
-
const binding = new Map([...base, [over.element, value]]);
|
|
3827
|
-
if (over.index !== "") {
|
|
3828
|
-
binding.set(over.index, String(position));
|
|
3829
|
-
}
|
|
3830
|
-
return binding;
|
|
3831
|
-
})
|
|
4011
|
+
(base) => bindings.map((binding) => new Map([...base, ...binding]))
|
|
3832
4012
|
);
|
|
3833
4013
|
}
|
|
3834
4014
|
return turns;
|
|
3835
4015
|
}
|
|
3836
|
-
function
|
|
3837
|
-
const
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
)
|
|
3843
|
-
const
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
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;
|
|
3847
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" });
|
|
3848
4074
|
}
|
|
3849
|
-
|
|
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);
|
|
3850
4099
|
}
|
|
3851
4100
|
|
|
3852
4101
|
// src/scope.ts
|
|
@@ -4595,9 +4844,9 @@ var BLOCK_TYPES5 = /* @__PURE__ */ new Set([
|
|
|
4595
4844
|
]);
|
|
4596
4845
|
function literalArgOf(node, facts) {
|
|
4597
4846
|
const value = evaluatedValue(node, facts);
|
|
4598
|
-
const
|
|
4599
|
-
if (
|
|
4600
|
-
return { kind: "string", value:
|
|
4847
|
+
const text3 = (0, import_values7.literalOf)(value);
|
|
4848
|
+
if (text3 !== null) {
|
|
4849
|
+
return { kind: "string", value: text3 };
|
|
4601
4850
|
}
|
|
4602
4851
|
const constant2 = (0, import_values7.constantOf)(value);
|
|
4603
4852
|
if (typeof constant2 === "number") {
|
|
@@ -4663,7 +4912,7 @@ function isCall(node, locals, inherited) {
|
|
|
4663
4912
|
}
|
|
4664
4913
|
function collectCalls(node, read, inherited, found) {
|
|
4665
4914
|
for (const child of children(node)) {
|
|
4666
|
-
if (read.stops.has(child.type)) {
|
|
4915
|
+
if (read.stops.has(child.type) && !isLambdaArgument(child)) {
|
|
4667
4916
|
continue;
|
|
4668
4917
|
}
|
|
4669
4918
|
if (isCall(child, read.locals, inherited)) {
|
|
@@ -4673,6 +4922,9 @@ function collectCalls(node, read, inherited, found) {
|
|
|
4673
4922
|
}
|
|
4674
4923
|
return found;
|
|
4675
4924
|
}
|
|
4925
|
+
function isLambdaArgument(node) {
|
|
4926
|
+
return node.type === LAMBDA_TYPE && node.parent?.type === "argument_list";
|
|
4927
|
+
}
|
|
4676
4928
|
function methodBody(definitionNode) {
|
|
4677
4929
|
const body = field(definitionNode, "body");
|
|
4678
4930
|
if (body === null) {
|
|
@@ -7594,7 +7846,7 @@ function envSiteAt(node) {
|
|
|
7594
7846
|
|
|
7595
7847
|
// src/filters.ts
|
|
7596
7848
|
var RESCUES_NOTHING = { refs: [], someUnread: false };
|
|
7597
|
-
function
|
|
7849
|
+
function controllerFilterChain(pattern, ancestry, read = {}) {
|
|
7598
7850
|
const forms = pattern.filters ?? [];
|
|
7599
7851
|
if (forms.length === 0) {
|
|
7600
7852
|
return [];
|
|
@@ -7638,27 +7890,47 @@ function controllerFilters(pattern, ancestry, read = {}) {
|
|
|
7638
7890
|
declared = applySkips(declared, skipsOf(statement, skipped, read.facts));
|
|
7639
7891
|
}
|
|
7640
7892
|
}
|
|
7641
|
-
const resolved =
|
|
7642
|
-
|
|
7643
|
-
const written = writtenAt(
|
|
7893
|
+
const resolved = declared.map(
|
|
7894
|
+
(declaration) => linkFor(
|
|
7644
7895
|
declaration,
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
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: {
|
|
7651
7921
|
filter: declaration.filter,
|
|
7652
7922
|
...written,
|
|
7653
7923
|
only: declaration.only,
|
|
7654
7924
|
except: declaration.except,
|
|
7655
7925
|
rescues: declaration.rescues
|
|
7656
|
-
}
|
|
7657
|
-
}
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
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;
|
|
7662
7934
|
}
|
|
7663
7935
|
function writtenAt(declaration, found) {
|
|
7664
7936
|
if (found.type === "found") {
|
|
@@ -7709,6 +7981,13 @@ function filterReference(filter, displayPath, caught) {
|
|
|
7709
7981
|
}
|
|
7710
7982
|
};
|
|
7711
7983
|
}
|
|
7984
|
+
function unreadFilterReference(filter, displayPath) {
|
|
7985
|
+
return {
|
|
7986
|
+
file: displayPath,
|
|
7987
|
+
name: filter.methodName,
|
|
7988
|
+
...filter.filter.onThrow === true ? { onThrow: true } : {}
|
|
7989
|
+
};
|
|
7990
|
+
}
|
|
7712
7991
|
function filterUnit(filter, pattern, displayPath, body, reading = {}) {
|
|
7713
7992
|
const range = rangeOf(filter.method);
|
|
7714
7993
|
const { respondingHelper, raises: raises2 } = reading;
|
|
@@ -7792,6 +8071,7 @@ function declarationsOf(statement, filter, declaredIn, facts, inlineOrdinal) {
|
|
|
7792
8071
|
only,
|
|
7793
8072
|
except: except ?? /* @__PURE__ */ new Set(),
|
|
7794
8073
|
rescues: rescues2,
|
|
8074
|
+
declaredIn: declaredIn.file,
|
|
7795
8075
|
...inline === void 0 ? {} : { inline }
|
|
7796
8076
|
}));
|
|
7797
8077
|
}
|
|
@@ -8784,8 +9064,8 @@ function moduleOfConstant(node, options) {
|
|
|
8784
9064
|
const files = [...new Set(keys.map(import_resolution10.fileOfKey))];
|
|
8785
9065
|
return files.length === 1 ? options.displayPathOf(files[0]) : null;
|
|
8786
9066
|
}
|
|
8787
|
-
function oneLine(
|
|
8788
|
-
return
|
|
9067
|
+
function oneLine(text3) {
|
|
9068
|
+
return text3.replace(/\s*\n\s*/g, " ").trim();
|
|
8789
9069
|
}
|
|
8790
9070
|
|
|
8791
9071
|
// src/testClasses.ts
|
|
@@ -9227,11 +9507,12 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9227
9507
|
])) {
|
|
9228
9508
|
return [];
|
|
9229
9509
|
}
|
|
9230
|
-
const
|
|
9510
|
+
const chain = controllerFilterChain(pattern, ancestry, {
|
|
9231
9511
|
facts: options.facts,
|
|
9232
9512
|
bodyBlocks: options.bodyBlocks,
|
|
9233
9513
|
dynamicNames: options.dynamicNames
|
|
9234
9514
|
});
|
|
9515
|
+
const filters = chain.flatMap((link) => "read" in link ? [link.read] : []);
|
|
9235
9516
|
const units = [];
|
|
9236
9517
|
const actions = controllerActions(
|
|
9237
9518
|
pattern,
|
|
@@ -9262,10 +9543,10 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9262
9543
|
return classes === void 0 ? [] : [classes];
|
|
9263
9544
|
});
|
|
9264
9545
|
for (const filter of filters) {
|
|
9265
|
-
const
|
|
9546
|
+
const displayPath2 = options.displayPathOf?.(filter.file) ?? filter.file;
|
|
9266
9547
|
const body = bodyOfMethod(filter.method, filter.file, options);
|
|
9267
9548
|
const handler = filter.filter.onThrow === true;
|
|
9268
|
-
const raw = filterUnit(filter, pattern,
|
|
9549
|
+
const raw = filterUnit(filter, pattern, displayPath2, body, {
|
|
9269
9550
|
facts: options.facts,
|
|
9270
9551
|
respondingHelper,
|
|
9271
9552
|
...handler ? {} : {
|
|
@@ -9293,14 +9574,14 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9293
9574
|
enclosingQualifiedName: filter.enclosingQualifiedName
|
|
9294
9575
|
});
|
|
9295
9576
|
}
|
|
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));
|
|
9296
9583
|
const emitAction = async (actionName, method, block, routes) => {
|
|
9297
|
-
const around =
|
|
9298
|
-
(filter) => filterReference(
|
|
9299
|
-
filter,
|
|
9300
|
-
options.displayPathOf?.(filter.file) ?? filter.file,
|
|
9301
|
-
caught.get(filter)
|
|
9302
|
-
)
|
|
9303
|
-
);
|
|
9584
|
+
const around = chain.filter((link) => filterCoversAction(filterOf(link), actionName)).map((link) => referenceTo(link));
|
|
9304
9585
|
const raises2 = {
|
|
9305
9586
|
classes: await raisedClasses(method, block.info.bodyNesting, exceptions),
|
|
9306
9587
|
handlers: handlersAround(actionName)
|
|
@@ -10567,8 +10848,8 @@ function flagsDeclaredIn(construction) {
|
|
|
10567
10848
|
return flags;
|
|
10568
10849
|
}
|
|
10569
10850
|
function flagOf(args) {
|
|
10570
|
-
const written = args.map((arg) => stringLiteralValue(arg)).filter((
|
|
10571
|
-
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;
|
|
10572
10853
|
if (chosen === null) {
|
|
10573
10854
|
return null;
|
|
10574
10855
|
}
|
|
@@ -10606,8 +10887,6 @@ function parserCalledOn(receiver, parserNamed) {
|
|
|
10606
10887
|
|
|
10607
10888
|
// src/reach/resolveCallee.ts
|
|
10608
10889
|
var import_resolution12 = require("@suss/resolution");
|
|
10609
|
-
var DYNAMIC_SEND_NAMES = /* @__PURE__ */ new Set(["send", "public_send", "__send__"]);
|
|
10610
|
-
var INVOKES_RECEIVER = "call";
|
|
10611
10890
|
var STOP_FOR = {
|
|
10612
10891
|
severalSources: "multipleSources",
|
|
10613
10892
|
outsideRun: "outsideRun",
|
|
@@ -10690,6 +10969,57 @@ function loaderSourceCallee(call, site, ctx) {
|
|
|
10690
10969
|
}
|
|
10691
10970
|
return null;
|
|
10692
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
|
+
}
|
|
10693
11023
|
function outcomeFor(key, ctx, read) {
|
|
10694
11024
|
return read?.outcomes.get(key) ?? (0, import_resolution12.calleeOutcomeOf)(ctx.facts, key, RUBY_PROGRAM);
|
|
10695
11025
|
}
|
|
@@ -10703,14 +11033,16 @@ function readsAsACall(call, site, ctx, read) {
|
|
|
10703
11033
|
return false;
|
|
10704
11034
|
}
|
|
10705
11035
|
const outcome = outcomeFor(spelling.key, ctx, read);
|
|
10706
|
-
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
|
+
);
|
|
10707
11039
|
}
|
|
10708
11040
|
function spellingFor2(call, site) {
|
|
10709
11041
|
const methodName = calleeMethodName(call);
|
|
10710
11042
|
if (methodName === void 0) {
|
|
10711
11043
|
return { kind: "stopped", reason: "noDeclaration" };
|
|
10712
11044
|
}
|
|
10713
|
-
if (
|
|
11045
|
+
if (SENDING_METHODS.has(methodName)) {
|
|
10714
11046
|
return { kind: "stopped", reason: "unsettledValue" };
|
|
10715
11047
|
}
|
|
10716
11048
|
const receiver = field(call, "receiver");
|
|
@@ -10756,7 +11088,7 @@ function asCallee(spelling, outcome, site, ctx) {
|
|
|
10756
11088
|
return methodOnObject(spelling, objectKey, ctx);
|
|
10757
11089
|
}
|
|
10758
11090
|
if (outcome.kind === "function") {
|
|
10759
|
-
return spelling.method ===
|
|
11091
|
+
return spelling.method === INVOKE_METHOD ? functionCallee(outcome.key, ctx) : NO_DECLARATION;
|
|
10760
11092
|
}
|
|
10761
11093
|
return stop(STOP_FOR[outcome.kind] ?? "noDeclaration");
|
|
10762
11094
|
}
|
|
@@ -10800,7 +11132,7 @@ function scopeOn(qualifiedName, method, ctx) {
|
|
|
10800
11132
|
return null;
|
|
10801
11133
|
}
|
|
10802
11134
|
function fromCaller(spelling, parameterKey, site) {
|
|
10803
|
-
if (!parameterKey.startsWith(`${site.owner}#`) || spelling.method !==
|
|
11135
|
+
if (!parameterKey.startsWith(`${site.owner}#`) || spelling.method !== INVOKE_METHOD) {
|
|
10804
11136
|
return stop("unsettledValue");
|
|
10805
11137
|
}
|
|
10806
11138
|
return stop("callerSupplied");
|
|
@@ -10936,6 +11268,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
10936
11268
|
const targetsByKey = /* @__PURE__ */ new Map();
|
|
10937
11269
|
const stopsByKey = /* @__PURE__ */ new Map();
|
|
10938
11270
|
const argTargetsByKey = /* @__PURE__ */ new Map();
|
|
11271
|
+
const possibleTargetsByKey = /* @__PURE__ */ new Map();
|
|
10939
11272
|
const parameterCallsByKey = /* @__PURE__ */ new Map();
|
|
10940
11273
|
const propertyReadsByKey = /* @__PURE__ */ new Map();
|
|
10941
11274
|
const receiverClassesByKey = /* @__PURE__ */ new Map();
|
|
@@ -10994,6 +11327,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
10994
11327
|
}
|
|
10995
11328
|
targetsByKey.set(key, scan.targets);
|
|
10996
11329
|
argTargetsByKey.set(key, scan.argTargets);
|
|
11330
|
+
possibleTargetsByKey.set(key, scan.possibleTargets);
|
|
10997
11331
|
if (scan.propertyReads.size > 0) {
|
|
10998
11332
|
propertyReadsByKey.set(key, scan.propertyReads);
|
|
10999
11333
|
}
|
|
@@ -11057,6 +11391,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
11057
11391
|
}
|
|
11058
11392
|
(0, import_behavioral_ir7.placeCalls)(summary2, targetsByKey.get(key));
|
|
11059
11393
|
(0, import_behavioral_ir7.placeArgTargets)(summary2, argTargetsByKey.get(key));
|
|
11394
|
+
(0, import_behavioral_ir7.placePossibleCalls)(summary2, possibleTargetsByKey.get(key));
|
|
11060
11395
|
(0, import_behavioral_ir7.placeCalleeParameters)(summary2, parameterCallsByKey.get(key));
|
|
11061
11396
|
return summary2;
|
|
11062
11397
|
};
|
|
@@ -11079,6 +11414,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
11079
11414
|
targetsByKey,
|
|
11080
11415
|
stopsByKey,
|
|
11081
11416
|
argTargetsByKey,
|
|
11417
|
+
possibleTargetsByKey,
|
|
11082
11418
|
parameterCallsByKey,
|
|
11083
11419
|
propertyReadsByKey,
|
|
11084
11420
|
receiverClassesByKey,
|
|
@@ -11108,36 +11444,70 @@ function batchedReads(round, options) {
|
|
|
11108
11444
|
const bodies = round.flatMap(
|
|
11109
11445
|
(entry) => "source" in entry ? [{ key: entry.key, ...bodyOf2(entry.source, options) }] : []
|
|
11110
11446
|
);
|
|
11111
|
-
const
|
|
11112
|
-
|
|
11113
|
-
|
|
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
|
|
11114
11464
|
);
|
|
11115
|
-
|
|
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;
|
|
11116
11476
|
}
|
|
11117
11477
|
function scanOnce(source, key, options, read, charges) {
|
|
11118
11478
|
const ledger = options.ledger;
|
|
11119
11479
|
if (ledger === void 0) {
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
11480
|
+
return scanBody(
|
|
11481
|
+
source,
|
|
11482
|
+
options.context,
|
|
11483
|
+
options,
|
|
11484
|
+
read ?? ownReads(source, options)
|
|
11485
|
+
);
|
|
11125
11486
|
}
|
|
11126
11487
|
return ledger.charging(chargeOf(charges, key), () => {
|
|
11127
11488
|
forgetEvaluations(options.context.facts);
|
|
11128
11489
|
ledger.readFile(source.file);
|
|
11129
|
-
const
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
|
|
11490
|
+
const scan = scanBody(
|
|
11491
|
+
source,
|
|
11492
|
+
options.context,
|
|
11493
|
+
options,
|
|
11494
|
+
ownReads(source, options)
|
|
11495
|
+
);
|
|
11135
11496
|
for (const target of scan.followed) {
|
|
11136
11497
|
ledger.touchKey(keyOf(target));
|
|
11137
11498
|
}
|
|
11138
11499
|
return scan;
|
|
11139
11500
|
});
|
|
11140
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
|
+
}
|
|
11141
11511
|
function storedScan(scan) {
|
|
11142
11512
|
return {
|
|
11143
11513
|
followed: scan.followed.map((target) => ({
|
|
@@ -11153,6 +11523,10 @@ function storedScan(scan) {
|
|
|
11153
11523
|
callee,
|
|
11154
11524
|
[...byPosition]
|
|
11155
11525
|
]),
|
|
11526
|
+
possibleTargets: [...scan.possibleTargets].map(([callee, places]) => [
|
|
11527
|
+
callee,
|
|
11528
|
+
[...places]
|
|
11529
|
+
]),
|
|
11156
11530
|
parameterCalls: [...scan.parameterCalls],
|
|
11157
11531
|
passedPositions: [...scan.passedPositions],
|
|
11158
11532
|
propertyReads: [...scan.propertyReads],
|
|
@@ -11170,6 +11544,7 @@ function scanFromStored(stored, functionFor) {
|
|
|
11170
11544
|
new Map(byPosition)
|
|
11171
11545
|
])
|
|
11172
11546
|
),
|
|
11547
|
+
possibleTargets: new Map(stored.possibleTargets),
|
|
11173
11548
|
parameterCalls: stored.parameterCalls,
|
|
11174
11549
|
passedPositions: new Set(stored.passedPositions),
|
|
11175
11550
|
propertyReads: new Set(stored.propertyReads),
|
|
@@ -11198,6 +11573,7 @@ var EMPTY_SCAN = {
|
|
|
11198
11573
|
stops: [],
|
|
11199
11574
|
targets: /* @__PURE__ */ new Map(),
|
|
11200
11575
|
argTargets: /* @__PURE__ */ new Map(),
|
|
11576
|
+
possibleTargets: /* @__PURE__ */ new Map(),
|
|
11201
11577
|
parameterCalls: [],
|
|
11202
11578
|
passedPositions: /* @__PURE__ */ new Set(),
|
|
11203
11579
|
propertyReads: /* @__PURE__ */ new Set(),
|
|
@@ -11219,7 +11595,7 @@ function bodyOf2(source, options) {
|
|
|
11219
11595
|
const file = run?.fileOf(call) ?? source.file;
|
|
11220
11596
|
return file === source.file ? site : { ...site, file, method: enclosingDefinition(call) };
|
|
11221
11597
|
};
|
|
11222
|
-
const written =
|
|
11598
|
+
const written = callsWrittenIn2(source.node, run, options);
|
|
11223
11599
|
const calls = callsReported(
|
|
11224
11600
|
written,
|
|
11225
11601
|
(call) => mightReadAsACall(call, siteFor(call), options.context)
|
|
@@ -11233,7 +11609,7 @@ function bodyOf2(source, options) {
|
|
|
11233
11609
|
written: calls.map((call) => ({ call, site: siteFor(call) }))
|
|
11234
11610
|
};
|
|
11235
11611
|
}
|
|
11236
|
-
function
|
|
11612
|
+
function callsWrittenIn2(node, run, options) {
|
|
11237
11613
|
if (run !== null) {
|
|
11238
11614
|
return exampleCalls(run, options.inheritedMethods).filter(
|
|
11239
11615
|
(call) => !run.isRunnerCall(call)
|
|
@@ -11300,6 +11676,12 @@ function scanBody(source, ctx, options, read) {
|
|
|
11300
11676
|
}
|
|
11301
11677
|
const argNodes = bodyStatements(args);
|
|
11302
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
|
+
}
|
|
11303
11685
|
const symbol = methodReferenceSymbol(argNodes[position]);
|
|
11304
11686
|
if (symbol === null) {
|
|
11305
11687
|
continue;
|
|
@@ -11337,11 +11719,35 @@ function scanBody(source, ctx, options, read) {
|
|
|
11337
11719
|
span: spanOf(target.node)
|
|
11338
11720
|
});
|
|
11339
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
|
+
};
|
|
11340
11729
|
for (const call of calls) {
|
|
11341
11730
|
const callee = calleeText(call);
|
|
11342
11731
|
const callSite = read.siteFor(call);
|
|
11343
11732
|
const predicate = read.predicateOf(call);
|
|
11344
|
-
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 };
|
|
11345
11751
|
if (options.storage !== void 0) {
|
|
11346
11752
|
for (const callback of callbacksReached(
|
|
11347
11753
|
call,
|
|
@@ -11390,17 +11796,14 @@ function scanBody(source, ctx, options, read) {
|
|
|
11390
11796
|
if (isArglessReceiverCall(call)) {
|
|
11391
11797
|
keptArgless.add(call.id);
|
|
11392
11798
|
}
|
|
11393
|
-
|
|
11394
|
-
if (!seen.has(key)) {
|
|
11395
|
-
seen.add(key);
|
|
11396
|
-
followed2.push(outcome.target);
|
|
11397
|
-
}
|
|
11799
|
+
follow(outcome.target);
|
|
11398
11800
|
}
|
|
11399
11801
|
return {
|
|
11400
11802
|
followed: followed2,
|
|
11401
11803
|
stops: stops.stops,
|
|
11402
11804
|
targets: placements.targets,
|
|
11403
11805
|
argTargets: placements.argTargets,
|
|
11806
|
+
possibleTargets: placements.possibleTargets,
|
|
11404
11807
|
parameterCalls,
|
|
11405
11808
|
passedPositions,
|
|
11406
11809
|
propertyReads: propertyReadsAmong(read.argless, calls, keptArgless),
|
|
@@ -11432,9 +11835,9 @@ function propertyReadsAmong(argless, made, keptArgless) {
|
|
|
11432
11835
|
);
|
|
11433
11836
|
const reads = /* @__PURE__ */ new Set();
|
|
11434
11837
|
for (const call of argless) {
|
|
11435
|
-
const
|
|
11436
|
-
if (!kept.has(
|
|
11437
|
-
reads.add(
|
|
11838
|
+
const text3 = calleeText(call);
|
|
11839
|
+
if (!kept.has(text3)) {
|
|
11840
|
+
reads.add(text3);
|
|
11438
11841
|
}
|
|
11439
11842
|
}
|
|
11440
11843
|
return reads;
|
|
@@ -12369,7 +12772,7 @@ function replaysCleanly(units, discovered) {
|
|
|
12369
12772
|
async function extractRubyProject(options) {
|
|
12370
12773
|
const timer = options.onTiming !== void 0 ? (0, import_extractor19.createTimer)() : (0, import_extractor19.noopTimer)();
|
|
12371
12774
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
12372
|
-
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)
|
|
12373
12776
|
);
|
|
12374
12777
|
const layer = (0, import_extractor19.createCacheLayer)(cacheDir);
|
|
12375
12778
|
const packsDigest = `${adapterStamp.packsDigest(
|
|
@@ -12390,10 +12793,13 @@ async function extractRubyProject(options) {
|
|
|
12390
12793
|
"cache.lookup",
|
|
12391
12794
|
() => layer.lookup(input)
|
|
12392
12795
|
);
|
|
12796
|
+
const composed = (stored) => (0, import_extractor19.composeWrappers)(stored, {
|
|
12797
|
+
gapHandling: options.gapHandling ?? "permissive"
|
|
12798
|
+
});
|
|
12393
12799
|
if (lookup.kind === "hit") {
|
|
12394
12800
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
12395
12801
|
options.onTiming?.(timer.report());
|
|
12396
|
-
return { summaries: lookup.summaries, facts: new import_datalog3.Database() };
|
|
12802
|
+
return { summaries: composed(lookup.summaries), facts: new import_datalog3.Database() };
|
|
12397
12803
|
}
|
|
12398
12804
|
const plan = lookup.diagnostic.missReason === "files-changed" ? await timer.timeAsync("cache.plan", () => layer.plan(input)) : null;
|
|
12399
12805
|
if (plan !== null && plan.changed.size === 0 && plan.removed.size === 0) {
|
|
@@ -12403,7 +12809,7 @@ async function extractRubyProject(options) {
|
|
|
12403
12809
|
}
|
|
12404
12810
|
options.onCacheDiagnostic?.({ kind: "hit" });
|
|
12405
12811
|
options.onTiming?.(timer.report());
|
|
12406
|
-
return { summaries: plan.allSummaries(), facts: new import_datalog3.Database() };
|
|
12812
|
+
return { summaries: composed(plan.allSummaries()), facts: new import_datalog3.Database() };
|
|
12407
12813
|
}
|
|
12408
12814
|
const cache = { timer, cacheDir, layer, input };
|
|
12409
12815
|
const records = plan === null ? null : (0, import_resolution16.recordsToReplay)(plan.roots, plan.changed, plan.removed);
|
|
@@ -12764,6 +13170,7 @@ async function runRuby(options, cache, previous) {
|
|
|
12764
13170
|
}
|
|
12765
13171
|
(0, import_behavioral_ir9.placeCalls)(summary, reached.targetsByKey.get(key));
|
|
12766
13172
|
(0, import_behavioral_ir9.placeArgTargets)(summary, reached.argTargetsByKey.get(key));
|
|
13173
|
+
(0, import_behavioral_ir9.placePossibleCalls)(summary, reached.possibleTargetsByKey.get(key));
|
|
12767
13174
|
(0, import_behavioral_ir9.placeCalleeParameters)(summary, reached.parameterCallsByKey.get(key));
|
|
12768
13175
|
(0, import_behavioral_ir9.placeReceiverClasses)(summary, reached.receiverClassesByKey.get(key));
|
|
12769
13176
|
}
|
|
@@ -12810,16 +13217,20 @@ async function runRuby(options, cache, previous) {
|
|
|
12810
13217
|
);
|
|
12811
13218
|
return (0, import_extractor19.composeWrappers)(summaries, { gapHandling });
|
|
12812
13219
|
});
|
|
13220
|
+
const walkedFiles = new Map(
|
|
13221
|
+
parsed.map(({ file }) => [displayPathOf(file), file])
|
|
13222
|
+
);
|
|
12813
13223
|
await timer.timeAsync("cache.write", async () => {
|
|
12814
|
-
if (cacheDir === null ||
|
|
13224
|
+
if (cacheDir === null || summaries.length === 0) {
|
|
12815
13225
|
return;
|
|
12816
13226
|
}
|
|
12817
13227
|
try {
|
|
12818
13228
|
await cache.layer.write(
|
|
12819
13229
|
cache.input,
|
|
12820
|
-
|
|
13230
|
+
summaries,
|
|
12821
13231
|
log === null || ledger === null || overBudget ? void 0 : rubyAttribution({
|
|
12822
|
-
|
|
13232
|
+
summaries,
|
|
13233
|
+
walkedFileOf: (locationFile) => walkedFiles.get(locationFile),
|
|
12823
13234
|
discoveries,
|
|
12824
13235
|
reached,
|
|
12825
13236
|
reuse,
|
|
@@ -12894,7 +13305,10 @@ function rubyAttribution(args) {
|
|
|
12894
13305
|
facts: args.facts.get(file) ?? { own: "", joined: "" }
|
|
12895
13306
|
}
|
|
12896
13307
|
}));
|
|
12897
|
-
return {
|
|
13308
|
+
return {
|
|
13309
|
+
roots,
|
|
13310
|
+
owners: (0, import_extractor19.ownersWhereWritten)(args.summaries, args.walkedFileOf)
|
|
13311
|
+
};
|
|
12898
13312
|
}
|
|
12899
13313
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["vendor", "node_modules", "tmp", ".git"]);
|
|
12900
13314
|
function findRubyFiles(root) {
|
|
@@ -12968,8 +13382,8 @@ function displayNameOf(node) {
|
|
|
12968
13382
|
if (node.type === "class" || node.type === "module") {
|
|
12969
13383
|
return field(node, "name")?.text ?? node.text;
|
|
12970
13384
|
}
|
|
12971
|
-
const
|
|
12972
|
-
return
|
|
13385
|
+
const text3 = node.text.split("\n")[0].trim();
|
|
13386
|
+
return text3.length > 40 ? `${text3.slice(0, 40)}...` : text3;
|
|
12973
13387
|
}
|
|
12974
13388
|
function width(node) {
|
|
12975
13389
|
return node.endIndex - node.startIndex;
|
|
@@ -12999,14 +13413,14 @@ var RubyWhySession = class {
|
|
|
12999
13413
|
* The smallest expression on `line` of `file` whose text is exactly
|
|
13000
13414
|
* `text`, or null.
|
|
13001
13415
|
*/
|
|
13002
|
-
findExpression(file, line,
|
|
13416
|
+
findExpression(file, line, text3) {
|
|
13003
13417
|
const root = this.rootOf(file);
|
|
13004
13418
|
if (root === null) {
|
|
13005
13419
|
return null;
|
|
13006
13420
|
}
|
|
13007
13421
|
let found = null;
|
|
13008
13422
|
const visit = (node) => {
|
|
13009
|
-
if (node.startPosition.row + 1 === line && node.text ===
|
|
13423
|
+
if (node.startPosition.row + 1 === line && node.text === text3) {
|
|
13010
13424
|
if (found === null || width(node) <= width(found)) {
|
|
13011
13425
|
found = node;
|
|
13012
13426
|
}
|