@suss/adapter-ruby 0.34.1 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +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.js
CHANGED
|
@@ -271,8 +271,8 @@ var VISIBILITY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
271
271
|
"protected",
|
|
272
272
|
"public"
|
|
273
273
|
]);
|
|
274
|
-
function visibilityKeyword(
|
|
275
|
-
return VISIBILITY_KEYWORDS.has(
|
|
274
|
+
function visibilityKeyword(text3) {
|
|
275
|
+
return VISIBILITY_KEYWORDS.has(text3) ? text3 : null;
|
|
276
276
|
}
|
|
277
277
|
function setVisibility(visibility, name, keyword) {
|
|
278
278
|
if (keyword === "public") {
|
|
@@ -542,8 +542,8 @@ function lowerAcronyms(word, acronyms) {
|
|
|
542
542
|
(_match, before, acronym) => `${before === void 0 ? "" : "_"}${acronym.toLowerCase()}`
|
|
543
543
|
);
|
|
544
544
|
}
|
|
545
|
-
function escapeRegExp(
|
|
546
|
-
return
|
|
545
|
+
function escapeRegExp(text3) {
|
|
546
|
+
return text3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
547
547
|
}
|
|
548
548
|
var PATH_CONVENTIONS = {
|
|
549
549
|
railsUnderscore: underscoreConstantPath
|
|
@@ -606,7 +606,7 @@ function isDirectory(directory) {
|
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
// src/defineMethod.ts
|
|
609
|
-
import { nodeOfKey as nodeOfKey2 } from "@suss/resolution";
|
|
609
|
+
import { nodeOfKey as nodeOfKey2, spanOfKey } from "@suss/resolution";
|
|
610
610
|
import { hole as hole2, literalOf as literalOf3, piecesOf } from "@suss/values";
|
|
611
611
|
|
|
612
612
|
// src/values/evaluator.ts
|
|
@@ -710,6 +710,15 @@ var OBJECT_METHODS = /* @__PURE__ */ new Set([
|
|
|
710
710
|
"warn",
|
|
711
711
|
"yield_self"
|
|
712
712
|
]);
|
|
713
|
+
var SENDING_METHODS = /* @__PURE__ */ new Set([
|
|
714
|
+
"send",
|
|
715
|
+
"public_send",
|
|
716
|
+
"__send__"
|
|
717
|
+
]);
|
|
718
|
+
var METHOD_REFERENCE = "method";
|
|
719
|
+
var INVOKE_METHOD = "call";
|
|
720
|
+
var BLOCK_WRAPPERS = /* @__PURE__ */ new Set(["proc", "lambda"]);
|
|
721
|
+
var PROC_CLASS = "Proc";
|
|
713
722
|
var CONSTRUCTOR = "new";
|
|
714
723
|
|
|
715
724
|
// src/facts/resolve.ts
|
|
@@ -781,12 +790,16 @@ function constructionSites(db, classKey) {
|
|
|
781
790
|
|
|
782
791
|
// src/facts/values.ts
|
|
783
792
|
import {
|
|
793
|
+
addEntryRows,
|
|
784
794
|
addPackWords,
|
|
795
|
+
addTemplateRows,
|
|
785
796
|
classMemberName,
|
|
786
797
|
NAMED_STORE_NAME,
|
|
787
798
|
RECEIVER_STORE_NAME,
|
|
799
|
+
SPREAD_ENTRY,
|
|
788
800
|
startsAtName,
|
|
789
801
|
UNPLACED_STORE_NAME,
|
|
802
|
+
VALUE_ENTRY,
|
|
790
803
|
valueLeftByWrites
|
|
791
804
|
} from "@suss/resolution";
|
|
792
805
|
|
|
@@ -1319,6 +1332,9 @@ function add(emitter, relation, ...tuple) {
|
|
|
1319
1332
|
}
|
|
1320
1333
|
emitter.db.add(relation, tuple);
|
|
1321
1334
|
}
|
|
1335
|
+
function rowsOf(emitter) {
|
|
1336
|
+
return (relation, row) => add(emitter, relation, ...row);
|
|
1337
|
+
}
|
|
1322
1338
|
function valueKey(emitter, written, parent) {
|
|
1323
1339
|
return readKey(emitter.filePath, written, emitter.enclosing, parent);
|
|
1324
1340
|
}
|
|
@@ -1402,6 +1418,97 @@ function emitCall(emitter, site) {
|
|
|
1402
1418
|
}
|
|
1403
1419
|
emitCallArguments(emitter, site);
|
|
1404
1420
|
emitConversion(emitter, site);
|
|
1421
|
+
emitSentChoice(emitter, site);
|
|
1422
|
+
emitMethodReference(emitter, site);
|
|
1423
|
+
emitBlockAsProc(emitter, site);
|
|
1424
|
+
}
|
|
1425
|
+
function emitBlockAsProc(emitter, site) {
|
|
1426
|
+
const { method, receiver, node } = site;
|
|
1427
|
+
const name = method?.text;
|
|
1428
|
+
const wraps = receiver === null ? name !== void 0 && BLOCK_WRAPPERS.has(name) : name === CONSTRUCTOR && receiver.text === PROC_CLASS;
|
|
1429
|
+
const block = field(node, "block");
|
|
1430
|
+
if (!wraps || block === null) {
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
const blockKey = nodeId(emitter.filePath, block);
|
|
1434
|
+
add(emitter, "func", blockKey);
|
|
1435
|
+
add(emitter, "binds", site.key, blockKey);
|
|
1436
|
+
for (const call of callsWrittenIn(block)) {
|
|
1437
|
+
add(emitter, "makesCall", blockKey, nodeId(emitter.filePath, call));
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
function callsWrittenIn(node, found = []) {
|
|
1441
|
+
for (const child of children(node)) {
|
|
1442
|
+
if (OWN_BODY_TYPES.has(child.type)) {
|
|
1443
|
+
continue;
|
|
1444
|
+
}
|
|
1445
|
+
if (child.type === "call") {
|
|
1446
|
+
found.push(child);
|
|
1447
|
+
}
|
|
1448
|
+
callsWrittenIn(child, found);
|
|
1449
|
+
}
|
|
1450
|
+
return found;
|
|
1451
|
+
}
|
|
1452
|
+
function emitSentChoice(emitter, site) {
|
|
1453
|
+
const { method, receiver, node } = site;
|
|
1454
|
+
if (method === null || !SENDING_METHODS.has(method.text)) {
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
const objectKey = receiver === null ? emitter.selfKey : valueKey(emitter, receiver, node);
|
|
1458
|
+
const [name] = readCallArgs(field(node, "arguments")).positional;
|
|
1459
|
+
if (objectKey === null || name === void 0) {
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1462
|
+
add(emitter, "callsChosenEntry", site.key);
|
|
1463
|
+
const written = symbolValue(name) ?? stringLiteralValue(name);
|
|
1464
|
+
if (written !== null) {
|
|
1465
|
+
for (const spelled of namesReadAs(emitter, receiver, objectKey, written)) {
|
|
1466
|
+
add(emitter, "choosesNamedEntry", site.key, objectKey, spelled);
|
|
1467
|
+
}
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
const ends = writtenEnds(name);
|
|
1471
|
+
if (ends === null) {
|
|
1472
|
+
add(emitter, "choosesEntry", site.key, objectKey);
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
for (const start of namesReadAs(emitter, receiver, objectKey, ends.start)) {
|
|
1476
|
+
add(emitter, "choosesEntryLike", site.key, objectKey, start, ends.end);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function writtenEnds(node) {
|
|
1480
|
+
if (node.type !== "string" && node.type !== "delimited_symbol") {
|
|
1481
|
+
return null;
|
|
1482
|
+
}
|
|
1483
|
+
const parts = children(node);
|
|
1484
|
+
const written = (part) => part.type === "string_content";
|
|
1485
|
+
const firstComputed = parts.findIndex((part) => !written(part));
|
|
1486
|
+
if (firstComputed === -1) {
|
|
1487
|
+
return null;
|
|
1488
|
+
}
|
|
1489
|
+
const lastComputed = parts.length - 1 - [...parts].reverse().findIndex((part) => !written(part));
|
|
1490
|
+
const start = parts.slice(0, firstComputed).map((part) => part.text).join("");
|
|
1491
|
+
const end = parts.slice(lastComputed + 1).map((part) => part.text).join("");
|
|
1492
|
+
return start === "" && end === "" ? null : { start, end };
|
|
1493
|
+
}
|
|
1494
|
+
function emitMethodReference(emitter, site) {
|
|
1495
|
+
const { method, receiver, node } = site;
|
|
1496
|
+
if (method?.text !== METHOD_REFERENCE || receiver !== null || emitter.selfKey === null) {
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
const [name] = readCallArgs(field(node, "arguments")).positional;
|
|
1500
|
+
const written = name === void 0 ? null : symbolValue(name) ?? stringLiteralValue(name);
|
|
1501
|
+
if (written === null) {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
for (const spelled of namesReadAs(
|
|
1505
|
+
emitter,
|
|
1506
|
+
receiver,
|
|
1507
|
+
emitter.selfKey,
|
|
1508
|
+
written
|
|
1509
|
+
)) {
|
|
1510
|
+
add(emitter, "readsProperty", site.key, emitter.selfKey, spelled);
|
|
1511
|
+
}
|
|
1405
1512
|
}
|
|
1406
1513
|
function emitConversion(emitter, site) {
|
|
1407
1514
|
const { method, receiver, node } = site;
|
|
@@ -1475,7 +1582,6 @@ var SELF_READS = {
|
|
|
1475
1582
|
function classSpelling(name) {
|
|
1476
1583
|
return name === CONSTRUCTOR ? name : classMemberName(name);
|
|
1477
1584
|
}
|
|
1478
|
-
var INVOKE_METHOD = "call";
|
|
1479
1585
|
function invokedValueOf(call) {
|
|
1480
1586
|
if (call.type !== "call") {
|
|
1481
1587
|
return null;
|
|
@@ -1521,6 +1627,7 @@ function emitArray(emitter, array) {
|
|
|
1521
1627
|
const objectKey = nodeId(emitter.filePath, array);
|
|
1522
1628
|
add(emitter, "objectValue", objectKey);
|
|
1523
1629
|
let position = 0;
|
|
1630
|
+
const entries = [];
|
|
1524
1631
|
for (const element of children(array)) {
|
|
1525
1632
|
add(
|
|
1526
1633
|
emitter,
|
|
@@ -1530,12 +1637,24 @@ function emitArray(emitter, array) {
|
|
|
1530
1637
|
valueKey(emitter, element, array)
|
|
1531
1638
|
);
|
|
1532
1639
|
position += 1;
|
|
1640
|
+
entries.push(writtenEntry(emitter, element, array));
|
|
1533
1641
|
}
|
|
1642
|
+
addEntryRows(rowsOf(emitter), objectKey, entries);
|
|
1643
|
+
}
|
|
1644
|
+
var SPREAD_TYPES = /* @__PURE__ */ new Set(["splat_argument", "hash_splat_argument"]);
|
|
1645
|
+
function writtenEntry(emitter, entry, parent) {
|
|
1646
|
+
const unpacked = SPREAD_TYPES.has(entry.type) ? children(entry)[0] : void 0;
|
|
1647
|
+
return unpacked === void 0 ? { key: valueKey(emitter, entry, parent), form: VALUE_ENTRY } : { key: valueKey(emitter, unpacked, entry), form: SPREAD_ENTRY };
|
|
1534
1648
|
}
|
|
1535
1649
|
function emitHash(emitter, hash) {
|
|
1536
1650
|
const objectKey = nodeId(emitter.filePath, hash);
|
|
1537
1651
|
add(emitter, "objectValue", objectKey);
|
|
1652
|
+
const entries = [];
|
|
1538
1653
|
for (const pair of children(hash)) {
|
|
1654
|
+
if (SPREAD_TYPES.has(pair.type)) {
|
|
1655
|
+
entries.push(writtenEntry(emitter, pair, hash));
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1539
1658
|
if (pair.type !== "pair") {
|
|
1540
1659
|
continue;
|
|
1541
1660
|
}
|
|
@@ -1544,6 +1663,7 @@ function emitHash(emitter, hash) {
|
|
|
1544
1663
|
if (key === null || value === null) {
|
|
1545
1664
|
continue;
|
|
1546
1665
|
}
|
|
1666
|
+
entries.push(writtenEntry(emitter, value, pair));
|
|
1547
1667
|
const keyText = pairKeyText(key);
|
|
1548
1668
|
if (keyText === null) {
|
|
1549
1669
|
add(emitter, "holdsUnderKey", objectKey, valueKey(emitter, value, pair));
|
|
@@ -1557,32 +1677,66 @@ function emitHash(emitter, hash) {
|
|
|
1557
1677
|
valueKey(emitter, value, pair)
|
|
1558
1678
|
);
|
|
1559
1679
|
}
|
|
1680
|
+
addEntryRows(rowsOf(emitter), objectKey, entries);
|
|
1560
1681
|
}
|
|
1561
1682
|
var BLOCK_TYPES3 = /* @__PURE__ */ new Set(["block", "do_block"]);
|
|
1562
1683
|
var LOOP_METHODS = /* @__PURE__ */ new Set(["each", "each_with_index", "map"]);
|
|
1563
|
-
var
|
|
1564
|
-
function
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
}
|
|
1568
|
-
const receiver = field(call, "receiver");
|
|
1569
|
-
const method = field(call, "method");
|
|
1684
|
+
var COUNTING_LOOP = "each_with_index";
|
|
1685
|
+
function emitLoopVariables(emitter, block, call) {
|
|
1686
|
+
const receiver = call.type === "call" ? field(call, "receiver") : null;
|
|
1687
|
+
const method = receiver === null ? null : field(call, "method");
|
|
1570
1688
|
if (receiver === null || method === null || !LOOP_METHODS.has(method.text)) {
|
|
1571
|
-
return
|
|
1689
|
+
return;
|
|
1572
1690
|
}
|
|
1573
|
-
const
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1691
|
+
const variables = children(field(block, "parameters")).filter(
|
|
1692
|
+
(variable) => variable.type !== "block_parameter"
|
|
1693
|
+
);
|
|
1694
|
+
const counting = method.text === COUNTING_LOOP;
|
|
1695
|
+
const [first, position] = variables;
|
|
1696
|
+
if (first === void 0 || counting && variables.length > 2) {
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
const taken = counting || variables.length === 1 ? elementTakenBy(first) : partsTakenBy(variables);
|
|
1700
|
+
const blockKey = nodeId(emitter.filePath, block);
|
|
1701
|
+
const over = valueKey(emitter, receiver, call);
|
|
1702
|
+
for (const variable of taken) {
|
|
1703
|
+
const key = `${blockKey}#${variable.name}`;
|
|
1704
|
+
if (variable.part === null) {
|
|
1705
|
+
add(emitter, "elementOf", key, over);
|
|
1706
|
+
continue;
|
|
1707
|
+
}
|
|
1708
|
+
add(emitter, "elementPartOf", key, over, variable.part);
|
|
1709
|
+
}
|
|
1710
|
+
const [anchor] = taken;
|
|
1711
|
+
if (counting && position?.type === "identifier" && anchor !== void 0) {
|
|
1712
|
+
add(
|
|
1713
|
+
emitter,
|
|
1714
|
+
"positionOf",
|
|
1715
|
+
`${blockKey}#${position.text}`,
|
|
1716
|
+
`${blockKey}#${anchor.name}`
|
|
1717
|
+
);
|
|
1578
1718
|
}
|
|
1579
|
-
return {
|
|
1580
|
-
element,
|
|
1581
|
-
index: names[1] ?? "",
|
|
1582
|
-
overKey: nodeId(emitter.filePath, receiver)
|
|
1583
|
-
};
|
|
1584
1719
|
}
|
|
1585
|
-
function
|
|
1720
|
+
function elementTakenBy(variable) {
|
|
1721
|
+
if (variable.type === "identifier") {
|
|
1722
|
+
return [{ name: variable.text, part: null }];
|
|
1723
|
+
}
|
|
1724
|
+
return variable.type === "destructured_parameter" ? partsTakenBy(children(variable)) : [];
|
|
1725
|
+
}
|
|
1726
|
+
function partsTakenBy(variables) {
|
|
1727
|
+
const parts = [];
|
|
1728
|
+
for (const [position, variable] of variables.entries()) {
|
|
1729
|
+
if (variable.type === "splat_parameter") {
|
|
1730
|
+
break;
|
|
1731
|
+
}
|
|
1732
|
+
if (variable.type === "identifier") {
|
|
1733
|
+
parts.push({ name: variable.text, part: String(position) });
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
return parts;
|
|
1737
|
+
}
|
|
1738
|
+
var DEFINE_METHOD_CALL = "define_method";
|
|
1739
|
+
function emitDynamicDefinition(emitter, call, type) {
|
|
1586
1740
|
if (emitter.selfKey === null || // A call inside a method runs when the method runs, not when the class loads.
|
|
1587
1741
|
emitter.enclosing !== null || type !== "call" || field(call, "receiver") !== null || field(call, "method")?.text !== DEFINE_METHOD_CALL) {
|
|
1588
1742
|
return;
|
|
@@ -1591,33 +1745,16 @@ function emitDynamicDefinition(emitter, call, type, turns) {
|
|
|
1591
1745
|
const first = args === null ? void 0 : children(args)[0];
|
|
1592
1746
|
const nameKey2 = nodeId(emitter.filePath, first ?? call);
|
|
1593
1747
|
add(emitter, "definesMethodFrom", emitter.selfKey, nameKey2);
|
|
1594
|
-
for (const turn of turns) {
|
|
1595
|
-
add(
|
|
1596
|
-
emitter,
|
|
1597
|
-
"nameTurnsOn",
|
|
1598
|
-
nameKey2,
|
|
1599
|
-
turn.element,
|
|
1600
|
-
turn.index,
|
|
1601
|
-
turn.overKey
|
|
1602
|
-
);
|
|
1603
|
-
}
|
|
1604
1748
|
}
|
|
1605
|
-
function walkExpressions(node,
|
|
1749
|
+
function walkExpressions(node, visit, nested = null) {
|
|
1606
1750
|
for (const child of children(node)) {
|
|
1607
1751
|
const type = child.type;
|
|
1608
1752
|
if (OWN_BODY_TYPES.has(type)) {
|
|
1609
1753
|
nested?.push(child);
|
|
1610
1754
|
continue;
|
|
1611
1755
|
}
|
|
1612
|
-
visit(child, type, node
|
|
1613
|
-
|
|
1614
|
-
walkExpressions(
|
|
1615
|
-
child,
|
|
1616
|
-
emitter,
|
|
1617
|
-
visit,
|
|
1618
|
-
nested,
|
|
1619
|
-
opened === null ? turns : [...turns, opened]
|
|
1620
|
-
);
|
|
1756
|
+
visit(child, type, node);
|
|
1757
|
+
walkExpressions(child, visit, nested);
|
|
1621
1758
|
}
|
|
1622
1759
|
}
|
|
1623
1760
|
var WRITTEN_KEY_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -1631,13 +1768,16 @@ function emitKeyedRead(emitter, site, container, key, keyParent) {
|
|
|
1631
1768
|
if (WRITTEN_KEY_TYPES.has(key.type)) {
|
|
1632
1769
|
return;
|
|
1633
1770
|
}
|
|
1771
|
+
const siteKey = nodeId(emitter.filePath, site);
|
|
1772
|
+
const containerKey = valueKey(emitter, container, site);
|
|
1634
1773
|
add(
|
|
1635
1774
|
emitter,
|
|
1636
1775
|
"readsKeyed",
|
|
1637
|
-
|
|
1638
|
-
|
|
1776
|
+
siteKey,
|
|
1777
|
+
containerKey,
|
|
1639
1778
|
valueKey(emitter, key, keyParent)
|
|
1640
1779
|
);
|
|
1780
|
+
add(emitter, "choosesEntry", siteKey, containerKey);
|
|
1641
1781
|
}
|
|
1642
1782
|
function emitKeyedElement(emitter, node, parent) {
|
|
1643
1783
|
const object = field(node, "object");
|
|
@@ -1698,14 +1838,14 @@ function raises(written, enclosing) {
|
|
|
1698
1838
|
return RAISING_METHODS2.has(field(node, "method")?.text ?? "") && (receiver === null || receiver.text === "Kernel");
|
|
1699
1839
|
}
|
|
1700
1840
|
function emitExpressionFacts(emitter, node) {
|
|
1701
|
-
emitDynamicDefinition(emitter, node, node.type
|
|
1702
|
-
walkExpressions(node,
|
|
1841
|
+
emitDynamicDefinition(emitter, node, node.type);
|
|
1842
|
+
walkExpressions(node, (child, type, parent) => {
|
|
1703
1843
|
const site = callSiteAt(emitter, child, type, parent);
|
|
1704
|
-
emitExpressionFact(emitter, child, type, parent,
|
|
1844
|
+
emitExpressionFact(emitter, child, type, parent, site);
|
|
1705
1845
|
});
|
|
1706
1846
|
}
|
|
1707
|
-
function emitExpressionFact(emitter, child, type, parent,
|
|
1708
|
-
emitDynamicDefinition(emitter, child, type
|
|
1847
|
+
function emitExpressionFact(emitter, child, type, parent, site) {
|
|
1848
|
+
emitDynamicDefinition(emitter, child, type);
|
|
1709
1849
|
if (site !== null) {
|
|
1710
1850
|
emitCall(emitter, site);
|
|
1711
1851
|
emitKeyedFetch(emitter, site);
|
|
@@ -1746,6 +1886,11 @@ function emitExpressionFact(emitter, child, type, parent, turns, site) {
|
|
|
1746
1886
|
}
|
|
1747
1887
|
if (BLOCK_TYPES3.has(type)) {
|
|
1748
1888
|
emitBlockValue(emitter, child);
|
|
1889
|
+
emitLoopVariables(emitter, child, parent);
|
|
1890
|
+
}
|
|
1891
|
+
const pieces = TEMPLATE_PIECES[type]?.(emitter, child) ?? [];
|
|
1892
|
+
if (pieces.length > 0) {
|
|
1893
|
+
addTemplateRows(rowsOf(emitter), nodeId(emitter.filePath, child), pieces);
|
|
1749
1894
|
}
|
|
1750
1895
|
for (const branch of BRANCHES_OF[type]?.(child) ?? []) {
|
|
1751
1896
|
add(
|
|
@@ -1765,6 +1910,29 @@ function emitExpressionFact(emitter, child, type, parent, turns, site) {
|
|
|
1765
1910
|
emitParameterDefault(emitter, child);
|
|
1766
1911
|
}
|
|
1767
1912
|
}
|
|
1913
|
+
function interpolatedPieces(emitter, string) {
|
|
1914
|
+
const parts = children(string);
|
|
1915
|
+
if (!parts.some((part) => part.type === "interpolation")) {
|
|
1916
|
+
return [];
|
|
1917
|
+
}
|
|
1918
|
+
return parts.flatMap((part) => {
|
|
1919
|
+
if (part.type === "string_content") {
|
|
1920
|
+
return [{ text: part.text }];
|
|
1921
|
+
}
|
|
1922
|
+
const expression = part.type === "interpolation" ? children(part)[0] : void 0;
|
|
1923
|
+
return expression === void 0 ? [] : [{ hole: valueKey(emitter, expression, part) }];
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
function adjacentPieces(emitter, joined2) {
|
|
1927
|
+
return children(joined2).map((part) => ({
|
|
1928
|
+
hole: valueKey(emitter, part, joined2)
|
|
1929
|
+
}));
|
|
1930
|
+
}
|
|
1931
|
+
var TEMPLATE_PIECES = {
|
|
1932
|
+
string: interpolatedPieces,
|
|
1933
|
+
delimited_symbol: interpolatedPieces,
|
|
1934
|
+
chained_string: adjacentPieces
|
|
1935
|
+
};
|
|
1768
1936
|
function emitBlockArgument(emitter, argument) {
|
|
1769
1937
|
const [handed] = children(argument);
|
|
1770
1938
|
if (handed !== void 0) {
|
|
@@ -2187,11 +2355,10 @@ function emitMethodFacts(emitter, method) {
|
|
|
2187
2355
|
const collecting = { ...inside, heldRows: expressionFacts };
|
|
2188
2356
|
walkExpressions(
|
|
2189
2357
|
body,
|
|
2190
|
-
|
|
2191
|
-
(child, type, parent, turns) => {
|
|
2358
|
+
(child, type, parent) => {
|
|
2192
2359
|
const site = callSiteAt(inside, child, type, parent);
|
|
2193
2360
|
emitBodyFact(bodyFacts, inside, funcKey, child, type, site);
|
|
2194
|
-
emitExpressionFact(collecting, child, type, parent,
|
|
2361
|
+
emitExpressionFact(collecting, child, type, parent, site);
|
|
2195
2362
|
},
|
|
2196
2363
|
nested
|
|
2197
2364
|
);
|
|
@@ -3675,7 +3842,7 @@ function contextOver(db, nodes) {
|
|
|
3675
3842
|
}
|
|
3676
3843
|
|
|
3677
3844
|
// src/values/literals.ts
|
|
3678
|
-
import { force as force2, literalOf as literalOf2 } from "@suss/values";
|
|
3845
|
+
import { force as force2, literalOf as literalOf2, sequence, text as text2 } from "@suss/values";
|
|
3679
3846
|
function literalElementsIn(value) {
|
|
3680
3847
|
if (value.kind !== "sequence") {
|
|
3681
3848
|
return null;
|
|
@@ -3690,8 +3857,24 @@ function literalElementsIn(value) {
|
|
|
3690
3857
|
}
|
|
3691
3858
|
return elements;
|
|
3692
3859
|
}
|
|
3693
|
-
function
|
|
3694
|
-
|
|
3860
|
+
function loopElementsOf(node, db) {
|
|
3861
|
+
const value = evaluatedValue(node, db);
|
|
3862
|
+
if (value.kind === "sequence") {
|
|
3863
|
+
return value.items.map((item) => elementOfList(force2(item.value)));
|
|
3864
|
+
}
|
|
3865
|
+
if (value.kind === "record" && !value.open) {
|
|
3866
|
+
return [...value.fields].map(([key, item]) => {
|
|
3867
|
+
const parts = [text2(key), force2(item.value)];
|
|
3868
|
+
return { whole: sequence(parts), parts };
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3871
|
+
return null;
|
|
3872
|
+
}
|
|
3873
|
+
function elementOfList(whole) {
|
|
3874
|
+
return {
|
|
3875
|
+
whole,
|
|
3876
|
+
parts: whole.kind === "sequence" ? whole.items.map((item) => force2(item.value)) : [whole]
|
|
3877
|
+
};
|
|
3695
3878
|
}
|
|
3696
3879
|
function namesOf(node, db) {
|
|
3697
3880
|
const value = evaluatedValue(node, db);
|
|
@@ -3713,13 +3896,16 @@ function definedNamesOf(dynamic, classKey) {
|
|
|
3713
3896
|
}
|
|
3714
3897
|
function readDynamicNames(db, rootsByFile) {
|
|
3715
3898
|
const byClass = /* @__PURE__ */ new Map();
|
|
3716
|
-
|
|
3899
|
+
const definitions = db.facts("definesMethodFrom");
|
|
3900
|
+
const loops = definitions.length === 0 ? /* @__PURE__ */ new Map() : loopsByFile(db);
|
|
3901
|
+
for (const [classKey, nameKey2] of definitions) {
|
|
3717
3902
|
const key = String(classKey);
|
|
3903
|
+
const around = loopsAround(loops, key, String(nameKey2));
|
|
3718
3904
|
byClass.set(
|
|
3719
3905
|
key,
|
|
3720
3906
|
foldReading(
|
|
3721
3907
|
byClass.get(key) ?? NOTHING,
|
|
3722
|
-
readOne(db, rootsByFile, String(nameKey2))
|
|
3908
|
+
readOne(db, rootsByFile, String(nameKey2), around)
|
|
3723
3909
|
)
|
|
3724
3910
|
);
|
|
3725
3911
|
}
|
|
@@ -3740,11 +3926,11 @@ function foldReading(soFar, reading) {
|
|
|
3740
3926
|
unreadable: soFar.unreadable
|
|
3741
3927
|
};
|
|
3742
3928
|
}
|
|
3743
|
-
function readOne(db, rootsByFile, nameKey2) {
|
|
3929
|
+
function readOne(db, rootsByFile, nameKey2, loops) {
|
|
3744
3930
|
const node = nodeOfKey2(rootsByFile, nameKey2);
|
|
3745
3931
|
const names = [];
|
|
3746
3932
|
const patterns = [];
|
|
3747
|
-
for (const bindings of loopTurns(db, rootsByFile,
|
|
3933
|
+
for (const bindings of loopTurns(db, rootsByFile, loops)) {
|
|
3748
3934
|
const value = node === null ? hole2(nameKey2) : evaluatedValue(node, db, bindings.size === 0 ? void 0 : bindings);
|
|
3749
3935
|
const name = literalOf3(value);
|
|
3750
3936
|
if (name !== null) {
|
|
@@ -3777,38 +3963,105 @@ function patternOf(value) {
|
|
|
3777
3963
|
}
|
|
3778
3964
|
return readSomething ? new RegExp(`${source}$`) : null;
|
|
3779
3965
|
}
|
|
3780
|
-
function escapeForPattern(
|
|
3781
|
-
return
|
|
3966
|
+
function escapeForPattern(text3) {
|
|
3967
|
+
return text3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3782
3968
|
}
|
|
3783
|
-
function loopTurns(db, rootsByFile,
|
|
3969
|
+
function loopTurns(db, rootsByFile, loops) {
|
|
3784
3970
|
let turns = [/* @__PURE__ */ new Map()];
|
|
3785
|
-
for (const
|
|
3971
|
+
for (const loop of loops) {
|
|
3972
|
+
const bindings = bindingsOf(db, rootsByFile, loop);
|
|
3973
|
+
if (bindings === null) {
|
|
3974
|
+
continue;
|
|
3975
|
+
}
|
|
3786
3976
|
turns = turns.flatMap(
|
|
3787
|
-
(base) =>
|
|
3788
|
-
const binding = new Map([...base, [over.element, value]]);
|
|
3789
|
-
if (over.index !== "") {
|
|
3790
|
-
binding.set(over.index, String(position));
|
|
3791
|
-
}
|
|
3792
|
-
return binding;
|
|
3793
|
-
})
|
|
3977
|
+
(base) => bindings.map((binding) => new Map([...base, ...binding]))
|
|
3794
3978
|
);
|
|
3795
3979
|
}
|
|
3796
3980
|
return turns;
|
|
3797
3981
|
}
|
|
3798
|
-
function
|
|
3799
|
-
const
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
)
|
|
3805
|
-
const
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3982
|
+
function bindingsOf(db, rootsByFile, loop) {
|
|
3983
|
+
const node = collectionNode(rootsByFile, loop);
|
|
3984
|
+
const elements = node === null ? null : loopElementsOf(node, db);
|
|
3985
|
+
if (elements === null) {
|
|
3986
|
+
return null;
|
|
3987
|
+
}
|
|
3988
|
+
const bound = [...loop.variables].flatMap(([name, takes]) => {
|
|
3989
|
+
const values = elements.map(
|
|
3990
|
+
(element, position) => GIVEN[takes.kind](element, position, takes)
|
|
3991
|
+
);
|
|
3992
|
+
return values.every((value) => value !== null) ? [{ name, values }] : [];
|
|
3993
|
+
});
|
|
3994
|
+
if (bound.length === 0) {
|
|
3995
|
+
return null;
|
|
3996
|
+
}
|
|
3997
|
+
return elements.map(
|
|
3998
|
+
(_, position) => new Map(bound.map(({ name, values }) => [name, values[position] ?? ""]))
|
|
3999
|
+
);
|
|
4000
|
+
}
|
|
4001
|
+
var GIVEN = {
|
|
4002
|
+
element: (element) => literalOf3(element.whole),
|
|
4003
|
+
part: (element, _, takes) => {
|
|
4004
|
+
const part = takes.kind === "part" ? element.parts[takes.part] : void 0;
|
|
4005
|
+
return part === void 0 ? null : literalOf3(part);
|
|
4006
|
+
},
|
|
4007
|
+
position: (_, position) => String(position)
|
|
4008
|
+
};
|
|
4009
|
+
function collectionNode(rootsByFile, loop) {
|
|
4010
|
+
const written = nodeOfKey2(rootsByFile, loop.over);
|
|
4011
|
+
if (written !== null) {
|
|
4012
|
+
return written;
|
|
4013
|
+
}
|
|
4014
|
+
const call = nodeOfKey2(rootsByFile, loop.block.key)?.parent ?? null;
|
|
4015
|
+
return call === null ? null : field(call, "receiver");
|
|
4016
|
+
}
|
|
4017
|
+
function blockVariableOf(key) {
|
|
4018
|
+
const at = key.lastIndexOf("#");
|
|
4019
|
+
const span = at < 0 ? null : spanOfKey(key.slice(0, at));
|
|
4020
|
+
return span === null ? null : { block: { ...span, key: key.slice(0, at) }, name: key.slice(at + 1) };
|
|
4021
|
+
}
|
|
4022
|
+
function loopsByFile(db) {
|
|
4023
|
+
const blocks = /* @__PURE__ */ new Map();
|
|
4024
|
+
const note = (key, over, takes) => {
|
|
4025
|
+
const variable = blockVariableOf(String(key));
|
|
4026
|
+
if (variable === null) {
|
|
4027
|
+
return;
|
|
3809
4028
|
}
|
|
4029
|
+
const known = blocks.get(variable.block.key);
|
|
4030
|
+
const loop = known ?? {
|
|
4031
|
+
block: variable.block,
|
|
4032
|
+
over: String(over),
|
|
4033
|
+
variables: /* @__PURE__ */ new Map()
|
|
4034
|
+
};
|
|
4035
|
+
loop.variables.set(variable.name, takes);
|
|
4036
|
+
blocks.set(variable.block.key, loop);
|
|
4037
|
+
};
|
|
4038
|
+
for (const [element, over] of db.facts("elementOf")) {
|
|
4039
|
+
note(element, over, { kind: "element" });
|
|
3810
4040
|
}
|
|
3811
|
-
|
|
4041
|
+
for (const [element, over, part] of db.facts("elementPartOf")) {
|
|
4042
|
+
note(element, over, { kind: "part", part: Number(part) });
|
|
4043
|
+
}
|
|
4044
|
+
for (const [position, element] of db.facts("positionOf")) {
|
|
4045
|
+
const block = blockVariableOf(String(element))?.block.key;
|
|
4046
|
+
if (block !== void 0 && blocks.has(block)) {
|
|
4047
|
+
note(position, blocks.get(block)?.over, { kind: "position" });
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
4051
|
+
for (const loop of blocks.values()) {
|
|
4052
|
+
byFile.set(loop.block.file, [...byFile.get(loop.block.file) ?? [], loop]);
|
|
4053
|
+
}
|
|
4054
|
+
return byFile;
|
|
4055
|
+
}
|
|
4056
|
+
function loopsAround(loops, classKey, nameKey2) {
|
|
4057
|
+
const cls = spanOfKey(classKey);
|
|
4058
|
+
const name = spanOfKey(nameKey2);
|
|
4059
|
+
if (cls === null || name === null) {
|
|
4060
|
+
return [];
|
|
4061
|
+
}
|
|
4062
|
+
return (loops.get(name.file) ?? []).filter(
|
|
4063
|
+
({ block }) => cls.start <= block.start && block.end <= cls.end && block.start <= name.start && name.end <= block.end
|
|
4064
|
+
).sort((a, b) => a.block.start - b.block.start);
|
|
3812
4065
|
}
|
|
3813
4066
|
|
|
3814
4067
|
// src/scope.ts
|
|
@@ -4567,9 +4820,9 @@ var BLOCK_TYPES5 = /* @__PURE__ */ new Set([
|
|
|
4567
4820
|
]);
|
|
4568
4821
|
function literalArgOf(node, facts) {
|
|
4569
4822
|
const value = evaluatedValue(node, facts);
|
|
4570
|
-
const
|
|
4571
|
-
if (
|
|
4572
|
-
return { kind: "string", value:
|
|
4823
|
+
const text3 = literalOf4(value);
|
|
4824
|
+
if (text3 !== null) {
|
|
4825
|
+
return { kind: "string", value: text3 };
|
|
4573
4826
|
}
|
|
4574
4827
|
const constant2 = constantOf(value);
|
|
4575
4828
|
if (typeof constant2 === "number") {
|
|
@@ -4635,7 +4888,7 @@ function isCall(node, locals, inherited) {
|
|
|
4635
4888
|
}
|
|
4636
4889
|
function collectCalls(node, read, inherited, found) {
|
|
4637
4890
|
for (const child of children(node)) {
|
|
4638
|
-
if (read.stops.has(child.type)) {
|
|
4891
|
+
if (read.stops.has(child.type) && !isLambdaArgument(child)) {
|
|
4639
4892
|
continue;
|
|
4640
4893
|
}
|
|
4641
4894
|
if (isCall(child, read.locals, inherited)) {
|
|
@@ -4645,6 +4898,9 @@ function collectCalls(node, read, inherited, found) {
|
|
|
4645
4898
|
}
|
|
4646
4899
|
return found;
|
|
4647
4900
|
}
|
|
4901
|
+
function isLambdaArgument(node) {
|
|
4902
|
+
return node.type === LAMBDA_TYPE && node.parent?.type === "argument_list";
|
|
4903
|
+
}
|
|
4648
4904
|
function methodBody(definitionNode) {
|
|
4649
4905
|
const body = field(definitionNode, "body");
|
|
4650
4906
|
if (body === null) {
|
|
@@ -7572,7 +7828,7 @@ function envSiteAt(node) {
|
|
|
7572
7828
|
|
|
7573
7829
|
// src/filters.ts
|
|
7574
7830
|
var RESCUES_NOTHING = { refs: [], someUnread: false };
|
|
7575
|
-
function
|
|
7831
|
+
function controllerFilterChain(pattern, ancestry, read = {}) {
|
|
7576
7832
|
const forms = pattern.filters ?? [];
|
|
7577
7833
|
if (forms.length === 0) {
|
|
7578
7834
|
return [];
|
|
@@ -7616,27 +7872,47 @@ function controllerFilters(pattern, ancestry, read = {}) {
|
|
|
7616
7872
|
declared = applySkips(declared, skipsOf(statement, skipped, read.facts));
|
|
7617
7873
|
}
|
|
7618
7874
|
}
|
|
7619
|
-
const resolved =
|
|
7620
|
-
|
|
7621
|
-
const written = writtenAt(
|
|
7875
|
+
const resolved = declared.map(
|
|
7876
|
+
(declaration) => linkFor(
|
|
7622
7877
|
declaration,
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7878
|
+
writtenAt(
|
|
7879
|
+
declaration,
|
|
7880
|
+
filterMethod(ancestry, declaration.methodName, read)
|
|
7881
|
+
)
|
|
7882
|
+
)
|
|
7883
|
+
);
|
|
7884
|
+
return [
|
|
7885
|
+
...resolved.filter((one) => !runsAfterARaise(one)),
|
|
7886
|
+
...resolved.filter(runsAfterARaise).reverse()
|
|
7887
|
+
];
|
|
7888
|
+
}
|
|
7889
|
+
function linkFor(declaration, written) {
|
|
7890
|
+
if (written === null) {
|
|
7891
|
+
return {
|
|
7892
|
+
unread: {
|
|
7893
|
+
filter: declaration.filter,
|
|
7894
|
+
methodName: declaration.methodName,
|
|
7895
|
+
declaredIn: declaration.declaredIn,
|
|
7896
|
+
only: declaration.only,
|
|
7897
|
+
except: declaration.except
|
|
7898
|
+
}
|
|
7899
|
+
};
|
|
7900
|
+
}
|
|
7901
|
+
return {
|
|
7902
|
+
read: {
|
|
7629
7903
|
filter: declaration.filter,
|
|
7630
7904
|
...written,
|
|
7631
7905
|
only: declaration.only,
|
|
7632
7906
|
except: declaration.except,
|
|
7633
7907
|
rescues: declaration.rescues
|
|
7634
|
-
}
|
|
7635
|
-
}
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7908
|
+
}
|
|
7909
|
+
};
|
|
7910
|
+
}
|
|
7911
|
+
function filterOf(link) {
|
|
7912
|
+
return "read" in link ? link.read : link.unread;
|
|
7913
|
+
}
|
|
7914
|
+
function runsAfterARaise(link) {
|
|
7915
|
+
return filterOf(link).filter.onThrow === true;
|
|
7640
7916
|
}
|
|
7641
7917
|
function writtenAt(declaration, found) {
|
|
7642
7918
|
if (found.type === "found") {
|
|
@@ -7687,6 +7963,13 @@ function filterReference(filter, displayPath, caught) {
|
|
|
7687
7963
|
}
|
|
7688
7964
|
};
|
|
7689
7965
|
}
|
|
7966
|
+
function unreadFilterReference(filter, displayPath) {
|
|
7967
|
+
return {
|
|
7968
|
+
file: displayPath,
|
|
7969
|
+
name: filter.methodName,
|
|
7970
|
+
...filter.filter.onThrow === true ? { onThrow: true } : {}
|
|
7971
|
+
};
|
|
7972
|
+
}
|
|
7690
7973
|
function filterUnit(filter, pattern, displayPath, body, reading = {}) {
|
|
7691
7974
|
const range = rangeOf(filter.method);
|
|
7692
7975
|
const { respondingHelper, raises: raises2 } = reading;
|
|
@@ -7770,6 +8053,7 @@ function declarationsOf(statement, filter, declaredIn, facts, inlineOrdinal) {
|
|
|
7770
8053
|
only,
|
|
7771
8054
|
except: except ?? /* @__PURE__ */ new Set(),
|
|
7772
8055
|
rescues: rescues2,
|
|
8056
|
+
declaredIn: declaredIn.file,
|
|
7773
8057
|
...inline === void 0 ? {} : { inline }
|
|
7774
8058
|
}));
|
|
7775
8059
|
}
|
|
@@ -8762,8 +9046,8 @@ function moduleOfConstant(node, options) {
|
|
|
8762
9046
|
const files = [...new Set(keys.map(fileOfKey))];
|
|
8763
9047
|
return files.length === 1 ? options.displayPathOf(files[0]) : null;
|
|
8764
9048
|
}
|
|
8765
|
-
function oneLine(
|
|
8766
|
-
return
|
|
9049
|
+
function oneLine(text3) {
|
|
9050
|
+
return text3.replace(/\s*\n\s*/g, " ").trim();
|
|
8767
9051
|
}
|
|
8768
9052
|
|
|
8769
9053
|
// src/testClasses.ts
|
|
@@ -9205,11 +9489,12 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9205
9489
|
])) {
|
|
9206
9490
|
return [];
|
|
9207
9491
|
}
|
|
9208
|
-
const
|
|
9492
|
+
const chain = controllerFilterChain(pattern, ancestry, {
|
|
9209
9493
|
facts: options.facts,
|
|
9210
9494
|
bodyBlocks: options.bodyBlocks,
|
|
9211
9495
|
dynamicNames: options.dynamicNames
|
|
9212
9496
|
});
|
|
9497
|
+
const filters = chain.flatMap((link) => "read" in link ? [link.read] : []);
|
|
9213
9498
|
const units = [];
|
|
9214
9499
|
const actions = controllerActions(
|
|
9215
9500
|
pattern,
|
|
@@ -9240,10 +9525,10 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9240
9525
|
return classes === void 0 ? [] : [classes];
|
|
9241
9526
|
});
|
|
9242
9527
|
for (const filter of filters) {
|
|
9243
|
-
const
|
|
9528
|
+
const displayPath2 = options.displayPathOf?.(filter.file) ?? filter.file;
|
|
9244
9529
|
const body = bodyOfMethod(filter.method, filter.file, options);
|
|
9245
9530
|
const handler = filter.filter.onThrow === true;
|
|
9246
|
-
const raw = filterUnit(filter, pattern,
|
|
9531
|
+
const raw = filterUnit(filter, pattern, displayPath2, body, {
|
|
9247
9532
|
facts: options.facts,
|
|
9248
9533
|
respondingHelper,
|
|
9249
9534
|
...handler ? {} : {
|
|
@@ -9271,14 +9556,14 @@ async function controllerActionUnits(pattern, pack, info, ownBlocks, fileBlocks,
|
|
|
9271
9556
|
enclosingQualifiedName: filter.enclosingQualifiedName
|
|
9272
9557
|
});
|
|
9273
9558
|
}
|
|
9559
|
+
const displayPath = (file) => options.displayPathOf?.(file) ?? file;
|
|
9560
|
+
const referenceTo = (link) => "read" in link ? filterReference(
|
|
9561
|
+
link.read,
|
|
9562
|
+
displayPath(link.read.file),
|
|
9563
|
+
caught.get(link.read)
|
|
9564
|
+
) : unreadFilterReference(link.unread, displayPath(link.unread.declaredIn));
|
|
9274
9565
|
const emitAction = async (actionName, method, block, routes) => {
|
|
9275
|
-
const around =
|
|
9276
|
-
(filter) => filterReference(
|
|
9277
|
-
filter,
|
|
9278
|
-
options.displayPathOf?.(filter.file) ?? filter.file,
|
|
9279
|
-
caught.get(filter)
|
|
9280
|
-
)
|
|
9281
|
-
);
|
|
9566
|
+
const around = chain.filter((link) => filterCoversAction(filterOf(link), actionName)).map((link) => referenceTo(link));
|
|
9282
9567
|
const raises2 = {
|
|
9283
9568
|
classes: await raisedClasses(method, block.info.bodyNesting, exceptions),
|
|
9284
9569
|
handlers: handlersAround(actionName)
|
|
@@ -10307,6 +10592,7 @@ import {
|
|
|
10307
10592
|
placeArgTargets as placeArgTargets2,
|
|
10308
10593
|
placeCalleeParameters as placeCalleeParameters2,
|
|
10309
10594
|
placeCalls as placeCalls2,
|
|
10595
|
+
placePossibleCalls as placePossibleCalls2,
|
|
10310
10596
|
placeReceiverClasses,
|
|
10311
10597
|
recordParameterGaps as recordParameterGaps2,
|
|
10312
10598
|
summaryIdFromParts,
|
|
@@ -10318,11 +10604,13 @@ import {
|
|
|
10318
10604
|
composeWrappers,
|
|
10319
10605
|
createCacheLayer,
|
|
10320
10606
|
createTimer,
|
|
10607
|
+
extractionCacheDirFor,
|
|
10321
10608
|
extractionConfigStamp,
|
|
10322
10609
|
KeptParses,
|
|
10323
10610
|
matchesTestFileName as matchesTestFileName3,
|
|
10324
10611
|
moduleInitStructure,
|
|
10325
10612
|
noopTimer,
|
|
10613
|
+
ownersWhereWritten,
|
|
10326
10614
|
runDigest,
|
|
10327
10615
|
stampModuleImports,
|
|
10328
10616
|
stampModules
|
|
@@ -10533,6 +10821,7 @@ import {
|
|
|
10533
10821
|
placeArgTargets,
|
|
10534
10822
|
placeCalleeParameters,
|
|
10535
10823
|
placeCalls,
|
|
10824
|
+
placePossibleCalls,
|
|
10536
10825
|
ReceiverClasses,
|
|
10537
10826
|
recordParameterGaps,
|
|
10538
10827
|
StopList,
|
|
@@ -10608,8 +10897,8 @@ function flagsDeclaredIn(construction) {
|
|
|
10608
10897
|
return flags;
|
|
10609
10898
|
}
|
|
10610
10899
|
function flagOf(args) {
|
|
10611
|
-
const written = args.map((arg) => stringLiteralValue(arg)).filter((
|
|
10612
|
-
const chosen = written.find((
|
|
10900
|
+
const written = args.map((arg) => stringLiteralValue(arg)).filter((text3) => text3 !== null && text3.startsWith("-"));
|
|
10901
|
+
const chosen = written.find((text3) => text3.startsWith("--")) ?? written[0] ?? null;
|
|
10613
10902
|
if (chosen === null) {
|
|
10614
10903
|
return null;
|
|
10615
10904
|
}
|
|
@@ -10651,10 +10940,9 @@ import {
|
|
|
10651
10940
|
calleeOutcomeOf,
|
|
10652
10941
|
calleeOutcomes,
|
|
10653
10942
|
classMemberName as classMemberName3,
|
|
10654
|
-
couldBeSettled
|
|
10943
|
+
couldBeSettled,
|
|
10944
|
+
dispatchOutcomes
|
|
10655
10945
|
} from "@suss/resolution";
|
|
10656
|
-
var DYNAMIC_SEND_NAMES = /* @__PURE__ */ new Set(["send", "public_send", "__send__"]);
|
|
10657
|
-
var INVOKES_RECEIVER = "call";
|
|
10658
10946
|
var STOP_FOR = {
|
|
10659
10947
|
severalSources: "multipleSources",
|
|
10660
10948
|
outsideRun: "outsideRun",
|
|
@@ -10737,6 +11025,57 @@ function loaderSourceCallee(call, site, ctx) {
|
|
|
10737
11025
|
}
|
|
10738
11026
|
return null;
|
|
10739
11027
|
}
|
|
11028
|
+
function dispatchedCalls(calls, ctx) {
|
|
11029
|
+
const byKey = new Map(
|
|
11030
|
+
calls.map((one) => [nodeId(one.site.file, one.call), one])
|
|
11031
|
+
);
|
|
11032
|
+
const found = /* @__PURE__ */ new Map();
|
|
11033
|
+
const outcomes = dispatchOutcomes(ctx.facts, [...byKey.keys()], RUBY_PROGRAM);
|
|
11034
|
+
for (const [key, outcome] of outcomes) {
|
|
11035
|
+
const asked = byKey.get(key);
|
|
11036
|
+
if (asked === void 0) {
|
|
11037
|
+
continue;
|
|
11038
|
+
}
|
|
11039
|
+
const fits = sendFits(asked.call, asked.site, ctx);
|
|
11040
|
+
const targets = /* @__PURE__ */ new Map();
|
|
11041
|
+
for (const fn of outcome.functions) {
|
|
11042
|
+
for (const target of reachedThrough(fn, outcome.through, ctx)) {
|
|
11043
|
+
if (fits(target)) {
|
|
11044
|
+
targets.set(nodeId(target.file, target.node), target);
|
|
11045
|
+
}
|
|
11046
|
+
}
|
|
11047
|
+
}
|
|
11048
|
+
found.set(asked.call.id, {
|
|
11049
|
+
targets: [...targets.values()],
|
|
11050
|
+
certain: outcome.certain && outcome.functions.every((fn) => ctx.definitions.has(fn)),
|
|
11051
|
+
unresolved: outcome.unresolved
|
|
11052
|
+
});
|
|
11053
|
+
}
|
|
11054
|
+
return found;
|
|
11055
|
+
}
|
|
11056
|
+
function reachedThrough(key, through, ctx) {
|
|
11057
|
+
const own = ctx.definitions.get(key);
|
|
11058
|
+
if (own !== void 0) {
|
|
11059
|
+
return [own];
|
|
11060
|
+
}
|
|
11061
|
+
return (through.get(key) ?? []).flatMap((inner) => {
|
|
11062
|
+
const target = ctx.definitions.get(inner);
|
|
11063
|
+
return target === void 0 ? [] : [target];
|
|
11064
|
+
});
|
|
11065
|
+
}
|
|
11066
|
+
function sendFits(call, site, ctx) {
|
|
11067
|
+
const method = calleeMethodName(call);
|
|
11068
|
+
if (method === void 0 || !SENDING_METHODS.has(method)) {
|
|
11069
|
+
return () => true;
|
|
11070
|
+
}
|
|
11071
|
+
const receiver = field(call, "receiver");
|
|
11072
|
+
const toClass = receiver === null || receiver.type === "self" ? inClassMethod(site, ctx) : readsOffClassItself(
|
|
11073
|
+
receiver,
|
|
11074
|
+
readKey(site.file, receiver, site.method),
|
|
11075
|
+
classLocalsFor(call, site)
|
|
11076
|
+
);
|
|
11077
|
+
return (target) => definesClassMethod(target.node, ctx.bodyBlocks) === toClass;
|
|
11078
|
+
}
|
|
10740
11079
|
function outcomeFor(key, ctx, read) {
|
|
10741
11080
|
return read?.outcomes.get(key) ?? calleeOutcomeOf(ctx.facts, key, RUBY_PROGRAM);
|
|
10742
11081
|
}
|
|
@@ -10750,14 +11089,16 @@ function readsAsACall(call, site, ctx, read) {
|
|
|
10750
11089
|
return false;
|
|
10751
11090
|
}
|
|
10752
11091
|
const outcome = outcomeFor(spelling.key, ctx, read);
|
|
10753
|
-
return outcome.kind === "function" || outcome.kind === "object"
|
|
11092
|
+
return outcome.kind === "function" || outcome.kind === "object" || objectsBehind(ctx.facts, spelling.key).some(
|
|
11093
|
+
(key) => ctx.classNames.has(key)
|
|
11094
|
+
);
|
|
10754
11095
|
}
|
|
10755
11096
|
function spellingFor2(call, site) {
|
|
10756
11097
|
const methodName = calleeMethodName(call);
|
|
10757
11098
|
if (methodName === void 0) {
|
|
10758
11099
|
return { kind: "stopped", reason: "noDeclaration" };
|
|
10759
11100
|
}
|
|
10760
|
-
if (
|
|
11101
|
+
if (SENDING_METHODS.has(methodName)) {
|
|
10761
11102
|
return { kind: "stopped", reason: "unsettledValue" };
|
|
10762
11103
|
}
|
|
10763
11104
|
const receiver = field(call, "receiver");
|
|
@@ -10803,7 +11144,7 @@ function asCallee(spelling, outcome, site, ctx) {
|
|
|
10803
11144
|
return methodOnObject(spelling, objectKey, ctx);
|
|
10804
11145
|
}
|
|
10805
11146
|
if (outcome.kind === "function") {
|
|
10806
|
-
return spelling.method ===
|
|
11147
|
+
return spelling.method === INVOKE_METHOD ? functionCallee(outcome.key, ctx) : NO_DECLARATION;
|
|
10807
11148
|
}
|
|
10808
11149
|
return stop(STOP_FOR[outcome.kind] ?? "noDeclaration");
|
|
10809
11150
|
}
|
|
@@ -10847,7 +11188,7 @@ function scopeOn(qualifiedName, method, ctx) {
|
|
|
10847
11188
|
return null;
|
|
10848
11189
|
}
|
|
10849
11190
|
function fromCaller(spelling, parameterKey, site) {
|
|
10850
|
-
if (!parameterKey.startsWith(`${site.owner}#`) || spelling.method !==
|
|
11191
|
+
if (!parameterKey.startsWith(`${site.owner}#`) || spelling.method !== INVOKE_METHOD) {
|
|
10851
11192
|
return stop("unsettledValue");
|
|
10852
11193
|
}
|
|
10853
11194
|
return stop("callerSupplied");
|
|
@@ -10983,6 +11324,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
10983
11324
|
const targetsByKey = /* @__PURE__ */ new Map();
|
|
10984
11325
|
const stopsByKey = /* @__PURE__ */ new Map();
|
|
10985
11326
|
const argTargetsByKey = /* @__PURE__ */ new Map();
|
|
11327
|
+
const possibleTargetsByKey = /* @__PURE__ */ new Map();
|
|
10986
11328
|
const parameterCallsByKey = /* @__PURE__ */ new Map();
|
|
10987
11329
|
const propertyReadsByKey = /* @__PURE__ */ new Map();
|
|
10988
11330
|
const receiverClassesByKey = /* @__PURE__ */ new Map();
|
|
@@ -11041,6 +11383,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
11041
11383
|
}
|
|
11042
11384
|
targetsByKey.set(key, scan.targets);
|
|
11043
11385
|
argTargetsByKey.set(key, scan.argTargets);
|
|
11386
|
+
possibleTargetsByKey.set(key, scan.possibleTargets);
|
|
11044
11387
|
if (scan.propertyReads.size > 0) {
|
|
11045
11388
|
propertyReadsByKey.set(key, scan.propertyReads);
|
|
11046
11389
|
}
|
|
@@ -11104,6 +11447,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
11104
11447
|
}
|
|
11105
11448
|
placeCalls(summary2, targetsByKey.get(key));
|
|
11106
11449
|
placeArgTargets(summary2, argTargetsByKey.get(key));
|
|
11450
|
+
placePossibleCalls(summary2, possibleTargetsByKey.get(key));
|
|
11107
11451
|
placeCalleeParameters(summary2, parameterCallsByKey.get(key));
|
|
11108
11452
|
return summary2;
|
|
11109
11453
|
};
|
|
@@ -11126,6 +11470,7 @@ async function reachedFunctions(seeds, options) {
|
|
|
11126
11470
|
targetsByKey,
|
|
11127
11471
|
stopsByKey,
|
|
11128
11472
|
argTargetsByKey,
|
|
11473
|
+
possibleTargetsByKey,
|
|
11129
11474
|
parameterCallsByKey,
|
|
11130
11475
|
propertyReadsByKey,
|
|
11131
11476
|
receiverClassesByKey,
|
|
@@ -11155,36 +11500,70 @@ function batchedReads(round, options) {
|
|
|
11155
11500
|
const bodies = round.flatMap(
|
|
11156
11501
|
(entry) => "source" in entry ? [{ key: entry.key, ...bodyOf2(entry.source, options) }] : []
|
|
11157
11502
|
);
|
|
11158
|
-
const
|
|
11159
|
-
|
|
11160
|
-
|
|
11503
|
+
const written = bodies.flatMap((body) => body.written);
|
|
11504
|
+
const spellings = calleeSpellings(written, options.context);
|
|
11505
|
+
const dispatched = dispatchedAmong(written, spellings, options.context);
|
|
11506
|
+
return new Map(
|
|
11507
|
+
bodies.map((body) => [body.key, { ...body, spellings, dispatched }])
|
|
11508
|
+
);
|
|
11509
|
+
}
|
|
11510
|
+
function dispatchedAmong(written, spellings, ctx) {
|
|
11511
|
+
return dispatchedCalls(
|
|
11512
|
+
written.filter(({ call, site }) => {
|
|
11513
|
+
if (!mayRunAnEntry(call)) {
|
|
11514
|
+
return false;
|
|
11515
|
+
}
|
|
11516
|
+
const outcome = resolveCallee(call, site, ctx, spellings);
|
|
11517
|
+
return outcome.kind === "stopped" && outcome.reason !== "callerSupplied";
|
|
11518
|
+
}),
|
|
11519
|
+
ctx
|
|
11161
11520
|
);
|
|
11162
|
-
|
|
11521
|
+
}
|
|
11522
|
+
function mayRunAnEntry(call) {
|
|
11523
|
+
const sent = calleeMethodName(call);
|
|
11524
|
+
if (sent !== void 0 && SENDING_METHODS.has(sent)) {
|
|
11525
|
+
return true;
|
|
11526
|
+
}
|
|
11527
|
+
if (call.type !== "call" || field(call, "receiver") === null) {
|
|
11528
|
+
return false;
|
|
11529
|
+
}
|
|
11530
|
+
const method = field(call, "method");
|
|
11531
|
+
return method === null || method.text === INVOKE_METHOD;
|
|
11163
11532
|
}
|
|
11164
11533
|
function scanOnce(source, key, options, read, charges) {
|
|
11165
11534
|
const ledger = options.ledger;
|
|
11166
11535
|
if (ledger === void 0) {
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11536
|
+
return scanBody(
|
|
11537
|
+
source,
|
|
11538
|
+
options.context,
|
|
11539
|
+
options,
|
|
11540
|
+
read ?? ownReads(source, options)
|
|
11541
|
+
);
|
|
11172
11542
|
}
|
|
11173
11543
|
return ledger.charging(chargeOf(charges, key), () => {
|
|
11174
11544
|
forgetEvaluations(options.context.facts);
|
|
11175
11545
|
ledger.readFile(source.file);
|
|
11176
|
-
const
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11546
|
+
const scan = scanBody(
|
|
11547
|
+
source,
|
|
11548
|
+
options.context,
|
|
11549
|
+
options,
|
|
11550
|
+
ownReads(source, options)
|
|
11551
|
+
);
|
|
11182
11552
|
for (const target of scan.followed) {
|
|
11183
11553
|
ledger.touchKey(keyOf(target));
|
|
11184
11554
|
}
|
|
11185
11555
|
return scan;
|
|
11186
11556
|
});
|
|
11187
11557
|
}
|
|
11558
|
+
function ownReads(source, options) {
|
|
11559
|
+
const body = bodyOf2(source, options);
|
|
11560
|
+
const spellings = calleeSpellings(body.written, options.context);
|
|
11561
|
+
return {
|
|
11562
|
+
...body,
|
|
11563
|
+
spellings,
|
|
11564
|
+
dispatched: dispatchedAmong(body.written, spellings, options.context)
|
|
11565
|
+
};
|
|
11566
|
+
}
|
|
11188
11567
|
function storedScan(scan) {
|
|
11189
11568
|
return {
|
|
11190
11569
|
followed: scan.followed.map((target) => ({
|
|
@@ -11200,6 +11579,10 @@ function storedScan(scan) {
|
|
|
11200
11579
|
callee,
|
|
11201
11580
|
[...byPosition]
|
|
11202
11581
|
]),
|
|
11582
|
+
possibleTargets: [...scan.possibleTargets].map(([callee, places]) => [
|
|
11583
|
+
callee,
|
|
11584
|
+
[...places]
|
|
11585
|
+
]),
|
|
11203
11586
|
parameterCalls: [...scan.parameterCalls],
|
|
11204
11587
|
passedPositions: [...scan.passedPositions],
|
|
11205
11588
|
propertyReads: [...scan.propertyReads],
|
|
@@ -11217,6 +11600,7 @@ function scanFromStored(stored, functionFor) {
|
|
|
11217
11600
|
new Map(byPosition)
|
|
11218
11601
|
])
|
|
11219
11602
|
),
|
|
11603
|
+
possibleTargets: new Map(stored.possibleTargets),
|
|
11220
11604
|
parameterCalls: stored.parameterCalls,
|
|
11221
11605
|
passedPositions: new Set(stored.passedPositions),
|
|
11222
11606
|
propertyReads: new Set(stored.propertyReads),
|
|
@@ -11245,6 +11629,7 @@ var EMPTY_SCAN = {
|
|
|
11245
11629
|
stops: [],
|
|
11246
11630
|
targets: /* @__PURE__ */ new Map(),
|
|
11247
11631
|
argTargets: /* @__PURE__ */ new Map(),
|
|
11632
|
+
possibleTargets: /* @__PURE__ */ new Map(),
|
|
11248
11633
|
parameterCalls: [],
|
|
11249
11634
|
passedPositions: /* @__PURE__ */ new Set(),
|
|
11250
11635
|
propertyReads: /* @__PURE__ */ new Set(),
|
|
@@ -11266,7 +11651,7 @@ function bodyOf2(source, options) {
|
|
|
11266
11651
|
const file = run?.fileOf(call) ?? source.file;
|
|
11267
11652
|
return file === source.file ? site : { ...site, file, method: enclosingDefinition(call) };
|
|
11268
11653
|
};
|
|
11269
|
-
const written =
|
|
11654
|
+
const written = callsWrittenIn2(source.node, run, options);
|
|
11270
11655
|
const calls = callsReported(
|
|
11271
11656
|
written,
|
|
11272
11657
|
(call) => mightReadAsACall(call, siteFor(call), options.context)
|
|
@@ -11280,7 +11665,7 @@ function bodyOf2(source, options) {
|
|
|
11280
11665
|
written: calls.map((call) => ({ call, site: siteFor(call) }))
|
|
11281
11666
|
};
|
|
11282
11667
|
}
|
|
11283
|
-
function
|
|
11668
|
+
function callsWrittenIn2(node, run, options) {
|
|
11284
11669
|
if (run !== null) {
|
|
11285
11670
|
return exampleCalls(run, options.inheritedMethods).filter(
|
|
11286
11671
|
(call) => !run.isRunnerCall(call)
|
|
@@ -11347,6 +11732,12 @@ function scanBody(source, ctx, options, read) {
|
|
|
11347
11732
|
}
|
|
11348
11733
|
const argNodes = bodyStatements(args);
|
|
11349
11734
|
for (let position = 0; position < argNodes.length; position += 1) {
|
|
11735
|
+
if (argNodes[position]?.type === LAMBDA_TYPE) {
|
|
11736
|
+
if (calleeKey !== null) {
|
|
11737
|
+
passedPositions.add(`${calleeKey}#${position}`);
|
|
11738
|
+
}
|
|
11739
|
+
continue;
|
|
11740
|
+
}
|
|
11350
11741
|
const symbol = methodReferenceSymbol(argNodes[position]);
|
|
11351
11742
|
if (symbol === null) {
|
|
11352
11743
|
continue;
|
|
@@ -11384,11 +11775,35 @@ function scanBody(source, ctx, options, read) {
|
|
|
11384
11775
|
span: spanOf(target.node)
|
|
11385
11776
|
});
|
|
11386
11777
|
};
|
|
11778
|
+
const follow = (target) => {
|
|
11779
|
+
const key = keyOf(target);
|
|
11780
|
+
if (!seen.has(key)) {
|
|
11781
|
+
seen.add(key);
|
|
11782
|
+
followed2.push(target);
|
|
11783
|
+
}
|
|
11784
|
+
};
|
|
11387
11785
|
for (const call of calls) {
|
|
11388
11786
|
const callee = calleeText(call);
|
|
11389
11787
|
const callSite = read.siteFor(call);
|
|
11390
11788
|
const predicate = read.predicateOf(call);
|
|
11391
|
-
const
|
|
11789
|
+
const settled = predicate === null ? resolveCallee(call, callSite, ctx, read.spellings) : resolveMethodOn(predicate.target, predicate.method, callSite, ctx);
|
|
11790
|
+
const dispatched = settled.kind === "stopped" ? read.dispatched.get(call.id) : void 0;
|
|
11791
|
+
const [only] = dispatched?.targets ?? [];
|
|
11792
|
+
if (dispatched !== void 0 && only !== void 0 && !dispatched.certain) {
|
|
11793
|
+
dispatched.targets.forEach(follow);
|
|
11794
|
+
placements.placePossible(
|
|
11795
|
+
callee,
|
|
11796
|
+
dispatched.targets.map((target) => ({
|
|
11797
|
+
file: displayPathOf(target.file),
|
|
11798
|
+
span: spanOf(target.node)
|
|
11799
|
+
}))
|
|
11800
|
+
);
|
|
11801
|
+
if (dispatched.unresolved > 0) {
|
|
11802
|
+
stops.add({ callee, reason: "unsettledValue" });
|
|
11803
|
+
}
|
|
11804
|
+
continue;
|
|
11805
|
+
}
|
|
11806
|
+
const outcome = only === void 0 ? settled : { kind: "followed", target: only };
|
|
11392
11807
|
if (options.storage !== void 0) {
|
|
11393
11808
|
for (const callback of callbacksReached(
|
|
11394
11809
|
call,
|
|
@@ -11437,17 +11852,14 @@ function scanBody(source, ctx, options, read) {
|
|
|
11437
11852
|
if (isArglessReceiverCall(call)) {
|
|
11438
11853
|
keptArgless.add(call.id);
|
|
11439
11854
|
}
|
|
11440
|
-
|
|
11441
|
-
if (!seen.has(key)) {
|
|
11442
|
-
seen.add(key);
|
|
11443
|
-
followed2.push(outcome.target);
|
|
11444
|
-
}
|
|
11855
|
+
follow(outcome.target);
|
|
11445
11856
|
}
|
|
11446
11857
|
return {
|
|
11447
11858
|
followed: followed2,
|
|
11448
11859
|
stops: stops.stops,
|
|
11449
11860
|
targets: placements.targets,
|
|
11450
11861
|
argTargets: placements.argTargets,
|
|
11862
|
+
possibleTargets: placements.possibleTargets,
|
|
11451
11863
|
parameterCalls,
|
|
11452
11864
|
passedPositions,
|
|
11453
11865
|
propertyReads: propertyReadsAmong(read.argless, calls, keptArgless),
|
|
@@ -11479,9 +11891,9 @@ function propertyReadsAmong(argless, made, keptArgless) {
|
|
|
11479
11891
|
);
|
|
11480
11892
|
const reads = /* @__PURE__ */ new Set();
|
|
11481
11893
|
for (const call of argless) {
|
|
11482
|
-
const
|
|
11483
|
-
if (!kept.has(
|
|
11484
|
-
reads.add(
|
|
11894
|
+
const text3 = calleeText(call);
|
|
11895
|
+
if (!kept.has(text3)) {
|
|
11896
|
+
reads.add(text3);
|
|
11485
11897
|
}
|
|
11486
11898
|
}
|
|
11487
11899
|
return reads;
|
|
@@ -12421,7 +12833,7 @@ function replaysCleanly(units, discovered) {
|
|
|
12421
12833
|
async function extractRubyProject(options) {
|
|
12422
12834
|
const timer = options.onTiming !== void 0 ? createTimer() : noopTimer();
|
|
12423
12835
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
12424
|
-
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ?
|
|
12836
|
+
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? extractionCacheDirFor(options.projectRoot) : null)
|
|
12425
12837
|
);
|
|
12426
12838
|
const layer = createCacheLayer(cacheDir);
|
|
12427
12839
|
const packsDigest = `${adapterStamp.packsDigest(
|
|
@@ -12442,10 +12854,13 @@ async function extractRubyProject(options) {
|
|
|
12442
12854
|
"cache.lookup",
|
|
12443
12855
|
() => layer.lookup(input)
|
|
12444
12856
|
);
|
|
12857
|
+
const composed = (stored) => composeWrappers(stored, {
|
|
12858
|
+
gapHandling: options.gapHandling ?? "permissive"
|
|
12859
|
+
});
|
|
12445
12860
|
if (lookup.kind === "hit") {
|
|
12446
12861
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
12447
12862
|
options.onTiming?.(timer.report());
|
|
12448
|
-
return { summaries: lookup.summaries, facts: new Database2() };
|
|
12863
|
+
return { summaries: composed(lookup.summaries), facts: new Database2() };
|
|
12449
12864
|
}
|
|
12450
12865
|
const plan = lookup.diagnostic.missReason === "files-changed" ? await timer.timeAsync("cache.plan", () => layer.plan(input)) : null;
|
|
12451
12866
|
if (plan !== null && plan.changed.size === 0 && plan.removed.size === 0) {
|
|
@@ -12455,7 +12870,7 @@ async function extractRubyProject(options) {
|
|
|
12455
12870
|
}
|
|
12456
12871
|
options.onCacheDiagnostic?.({ kind: "hit" });
|
|
12457
12872
|
options.onTiming?.(timer.report());
|
|
12458
|
-
return { summaries: plan.allSummaries(), facts: new Database2() };
|
|
12873
|
+
return { summaries: composed(plan.allSummaries()), facts: new Database2() };
|
|
12459
12874
|
}
|
|
12460
12875
|
const cache = { timer, cacheDir, layer, input };
|
|
12461
12876
|
const records = plan === null ? null : recordsToReplay(plan.roots, plan.changed, plan.removed);
|
|
@@ -12816,6 +13231,7 @@ async function runRuby(options, cache, previous) {
|
|
|
12816
13231
|
}
|
|
12817
13232
|
placeCalls2(summary, reached.targetsByKey.get(key));
|
|
12818
13233
|
placeArgTargets2(summary, reached.argTargetsByKey.get(key));
|
|
13234
|
+
placePossibleCalls2(summary, reached.possibleTargetsByKey.get(key));
|
|
12819
13235
|
placeCalleeParameters2(summary, reached.parameterCallsByKey.get(key));
|
|
12820
13236
|
placeReceiverClasses(summary, reached.receiverClassesByKey.get(key));
|
|
12821
13237
|
}
|
|
@@ -12862,16 +13278,20 @@ async function runRuby(options, cache, previous) {
|
|
|
12862
13278
|
);
|
|
12863
13279
|
return composeWrappers(summaries, { gapHandling });
|
|
12864
13280
|
});
|
|
13281
|
+
const walkedFiles = new Map(
|
|
13282
|
+
parsed.map(({ file }) => [displayPathOf(file), file])
|
|
13283
|
+
);
|
|
12865
13284
|
await timer.timeAsync("cache.write", async () => {
|
|
12866
|
-
if (cacheDir === null ||
|
|
13285
|
+
if (cacheDir === null || summaries.length === 0) {
|
|
12867
13286
|
return;
|
|
12868
13287
|
}
|
|
12869
13288
|
try {
|
|
12870
13289
|
await cache.layer.write(
|
|
12871
13290
|
cache.input,
|
|
12872
|
-
|
|
13291
|
+
summaries,
|
|
12873
13292
|
log === null || ledger === null || overBudget ? void 0 : rubyAttribution({
|
|
12874
|
-
|
|
13293
|
+
summaries,
|
|
13294
|
+
walkedFileOf: (locationFile) => walkedFiles.get(locationFile),
|
|
12875
13295
|
discoveries,
|
|
12876
13296
|
reached,
|
|
12877
13297
|
reuse,
|
|
@@ -12946,7 +13366,10 @@ function rubyAttribution(args) {
|
|
|
12946
13366
|
facts: args.facts.get(file) ?? { own: "", joined: "" }
|
|
12947
13367
|
}
|
|
12948
13368
|
}));
|
|
12949
|
-
return {
|
|
13369
|
+
return {
|
|
13370
|
+
roots,
|
|
13371
|
+
owners: ownersWhereWritten(args.summaries, args.walkedFileOf)
|
|
13372
|
+
};
|
|
12950
13373
|
}
|
|
12951
13374
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["vendor", "node_modules", "tmp", ".git"]);
|
|
12952
13375
|
function findRubyFiles(root) {
|
|
@@ -13020,8 +13443,8 @@ function displayNameOf(node) {
|
|
|
13020
13443
|
if (node.type === "class" || node.type === "module") {
|
|
13021
13444
|
return field(node, "name")?.text ?? node.text;
|
|
13022
13445
|
}
|
|
13023
|
-
const
|
|
13024
|
-
return
|
|
13446
|
+
const text3 = node.text.split("\n")[0].trim();
|
|
13447
|
+
return text3.length > 40 ? `${text3.slice(0, 40)}...` : text3;
|
|
13025
13448
|
}
|
|
13026
13449
|
function width(node) {
|
|
13027
13450
|
return node.endIndex - node.startIndex;
|
|
@@ -13051,14 +13474,14 @@ var RubyWhySession = class {
|
|
|
13051
13474
|
* The smallest expression on `line` of `file` whose text is exactly
|
|
13052
13475
|
* `text`, or null.
|
|
13053
13476
|
*/
|
|
13054
|
-
findExpression(file, line,
|
|
13477
|
+
findExpression(file, line, text3) {
|
|
13055
13478
|
const root = this.rootOf(file);
|
|
13056
13479
|
if (root === null) {
|
|
13057
13480
|
return null;
|
|
13058
13481
|
}
|
|
13059
13482
|
let found = null;
|
|
13060
13483
|
const visit = (node) => {
|
|
13061
|
-
if (node.startPosition.row + 1 === line && node.text ===
|
|
13484
|
+
if (node.startPosition.row + 1 === line && node.text === text3) {
|
|
13062
13485
|
if (found === null || width(node) <= width(found)) {
|
|
13063
13486
|
found = node;
|
|
13064
13487
|
}
|