@suss/adapter-python 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 +551 -81
- package/dist/index.d.cts +43 -3
- package/dist/index.d.ts +43 -3
- package/dist/index.js +560 -81
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -1048,6 +1048,8 @@ var CONVERTING_BUILTINS = /* @__PURE__ */ new Set([
|
|
|
1048
1048
|
"str",
|
|
1049
1049
|
"float"
|
|
1050
1050
|
]);
|
|
1051
|
+
var ATTRIBUTE_GETTER = "getattr";
|
|
1052
|
+
var POSITION_COUNTER = "enumerate";
|
|
1051
1053
|
|
|
1052
1054
|
// src/facts/values.ts
|
|
1053
1055
|
function nodeId(filePath, node) {
|
|
@@ -1219,8 +1221,7 @@ function emitConversion(emitter, call, callKey) {
|
|
|
1219
1221
|
return;
|
|
1220
1222
|
}
|
|
1221
1223
|
const name = callee.text;
|
|
1222
|
-
|
|
1223
|
-
if (builtin) {
|
|
1224
|
+
if (isBuiltin(emitter, name)) {
|
|
1224
1225
|
add(emitter, "converts", callKey, valueKey(emitter, first.node), name);
|
|
1225
1226
|
}
|
|
1226
1227
|
}
|
|
@@ -1269,6 +1270,7 @@ function emitSequence(emitter, sequence) {
|
|
|
1269
1270
|
const objectKey = nodeId(emitter.filePath, sequence);
|
|
1270
1271
|
add(emitter, "objectValue", objectKey);
|
|
1271
1272
|
let position = 0;
|
|
1273
|
+
const entries = [];
|
|
1272
1274
|
for (const element of children(sequence)) {
|
|
1273
1275
|
add(
|
|
1274
1276
|
emitter,
|
|
@@ -1278,12 +1280,21 @@ function emitSequence(emitter, sequence) {
|
|
|
1278
1280
|
valueKey(emitter, element)
|
|
1279
1281
|
);
|
|
1280
1282
|
position += 1;
|
|
1283
|
+
if (element.type !== "comment") {
|
|
1284
|
+
entries.push(writtenEntry(emitter, element));
|
|
1285
|
+
}
|
|
1281
1286
|
}
|
|
1287
|
+
(0, import_resolution3.addEntryRows)(rowsOf(emitter), objectKey, entries);
|
|
1282
1288
|
}
|
|
1283
1289
|
function emitDictionary(emitter, dictionary) {
|
|
1284
1290
|
const objectKey = nodeId(emitter.filePath, dictionary);
|
|
1285
1291
|
add(emitter, "objectValue", objectKey);
|
|
1292
|
+
const entries = [];
|
|
1286
1293
|
for (const pair of children(dictionary)) {
|
|
1294
|
+
if (SPREAD_TYPES.has(pair.type)) {
|
|
1295
|
+
entries.push(writtenEntry(emitter, pair));
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1287
1298
|
if (pair.type !== "pair") {
|
|
1288
1299
|
continue;
|
|
1289
1300
|
}
|
|
@@ -1292,6 +1303,7 @@ function emitDictionary(emitter, dictionary) {
|
|
|
1292
1303
|
if (key === null || value === null) {
|
|
1293
1304
|
continue;
|
|
1294
1305
|
}
|
|
1306
|
+
entries.push(writtenEntry(emitter, value));
|
|
1295
1307
|
if (key.type !== "string") {
|
|
1296
1308
|
add(emitter, "holdsUnderKey", objectKey, valueKey(emitter, value));
|
|
1297
1309
|
continue;
|
|
@@ -1304,6 +1316,15 @@ function emitDictionary(emitter, dictionary) {
|
|
|
1304
1316
|
valueKey(emitter, value)
|
|
1305
1317
|
);
|
|
1306
1318
|
}
|
|
1319
|
+
(0, import_resolution3.addEntryRows)(rowsOf(emitter), objectKey, entries);
|
|
1320
|
+
}
|
|
1321
|
+
var SPREAD_TYPES = /* @__PURE__ */ new Set(["list_splat", "dictionary_splat"]);
|
|
1322
|
+
function writtenEntry(emitter, entry) {
|
|
1323
|
+
const unpacked = SPREAD_TYPES.has(entry.type) ? children(entry)[0] : void 0;
|
|
1324
|
+
return unpacked === void 0 ? { key: valueKey(emitter, entry), form: import_resolution3.VALUE_ENTRY } : { key: valueKey(emitter, unpacked), form: import_resolution3.SPREAD_ENTRY };
|
|
1325
|
+
}
|
|
1326
|
+
function rowsOf(emitter) {
|
|
1327
|
+
return (relation, row) => add(emitter, relation, ...row);
|
|
1307
1328
|
}
|
|
1308
1329
|
function emitAttribute(emitter, attribute) {
|
|
1309
1330
|
const object = field(attribute, "object");
|
|
@@ -1368,13 +1389,50 @@ function emitKeyedRead(emitter, site, container, key) {
|
|
|
1368
1389
|
if (WRITTEN_KEY_TYPES.has(key.type)) {
|
|
1369
1390
|
return;
|
|
1370
1391
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1392
|
+
const siteKey = nodeId(emitter.filePath, site);
|
|
1393
|
+
const containerKey = valueKey(emitter, container);
|
|
1394
|
+
add(emitter, "readsKeyed", siteKey, containerKey, valueKey(emitter, key));
|
|
1395
|
+
add(emitter, "choosesEntry", siteKey, containerKey);
|
|
1396
|
+
}
|
|
1397
|
+
function emitAttributeChoice(emitter, call) {
|
|
1398
|
+
const callee = field(call, "function");
|
|
1399
|
+
const [target, name] = callArguments(call);
|
|
1400
|
+
if (callee?.type !== "identifier" || callee.text !== ATTRIBUTE_GETTER || !isBuiltin(emitter, callee.text) || target?.kind !== "positional" || name?.kind !== "positional") {
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
const siteKey = nodeId(emitter.filePath, call);
|
|
1404
|
+
const targetKey = valueKey(emitter, target.node);
|
|
1405
|
+
const written = plainStringOf(name.node);
|
|
1406
|
+
if (written !== null) {
|
|
1407
|
+
add(emitter, "choosesNamedEntry", siteKey, targetKey, written);
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
const ends = writtenEnds(name.node);
|
|
1411
|
+
if (ends === null) {
|
|
1412
|
+
add(emitter, "choosesEntry", siteKey, targetKey);
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
add(emitter, "choosesEntryLike", siteKey, targetKey, ends.start, ends.end);
|
|
1416
|
+
}
|
|
1417
|
+
function writtenEnds(node) {
|
|
1418
|
+
if (node.type !== "string") {
|
|
1419
|
+
return null;
|
|
1420
|
+
}
|
|
1421
|
+
const parts = children(node).filter(
|
|
1422
|
+
(part) => part.type !== "string_start" && part.type !== "string_end"
|
|
1377
1423
|
);
|
|
1424
|
+
const written = (part) => part.type === "string_content";
|
|
1425
|
+
const firstComputed = parts.findIndex((part) => !written(part));
|
|
1426
|
+
if (firstComputed === -1) {
|
|
1427
|
+
return null;
|
|
1428
|
+
}
|
|
1429
|
+
const lastComputed = parts.length - 1 - [...parts].reverse().findIndex((part) => !written(part));
|
|
1430
|
+
const start = parts.slice(0, firstComputed).map((part) => part.text).join("");
|
|
1431
|
+
const end = parts.slice(lastComputed + 1).map((part) => part.text).join("");
|
|
1432
|
+
return start === "" && end === "" ? null : { start, end };
|
|
1433
|
+
}
|
|
1434
|
+
function isBuiltin(emitter, name) {
|
|
1435
|
+
return nameKey(emitter.filePath, emitter.enclosing, name) === nameId(emitter.filePath, name) && !emitter.moduleNames().has(name);
|
|
1378
1436
|
}
|
|
1379
1437
|
function emitWrittenKeyRead(emitter, site, container, key) {
|
|
1380
1438
|
const name = plainStringOf(key);
|
|
@@ -1510,6 +1568,86 @@ function emitComprehensionElement(emitter, comprehension) {
|
|
|
1510
1568
|
);
|
|
1511
1569
|
}
|
|
1512
1570
|
}
|
|
1571
|
+
var PAIR_TARGET_TYPES = /* @__PURE__ */ new Set(["pattern_list", "tuple_pattern"]);
|
|
1572
|
+
function emitElementVariables(emitter, clause) {
|
|
1573
|
+
const target = field(clause, "left");
|
|
1574
|
+
const over = field(clause, "right");
|
|
1575
|
+
if (target === null || over === null) {
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
const names = PAIR_TARGET_TYPES.has(target.type) ? children(target) : [];
|
|
1579
|
+
const [position, element] = names;
|
|
1580
|
+
const counted = countedCollection(emitter, over);
|
|
1581
|
+
if (counted !== null && names.length === 2 && position?.type === "identifier" && element !== void 0) {
|
|
1582
|
+
emitElementTaken(emitter, element, valueKey(emitter, counted), position);
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
emitElementTaken(emitter, target, valueKey(emitter, over), null);
|
|
1586
|
+
}
|
|
1587
|
+
function emitElementTaken(emitter, target, overKey, position) {
|
|
1588
|
+
const variables = target.type === "identifier" ? [{ node: target, part: null }] : partsTakenApart(target);
|
|
1589
|
+
for (const variable of variables) {
|
|
1590
|
+
const key = valueKey(emitter, variable.node);
|
|
1591
|
+
if (variable.part === null) {
|
|
1592
|
+
add(emitter, "elementOf", key, overKey);
|
|
1593
|
+
continue;
|
|
1594
|
+
}
|
|
1595
|
+
add(emitter, "elementPartOf", key, overKey, variable.part);
|
|
1596
|
+
}
|
|
1597
|
+
const [first] = variables;
|
|
1598
|
+
if (position !== null && first !== void 0) {
|
|
1599
|
+
add(
|
|
1600
|
+
emitter,
|
|
1601
|
+
"positionOf",
|
|
1602
|
+
valueKey(emitter, position),
|
|
1603
|
+
valueKey(emitter, first.node)
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
function partsTakenApart(target) {
|
|
1608
|
+
const parts = [];
|
|
1609
|
+
if (!PAIR_TARGET_TYPES.has(target.type)) {
|
|
1610
|
+
return parts;
|
|
1611
|
+
}
|
|
1612
|
+
for (const [position, part] of children(target).entries()) {
|
|
1613
|
+
if (part.type === "list_splat_pattern") {
|
|
1614
|
+
break;
|
|
1615
|
+
}
|
|
1616
|
+
if (part.type === "identifier") {
|
|
1617
|
+
parts.push({ node: part, part: String(position) });
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
return parts;
|
|
1621
|
+
}
|
|
1622
|
+
function countedCollection(emitter, over) {
|
|
1623
|
+
const callee = over.type === "call" ? field(over, "function") : null;
|
|
1624
|
+
const args = field(over, "arguments");
|
|
1625
|
+
const [first] = callArguments(over);
|
|
1626
|
+
if (callee?.type !== "identifier" || callee.text !== POSITION_COUNTER || !isBuiltin(emitter, POSITION_COUNTER) || args === null || writtenArgumentCount(args) !== 1 || first?.kind !== "positional") {
|
|
1627
|
+
return null;
|
|
1628
|
+
}
|
|
1629
|
+
return first.node;
|
|
1630
|
+
}
|
|
1631
|
+
function interpolatedPieces(emitter, string2) {
|
|
1632
|
+
const parts = children(string2);
|
|
1633
|
+
if (!parts.some((part) => part.type === "interpolation")) {
|
|
1634
|
+
return [];
|
|
1635
|
+
}
|
|
1636
|
+
return parts.flatMap((part) => {
|
|
1637
|
+
if (part.type === "string_content") {
|
|
1638
|
+
return [{ text: stringContentValue(part) }];
|
|
1639
|
+
}
|
|
1640
|
+
const expression = part.type === "interpolation" ? field(part, "expression") ?? children(part)[0] : void 0;
|
|
1641
|
+
return expression === void 0 ? [] : [{ hole: valueKey(emitter, expression) }];
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
function adjacentPieces(emitter, joined2) {
|
|
1645
|
+
return children(joined2).filter((part) => part.type !== "comment").map((part) => ({ hole: valueKey(emitter, part) }));
|
|
1646
|
+
}
|
|
1647
|
+
var TEMPLATE_PIECES = {
|
|
1648
|
+
string: interpolatedPieces,
|
|
1649
|
+
concatenated_string: adjacentPieces
|
|
1650
|
+
};
|
|
1513
1651
|
function emitExpressionFact(emitter, child, type) {
|
|
1514
1652
|
if (type === "call") {
|
|
1515
1653
|
emitCall(emitter, child);
|
|
@@ -1517,6 +1655,7 @@ function emitExpressionFact(emitter, child, type) {
|
|
|
1517
1655
|
if (mapping !== null) {
|
|
1518
1656
|
emitKeyedRead(emitter, child, mapping.container, mapping.key);
|
|
1519
1657
|
}
|
|
1658
|
+
emitAttributeChoice(emitter, child);
|
|
1520
1659
|
}
|
|
1521
1660
|
if (type === "subscript") {
|
|
1522
1661
|
const index = singleSubscript(child);
|
|
@@ -1546,6 +1685,13 @@ function emitExpressionFact(emitter, child, type) {
|
|
|
1546
1685
|
if (COMPREHENSION_TYPES.has(type)) {
|
|
1547
1686
|
emitComprehensionElement(emitter, child);
|
|
1548
1687
|
}
|
|
1688
|
+
if (type === "for_in_clause") {
|
|
1689
|
+
emitElementVariables(emitter, child);
|
|
1690
|
+
}
|
|
1691
|
+
const pieces = TEMPLATE_PIECES[type]?.(emitter, child) ?? [];
|
|
1692
|
+
if (pieces.length > 0) {
|
|
1693
|
+
(0, import_resolution3.addTemplateRows)(rowsOf(emitter), nodeId(emitter.filePath, child), pieces);
|
|
1694
|
+
}
|
|
1549
1695
|
const branches = fallbackBranchesOf(child, type);
|
|
1550
1696
|
if (branches !== null) {
|
|
1551
1697
|
for (const branch of branches) {
|
|
@@ -2064,6 +2210,9 @@ function readUnderName(emitter, statement, funcKey, accessed) {
|
|
|
2064
2210
|
function emitNestedDefinitions(emitter, node) {
|
|
2065
2211
|
for (const child of children(node)) {
|
|
2066
2212
|
const type = child.type;
|
|
2213
|
+
if (type === "decorated_definition") {
|
|
2214
|
+
emitDecoratorCalls(emitter, child);
|
|
2215
|
+
}
|
|
2067
2216
|
if (FUNCTION_TYPES.has(type)) {
|
|
2068
2217
|
emitFunctionFacts(emitter, child);
|
|
2069
2218
|
if (emitter.enclosing !== null) {
|
|
@@ -2083,6 +2232,20 @@ function emitNestedDefinitions(emitter, node) {
|
|
|
2083
2232
|
emitNestedDefinitions(emitter, child);
|
|
2084
2233
|
}
|
|
2085
2234
|
}
|
|
2235
|
+
function emitDecoratorCalls(emitter, decorated) {
|
|
2236
|
+
const { definition, decorators } = stripDecorators(decorated);
|
|
2237
|
+
let applied = nodeId(emitter.filePath, definition);
|
|
2238
|
+
for (const decorator of [...decorators].reverse()) {
|
|
2239
|
+
const [expression] = children(decorator);
|
|
2240
|
+
if (expression === void 0) {
|
|
2241
|
+
continue;
|
|
2242
|
+
}
|
|
2243
|
+
const callKey = nodeId(emitter.filePath, decorator);
|
|
2244
|
+
add(emitter, "call", callKey, valueKey(emitter, expression));
|
|
2245
|
+
add(emitter, "callArg", callKey, "0", applied);
|
|
2246
|
+
applied = callKey;
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2086
2249
|
var readingsByTree = /* @__PURE__ */ new WeakMap();
|
|
2087
2250
|
function scopeReadingOf(fn, given) {
|
|
2088
2251
|
const tree = fn.tree;
|
|
@@ -4783,13 +4946,37 @@ function modelColumn(node) {
|
|
|
4783
4946
|
}
|
|
4784
4947
|
return field(node, "attribute")?.text ?? null;
|
|
4785
4948
|
}
|
|
4786
|
-
function selectorOf(chain, valueMethods) {
|
|
4949
|
+
function selectorOf(chain, valueMethods, model) {
|
|
4950
|
+
const picking = laterCalls(chain).filter(
|
|
4951
|
+
(call) => !valueMethods.includes(methodNameOf(call))
|
|
4952
|
+
);
|
|
4787
4953
|
return [
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4954
|
+
.../* @__PURE__ */ new Set([
|
|
4955
|
+
...picking.flatMap((call) => pickedBy(call).map((one) => one.name)),
|
|
4956
|
+
...model === null ? [] : picking.flatMap((call) => columnsComparedBy(call, model))
|
|
4957
|
+
])
|
|
4791
4958
|
];
|
|
4792
4959
|
}
|
|
4960
|
+
var COMBINED_TESTS = ["and_", "or_", "not_"];
|
|
4961
|
+
function columnsComparedBy(call, model) {
|
|
4962
|
+
const args = field(call, "arguments");
|
|
4963
|
+
return (args === null ? [] : children(args)).flatMap(
|
|
4964
|
+
(argument) => columnsCompared(argument, model)
|
|
4965
|
+
);
|
|
4966
|
+
}
|
|
4967
|
+
function columnsCompared(node, model) {
|
|
4968
|
+
if (node.type === "call" && COMBINED_TESTS.includes(methodNameOf(node))) {
|
|
4969
|
+
return columnsComparedBy(node, model);
|
|
4970
|
+
}
|
|
4971
|
+
if (node.type !== "comparison_operator") {
|
|
4972
|
+
return [];
|
|
4973
|
+
}
|
|
4974
|
+
return children(node).flatMap((side) => {
|
|
4975
|
+
const object = side.type === "attribute" ? field(side, "object") : null;
|
|
4976
|
+
const column = object?.text === model ? field(side, "attribute") : null;
|
|
4977
|
+
return column === null ? [] : [column.text];
|
|
4978
|
+
});
|
|
4979
|
+
}
|
|
4793
4980
|
var TABLE_METHODS = ["select_from", "join"];
|
|
4794
4981
|
function modelOf(chain, options) {
|
|
4795
4982
|
const fromRoot = modelArgument(chain.root, chain.root, options);
|
|
@@ -4854,14 +5041,15 @@ function isClassName(name) {
|
|
|
4854
5041
|
}
|
|
4855
5042
|
function effectFor2(pattern, chain, operation, options) {
|
|
4856
5043
|
const valueMethods = pattern.valueMethods ?? [];
|
|
4857
|
-
const
|
|
5044
|
+
const model = modelOf(chain, options);
|
|
5045
|
+
const picked = selectorOf(chain, valueMethods, model);
|
|
4858
5046
|
const effect = {
|
|
4859
5047
|
type: "interaction",
|
|
4860
5048
|
binding: (0, import_ir_core2.storageBinding)({
|
|
4861
5049
|
recognition: "python-storage",
|
|
4862
5050
|
storageSystem: pattern.storageSystem,
|
|
4863
5051
|
scope: "default",
|
|
4864
|
-
container:
|
|
5052
|
+
container: model
|
|
4865
5053
|
}),
|
|
4866
5054
|
callee: chain.last.text,
|
|
4867
5055
|
interaction: {
|
|
@@ -6592,7 +6780,7 @@ function isStdlibModule(node, scope, module2) {
|
|
|
6592
6780
|
const binding = resolveName(scope, node.text);
|
|
6593
6781
|
return binding?.kind === "import" && binding.module === module2 && binding.relativeLevel === 0;
|
|
6594
6782
|
}
|
|
6595
|
-
function
|
|
6783
|
+
function isBuiltin2(node, scope, name) {
|
|
6596
6784
|
return node.type === "identifier" && node.text === name && resolveName(scope, name) === null;
|
|
6597
6785
|
}
|
|
6598
6786
|
function isStdlibMember(node, scope, module2, name) {
|
|
@@ -6640,7 +6828,7 @@ function streamWriteAt(call, scope) {
|
|
|
6640
6828
|
}
|
|
6641
6829
|
const written = callArguments(call);
|
|
6642
6830
|
const positional = written.filter((argument) => argument.kind === "positional").map((argument) => argument.node);
|
|
6643
|
-
if (callee.type === "identifier" &&
|
|
6831
|
+
if (callee.type === "identifier" && isBuiltin2(callee, scope, "print")) {
|
|
6644
6832
|
const file = written.find(
|
|
6645
6833
|
(argument) => argument.kind === "keyword" && argument.name === "file"
|
|
6646
6834
|
);
|
|
@@ -8129,12 +8317,12 @@ function exitSiteAt(statement, scope) {
|
|
|
8129
8317
|
return endsTheProcess(callee, scope) ? { statement, code, raised: false } : null;
|
|
8130
8318
|
}
|
|
8131
8319
|
if (statement.type === "raise_statement") {
|
|
8132
|
-
return
|
|
8320
|
+
return isBuiltin2(callee, scope, "SystemExit") ? { statement, code, raised: true } : null;
|
|
8133
8321
|
}
|
|
8134
8322
|
return null;
|
|
8135
8323
|
}
|
|
8136
8324
|
function endsTheProcess(callee, scope) {
|
|
8137
|
-
return isStdlibMember(callee, scope, "sys", "exit") ||
|
|
8325
|
+
return isStdlibMember(callee, scope, "sys", "exit") || isBuiltin2(callee, scope, "exit") || isBuiltin2(callee, scope, "quit");
|
|
8138
8326
|
}
|
|
8139
8327
|
function firstArgument(call) {
|
|
8140
8328
|
return callArguments(call).find(
|
|
@@ -8438,6 +8626,40 @@ function instancesHaveAttribute(facts, classKey, name) {
|
|
|
8438
8626
|
function namedOutcomes(keys, ctx) {
|
|
8439
8627
|
return (0, import_resolution11.calleeOutcomes)(ctx.facts, [...new Set(keys)]);
|
|
8440
8628
|
}
|
|
8629
|
+
function dispatchedCalls(calls, ctx) {
|
|
8630
|
+
const byKey = new Map(
|
|
8631
|
+
calls.map(({ call, site }) => [nodeId(site.file.file, call), call])
|
|
8632
|
+
);
|
|
8633
|
+
const found = /* @__PURE__ */ new Map();
|
|
8634
|
+
for (const [key, outcome] of (0, import_resolution11.dispatchOutcomes)(ctx.facts, [...byKey.keys()])) {
|
|
8635
|
+
const call = byKey.get(key);
|
|
8636
|
+
if (call === void 0) {
|
|
8637
|
+
continue;
|
|
8638
|
+
}
|
|
8639
|
+
const targets = /* @__PURE__ */ new Map();
|
|
8640
|
+
for (const fn of outcome.functions) {
|
|
8641
|
+
for (const target of reachedThrough(fn, outcome.through, ctx)) {
|
|
8642
|
+
targets.set(nodeId(target.file.file, target.node), target);
|
|
8643
|
+
}
|
|
8644
|
+
}
|
|
8645
|
+
found.set(call.id, {
|
|
8646
|
+
targets: [...targets.values()],
|
|
8647
|
+
certain: outcome.certain && outcome.functions.every((fn) => !isLambda(fn, ctx)),
|
|
8648
|
+
unresolved: outcome.unresolved
|
|
8649
|
+
});
|
|
8650
|
+
}
|
|
8651
|
+
return found;
|
|
8652
|
+
}
|
|
8653
|
+
function reachedThrough(key, through, ctx) {
|
|
8654
|
+
const keys = isLambda(key, ctx) ? through.get(key) ?? [] : [key];
|
|
8655
|
+
return keys.flatMap((one) => {
|
|
8656
|
+
const target = isLambda(one, ctx) ? null : functionAt(one, ctx);
|
|
8657
|
+
return target === null ? [] : [target];
|
|
8658
|
+
});
|
|
8659
|
+
}
|
|
8660
|
+
function isLambda(key, ctx) {
|
|
8661
|
+
return ctx.definitions.get(key)?.type === "lambda";
|
|
8662
|
+
}
|
|
8441
8663
|
function functionNamed(nameKey2, ctx, read) {
|
|
8442
8664
|
if (assignedElsewhere(ctx.facts, nameKey2)) {
|
|
8443
8665
|
return null;
|
|
@@ -8656,6 +8878,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8656
8878
|
const targetsByKey = /* @__PURE__ */ new Map();
|
|
8657
8879
|
const stopsByKey = /* @__PURE__ */ new Map();
|
|
8658
8880
|
const argTargetsByKey = /* @__PURE__ */ new Map();
|
|
8881
|
+
const possibleTargetsByKey = /* @__PURE__ */ new Map();
|
|
8659
8882
|
const parameterCallsByKey = /* @__PURE__ */ new Map();
|
|
8660
8883
|
const callsByKey = /* @__PURE__ */ new Map();
|
|
8661
8884
|
const passedPositions = /* @__PURE__ */ new Set();
|
|
@@ -8718,6 +8941,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8718
8941
|
}
|
|
8719
8942
|
targetsByKey.set(key, scan.targets);
|
|
8720
8943
|
argTargetsByKey.set(key, scan.argTargets);
|
|
8944
|
+
possibleTargetsByKey.set(key, scan.possibleTargets);
|
|
8721
8945
|
if (scan.parameterCalls.length > 0) {
|
|
8722
8946
|
parameterCallsByKey.set(key, scan.parameterCalls);
|
|
8723
8947
|
}
|
|
@@ -8768,6 +8992,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8768
8992
|
}
|
|
8769
8993
|
(0, import_behavioral_ir7.placeCalls)(summary2, targetsByKey.get(key));
|
|
8770
8994
|
(0, import_behavioral_ir7.placeArgTargets)(summary2, argTargetsByKey.get(key));
|
|
8995
|
+
(0, import_behavioral_ir7.placePossibleCalls)(summary2, possibleTargetsByKey.get(key));
|
|
8771
8996
|
(0, import_behavioral_ir7.placeCalleeParameters)(summary2, parameterCallsByKey.get(key));
|
|
8772
8997
|
return summary2;
|
|
8773
8998
|
};
|
|
@@ -8791,6 +9016,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8791
9016
|
targetsByKey,
|
|
8792
9017
|
stopsByKey,
|
|
8793
9018
|
argTargetsByKey,
|
|
9019
|
+
possibleTargetsByKey,
|
|
8794
9020
|
parameterCallsByKey,
|
|
8795
9021
|
callsByKey,
|
|
8796
9022
|
passedPositions,
|
|
@@ -8814,24 +9040,42 @@ function chargeOf(charges, key) {
|
|
|
8814
9040
|
}
|
|
8815
9041
|
return charge;
|
|
8816
9042
|
}
|
|
9043
|
+
function dispatchedAmong(written, spellings, ctx) {
|
|
9044
|
+
return dispatchedCalls(
|
|
9045
|
+
written.filter(({ call, site }) => {
|
|
9046
|
+
if (!ENTRY_CALLEE_TYPES.has(field(call, "function")?.type ?? "")) {
|
|
9047
|
+
return false;
|
|
9048
|
+
}
|
|
9049
|
+
const outcome = resolveCallee2(call, site, ctx, spellings);
|
|
9050
|
+
return outcome.kind === "stopped" && outcome.reason !== "callerSupplied";
|
|
9051
|
+
}),
|
|
9052
|
+
ctx
|
|
9053
|
+
);
|
|
9054
|
+
}
|
|
9055
|
+
var ENTRY_CALLEE_TYPES = /* @__PURE__ */ new Set(["subscript", "call", "identifier"]);
|
|
8817
9056
|
function batchedReads(round, ctx) {
|
|
8818
9057
|
const bodies = round.flatMap(
|
|
8819
9058
|
(entry) => "source" in entry ? [{ key: entry.key, source: entry.source, ...bodyOf(entry.source) }] : []
|
|
8820
9059
|
);
|
|
8821
|
-
const
|
|
8822
|
-
|
|
8823
|
-
ctx
|
|
8824
|
-
);
|
|
9060
|
+
const written = bodies.flatMap((body) => body.written);
|
|
9061
|
+
const spellings = calleeSpellings(written, ctx);
|
|
8825
9062
|
const passed = namedOutcomes(
|
|
8826
9063
|
bodies.flatMap(
|
|
8827
|
-
({ source, written }) =>
|
|
9064
|
+
({ source, written: written2 }) => written2.flatMap(({ call }) => passedNameKeys(source.file, call))
|
|
8828
9065
|
),
|
|
8829
9066
|
ctx
|
|
8830
9067
|
);
|
|
9068
|
+
const dispatched = dispatchedAmong(written, spellings, ctx);
|
|
8831
9069
|
return new Map(
|
|
8832
9070
|
bodies.map((body) => [
|
|
8833
9071
|
body.key,
|
|
8834
|
-
{
|
|
9072
|
+
{
|
|
9073
|
+
body: body.body,
|
|
9074
|
+
written: body.written,
|
|
9075
|
+
spellings,
|
|
9076
|
+
passed,
|
|
9077
|
+
dispatched
|
|
9078
|
+
}
|
|
8835
9079
|
])
|
|
8836
9080
|
);
|
|
8837
9081
|
}
|
|
@@ -8862,13 +9106,15 @@ function scanOnce(source, key, ctx, options, read, charges) {
|
|
|
8862
9106
|
}
|
|
8863
9107
|
function ownReads(source, ctx) {
|
|
8864
9108
|
const body = bodyOf(source);
|
|
9109
|
+
const spellings = calleeSpellings(body.written, ctx);
|
|
8865
9110
|
return {
|
|
8866
9111
|
...body,
|
|
8867
|
-
spellings
|
|
9112
|
+
spellings,
|
|
8868
9113
|
passed: namedOutcomes(
|
|
8869
9114
|
body.written.flatMap(({ call }) => passedNameKeys(source.file, call)),
|
|
8870
9115
|
ctx
|
|
8871
|
-
)
|
|
9116
|
+
),
|
|
9117
|
+
dispatched: dispatchedAmong(body.written, spellings, ctx)
|
|
8872
9118
|
};
|
|
8873
9119
|
}
|
|
8874
9120
|
function storedScan(scan) {
|
|
@@ -8884,6 +9130,10 @@ function storedScan(scan) {
|
|
|
8884
9130
|
callee,
|
|
8885
9131
|
[...byPosition]
|
|
8886
9132
|
]),
|
|
9133
|
+
possibleTargets: [...scan.possibleTargets].map(([callee, places]) => [
|
|
9134
|
+
callee,
|
|
9135
|
+
[...places]
|
|
9136
|
+
]),
|
|
8887
9137
|
parameterCalls: [...scan.parameterCalls],
|
|
8888
9138
|
passedPositions: [...scan.passedPositions]
|
|
8889
9139
|
};
|
|
@@ -8899,6 +9149,7 @@ function scanFromStored(stored, functionFor) {
|
|
|
8899
9149
|
new Map(byPosition)
|
|
8900
9150
|
])
|
|
8901
9151
|
),
|
|
9152
|
+
possibleTargets: new Map(stored.possibleTargets),
|
|
8902
9153
|
parameterCalls: stored.parameterCalls,
|
|
8903
9154
|
passedPositions: new Set(stored.passedPositions)
|
|
8904
9155
|
};
|
|
@@ -8927,6 +9178,7 @@ var EMPTY_SCAN = {
|
|
|
8927
9178
|
stops: [],
|
|
8928
9179
|
targets: /* @__PURE__ */ new Map(),
|
|
8929
9180
|
argTargets: /* @__PURE__ */ new Map(),
|
|
9181
|
+
possibleTargets: /* @__PURE__ */ new Map(),
|
|
8930
9182
|
parameterCalls: [],
|
|
8931
9183
|
passedPositions: /* @__PURE__ */ new Set()
|
|
8932
9184
|
};
|
|
@@ -9003,12 +9255,25 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
9003
9255
|
return EMPTY_SCAN;
|
|
9004
9256
|
}
|
|
9005
9257
|
const ownParameters = callParameterNames(node, source.exportPath.length > 1);
|
|
9258
|
+
const follow = (target) => {
|
|
9259
|
+
const key = keyOf2(target);
|
|
9260
|
+
if (!seen.has(key)) {
|
|
9261
|
+
seen.add(key);
|
|
9262
|
+
followed.push(target);
|
|
9263
|
+
}
|
|
9264
|
+
};
|
|
9006
9265
|
const recordPassedArgs = (call, callee, calleeKey2) => {
|
|
9007
9266
|
const args = field(call, "arguments");
|
|
9008
9267
|
if (args === null) {
|
|
9009
9268
|
return;
|
|
9010
9269
|
}
|
|
9011
9270
|
children(args).forEach((arg, position) => {
|
|
9271
|
+
if (arg.type === "lambda") {
|
|
9272
|
+
if (calleeKey2 !== null) {
|
|
9273
|
+
passedPositions.add(`${calleeKey2}#${position}`);
|
|
9274
|
+
}
|
|
9275
|
+
return;
|
|
9276
|
+
}
|
|
9012
9277
|
const nameKey2 = passedNameKeyOf(file, arg);
|
|
9013
9278
|
if (nameKey2 === null) {
|
|
9014
9279
|
return;
|
|
@@ -9017,11 +9282,7 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
9017
9282
|
if (resolved === null) {
|
|
9018
9283
|
return;
|
|
9019
9284
|
}
|
|
9020
|
-
|
|
9021
|
-
if (!seen.has(key)) {
|
|
9022
|
-
seen.add(key);
|
|
9023
|
-
followed.push(resolved);
|
|
9024
|
-
}
|
|
9285
|
+
follow(resolved);
|
|
9025
9286
|
placements.placeArg(callee, position, {
|
|
9026
9287
|
file: resolved.file.displayPath,
|
|
9027
9288
|
span: spanOf(resolved.node)
|
|
@@ -9031,9 +9292,30 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
9031
9292
|
}
|
|
9032
9293
|
});
|
|
9033
9294
|
};
|
|
9295
|
+
const recordPossible = (call, callee, dispatched) => {
|
|
9296
|
+
dispatched.targets.forEach(follow);
|
|
9297
|
+
placements.placePossible(
|
|
9298
|
+
callee,
|
|
9299
|
+
dispatched.targets.map((target) => ({
|
|
9300
|
+
file: target.file.displayPath,
|
|
9301
|
+
span: spanOf(target.node)
|
|
9302
|
+
}))
|
|
9303
|
+
);
|
|
9304
|
+
recordPassedArgs(call, callee, null);
|
|
9305
|
+
if (dispatched.unresolved > 0 && !recognized.has(call.id)) {
|
|
9306
|
+
stops.add({ callee, reason: "unsettledValue" });
|
|
9307
|
+
}
|
|
9308
|
+
};
|
|
9034
9309
|
const record = (call, site) => {
|
|
9035
9310
|
const callee = calleeText(call);
|
|
9036
|
-
const
|
|
9311
|
+
const settled = resolveCallee2(call, site, ctx, spellings);
|
|
9312
|
+
const dispatched = settled.kind === "stopped" ? read.dispatched.get(call.id) : void 0;
|
|
9313
|
+
const [only] = dispatched?.targets ?? [];
|
|
9314
|
+
if (dispatched !== void 0 && only !== void 0 && !dispatched.certain) {
|
|
9315
|
+
recordPossible(call, callee, dispatched);
|
|
9316
|
+
return;
|
|
9317
|
+
}
|
|
9318
|
+
const outcome = only === void 0 ? settled : { kind: "followed", target: only };
|
|
9037
9319
|
placeCallee(placements, callee, outcome, call, file);
|
|
9038
9320
|
recordPassedArgs(
|
|
9039
9321
|
call,
|
|
@@ -9057,11 +9339,7 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
9057
9339
|
}
|
|
9058
9340
|
return;
|
|
9059
9341
|
}
|
|
9060
|
-
|
|
9061
|
-
if (!seen.has(key)) {
|
|
9062
|
-
seen.add(key);
|
|
9063
|
-
followed.push(outcome.target);
|
|
9064
|
-
}
|
|
9342
|
+
follow(outcome.target);
|
|
9065
9343
|
};
|
|
9066
9344
|
for (const { call, site } of written) {
|
|
9067
9345
|
record(call, site);
|
|
@@ -9071,17 +9349,14 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
9071
9349
|
file: target.file.displayPath,
|
|
9072
9350
|
span: spanOf(target.node)
|
|
9073
9351
|
});
|
|
9074
|
-
|
|
9075
|
-
if (!seen.has(key)) {
|
|
9076
|
-
seen.add(key);
|
|
9077
|
-
followed.push(target);
|
|
9078
|
-
}
|
|
9352
|
+
follow(target);
|
|
9079
9353
|
}
|
|
9080
9354
|
return {
|
|
9081
9355
|
followed,
|
|
9082
9356
|
stops: stops.stops,
|
|
9083
9357
|
targets: placements.targets,
|
|
9084
9358
|
argTargets: placements.argTargets,
|
|
9359
|
+
possibleTargets: placements.possibleTargets,
|
|
9085
9360
|
parameterCalls,
|
|
9086
9361
|
passedPositions
|
|
9087
9362
|
};
|
|
@@ -9405,6 +9680,10 @@ var PackPositions = class {
|
|
|
9405
9680
|
const [packAt, patternAt] = id.split("/").map(Number);
|
|
9406
9681
|
return this.packs[packAt ?? -1]?.discovery[patternAt ?? -1];
|
|
9407
9682
|
}
|
|
9683
|
+
packOf(id) {
|
|
9684
|
+
const [packAt] = id.split("/").map(Number);
|
|
9685
|
+
return this.packs[packAt ?? -1];
|
|
9686
|
+
}
|
|
9408
9687
|
formAt(at) {
|
|
9409
9688
|
const pack = this.packs[at[0]];
|
|
9410
9689
|
const pattern = pack?.discovery[at[1]];
|
|
@@ -11499,7 +11778,10 @@ var PythonWrapperIndex = class {
|
|
|
11499
11778
|
/** By wrapper reference: the parameters a dependency function declares, and its file. */
|
|
11500
11779
|
dependencyParameterTable = /* @__PURE__ */ new Map();
|
|
11501
11780
|
unitsByFile = /* @__PURE__ */ new Map();
|
|
11502
|
-
/**
|
|
11781
|
+
/**
|
|
11782
|
+
* Told about every registration, a pack's form or a project decorator's
|
|
11783
|
+
* closure, so a cache can repeat the ones a file's discovery made.
|
|
11784
|
+
*/
|
|
11503
11785
|
onRegistered = null;
|
|
11504
11786
|
/**
|
|
11505
11787
|
* The same lookup `wrappersFor` noted under `id`, made again over this
|
|
@@ -11580,6 +11862,25 @@ var PythonWrapperIndex = class {
|
|
|
11580
11862
|
}
|
|
11581
11863
|
return { reference, form: declared.form };
|
|
11582
11864
|
}
|
|
11865
|
+
/**
|
|
11866
|
+
* The unit for the closure a project's decorator hands back, built once
|
|
11867
|
+
* however many routes the decorator is written on. Its name is what
|
|
11868
|
+
* calling the decorator writes, since the decorator may have a summary
|
|
11869
|
+
* of its own under its name.
|
|
11870
|
+
*/
|
|
11871
|
+
registeredClosure(target, closure) {
|
|
11872
|
+
this.onRegistered?.(target, closure);
|
|
11873
|
+
const span = spanOf(target.node);
|
|
11874
|
+
const key = `${target.file.file}:${span.start}-${span.end}`;
|
|
11875
|
+
if (!this.unitsByKey.has(key)) {
|
|
11876
|
+
const unit = closureUnit(target, closure, this.options);
|
|
11877
|
+
this.unitsByKey.set(key, unit);
|
|
11878
|
+
const inFile = this.unitsByFile.get(target.file.file) ?? [];
|
|
11879
|
+
inFile.push(unit);
|
|
11880
|
+
this.unitsByFile.set(target.file.file, inFile);
|
|
11881
|
+
}
|
|
11882
|
+
return { file: target.file.displayPath, name: target.name };
|
|
11883
|
+
}
|
|
11583
11884
|
/**
|
|
11584
11885
|
* The parameters the dependencies among these wrappers declare, and
|
|
11585
11886
|
* whether one is declared through a parameter source such as `Query()`.
|
|
@@ -11611,9 +11912,13 @@ var PythonWrapperIndex = class {
|
|
|
11611
11912
|
pattern: query.pattern,
|
|
11612
11913
|
form
|
|
11613
11914
|
}));
|
|
11614
|
-
if (file === void 0
|
|
11915
|
+
if (file === void 0) {
|
|
11615
11916
|
return [];
|
|
11616
11917
|
}
|
|
11918
|
+
const decorators = this.decoratorLayers(query, file);
|
|
11919
|
+
if (forms.length === 0) {
|
|
11920
|
+
return decorators;
|
|
11921
|
+
}
|
|
11617
11922
|
const own = this.ownRoutesOf(query);
|
|
11618
11923
|
const found = [
|
|
11619
11924
|
...this.noted(
|
|
@@ -11651,7 +11956,68 @@ var PythonWrapperIndex = class {
|
|
|
11651
11956
|
seen.add(key);
|
|
11652
11957
|
ordered.push(wrapper.reference);
|
|
11653
11958
|
}
|
|
11654
|
-
return
|
|
11959
|
+
return [
|
|
11960
|
+
...ordered.filter((one) => one.onThrow !== true),
|
|
11961
|
+
...decorators,
|
|
11962
|
+
...ordered.filter((one) => one.onThrow === true)
|
|
11963
|
+
];
|
|
11964
|
+
}
|
|
11965
|
+
/**
|
|
11966
|
+
* The decorators written on the route's function below the one that
|
|
11967
|
+
* registers it, outermost first. Each wraps the function the library
|
|
11968
|
+
* calls. None has a summary: a library's has no body in the run, and a
|
|
11969
|
+
* project's own is not composed into the route yet, so a project
|
|
11970
|
+
* decorator goes by what calling it writes, `require_admin(fn)`, which
|
|
11971
|
+
* no summary is named. The decorators the packs read, such as the
|
|
11972
|
+
* route's own and the namespace's `@ns.doc`, are left out.
|
|
11973
|
+
*/
|
|
11974
|
+
decoratorLayers(query, file) {
|
|
11975
|
+
const decorated = query.definitionNode.parent;
|
|
11976
|
+
if (decorated === null || decorated.type !== "decorated_definition") {
|
|
11977
|
+
return [];
|
|
11978
|
+
}
|
|
11979
|
+
const written = stripDecorators(decorated).decorators;
|
|
11980
|
+
const routeAt = written.findIndex(
|
|
11981
|
+
(decorator) => sameRange(rangeOf(decorator), query.classification.range)
|
|
11982
|
+
);
|
|
11983
|
+
return written.slice(routeAt + 1).flatMap((decorator) => this.decoratorLayer(decorator, query, file));
|
|
11984
|
+
}
|
|
11985
|
+
decoratorLayer(decorator, query, file) {
|
|
11986
|
+
const facts = this.options.facts;
|
|
11987
|
+
const direct = classifyDecorator(decorator, query.module, facts);
|
|
11988
|
+
const written = decoratorCallee(decorator);
|
|
11989
|
+
if (written === null || direct.module !== null && readByAPack(direct.module, this.options) || direct.objectName !== null && direct.objectName === query.classification.objectName || unwrapDecorator(decorator, facts) !== null) {
|
|
11990
|
+
return [];
|
|
11991
|
+
}
|
|
11992
|
+
const project = written.type === "identifier" ? this.functionCalled(file.file, written.text) : null;
|
|
11993
|
+
if (project !== null) {
|
|
11994
|
+
if (facts !== void 0) {
|
|
11995
|
+
(0, import_resolution17.noteKeyRead)(facts, project.file.file);
|
|
11996
|
+
}
|
|
11997
|
+
return [this.projectDecoratorLayer(project, query)];
|
|
11998
|
+
}
|
|
11999
|
+
return [{ file: direct.module ?? file.displayPath, name: written.text }];
|
|
12000
|
+
}
|
|
12001
|
+
/**
|
|
12002
|
+
* The layer a project's own decorator puts around the route. When it
|
|
12003
|
+
* hands back a closure written inside it that returns what calling the
|
|
12004
|
+
* function it was given returns, the closure is summarized and
|
|
12005
|
+
* composed into the route. Any other decorator, including one whose
|
|
12006
|
+
* closure keeps going after that call, goes by the same name with no
|
|
12007
|
+
* summary behind it.
|
|
12008
|
+
*/
|
|
12009
|
+
projectDecoratorLayer(decorator, query) {
|
|
12010
|
+
const continuation = parameterNamesOf(decorator.node)[0] ?? "";
|
|
12011
|
+
const name = `${decorator.name}(${continuation})`;
|
|
12012
|
+
const closure = closureReturnedBy(decorator.node);
|
|
12013
|
+
const handsOn = closure === null || continuation === "" ? [] : callsThrough(closure, continuation);
|
|
12014
|
+
if (closure === null || handsOn.length === 0 || !handsOn.every((statement) => returnsCallTo(statement, continuation))) {
|
|
12015
|
+
return { file: decorator.file.displayPath, name };
|
|
12016
|
+
}
|
|
12017
|
+
return this.registeredClosure(
|
|
12018
|
+
{ file: decorator.file, node: closure, name, exportPath: [] },
|
|
12019
|
+
{ pack: query.pack, pattern: query.pattern, continuation }
|
|
12020
|
+
);
|
|
11655
12021
|
}
|
|
11656
12022
|
/**
|
|
11657
12023
|
* What the mounts above the route's router register on the way down:
|
|
@@ -11812,6 +12178,21 @@ var PythonWrapperIndex = class {
|
|
|
11812
12178
|
function referenceKey(reference) {
|
|
11813
12179
|
return `${reference.file}::${reference.name}`;
|
|
11814
12180
|
}
|
|
12181
|
+
function readByAPack(module2, options) {
|
|
12182
|
+
return options.packs.some(
|
|
12183
|
+
(pack) => pack.discovery.some((pattern) => pattern.importModule.includes(module2))
|
|
12184
|
+
);
|
|
12185
|
+
}
|
|
12186
|
+
function decoratorCallee(decorator) {
|
|
12187
|
+
const written = decorator.namedChild(0);
|
|
12188
|
+
if (written === null) {
|
|
12189
|
+
return null;
|
|
12190
|
+
}
|
|
12191
|
+
return written.type === "call" ? field(written, "function") : written;
|
|
12192
|
+
}
|
|
12193
|
+
function sameRange(a, b) {
|
|
12194
|
+
return a.start === b.start && a.end === b.end;
|
|
12195
|
+
}
|
|
11815
12196
|
function parameterNamesOf(definition) {
|
|
11816
12197
|
return children(field(definition, "parameters")).flatMap((parameter) => {
|
|
11817
12198
|
const named = parameterNameAndType(parameter);
|
|
@@ -11999,16 +12380,42 @@ function parameterDependencies(definitionNode, form) {
|
|
|
11999
12380
|
return names;
|
|
12000
12381
|
}
|
|
12001
12382
|
function wrapperUnit(target, declared, options) {
|
|
12383
|
+
return unitAround(
|
|
12384
|
+
target,
|
|
12385
|
+
declared.pattern,
|
|
12386
|
+
{
|
|
12387
|
+
continuations: continuationStatements(target.node, declared.form),
|
|
12388
|
+
continuationName: null,
|
|
12389
|
+
form: declared.form,
|
|
12390
|
+
nameKind: "binding"
|
|
12391
|
+
},
|
|
12392
|
+
options
|
|
12393
|
+
);
|
|
12394
|
+
}
|
|
12395
|
+
function closureUnit(target, closure, options) {
|
|
12396
|
+
return unitAround(
|
|
12397
|
+
target,
|
|
12398
|
+
closure.pattern,
|
|
12399
|
+
{
|
|
12400
|
+
continuations: callsThrough(target.node, closure.continuation),
|
|
12401
|
+
continuationName: closure.continuation,
|
|
12402
|
+
form: null,
|
|
12403
|
+
nameKind: "label"
|
|
12404
|
+
},
|
|
12405
|
+
options
|
|
12406
|
+
);
|
|
12407
|
+
}
|
|
12408
|
+
function unitAround(target, pattern, reading, options) {
|
|
12002
12409
|
const { file, node, name, exportPath } = target;
|
|
12003
12410
|
const body = field(node, "body");
|
|
12004
12411
|
const range = rangeOf(node);
|
|
12005
12412
|
const raised = raisedResponses(body, {
|
|
12006
|
-
calls:
|
|
12413
|
+
calls: pattern.responseStatusCalls ?? [],
|
|
12007
12414
|
module: file.module,
|
|
12008
12415
|
facts: options.facts,
|
|
12009
|
-
constants:
|
|
12416
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
12010
12417
|
});
|
|
12011
|
-
const continuations =
|
|
12418
|
+
const continuations = reading.continuations;
|
|
12012
12419
|
const terminals = bodyTerminals(body, raised, continuations);
|
|
12013
12420
|
const effects = invocationEffects(node, options.facts);
|
|
12014
12421
|
const extra = recognizedBodyEffects(
|
|
@@ -12017,7 +12424,7 @@ function wrapperUnit(target, declared, options) {
|
|
|
12017
12424
|
options.storageFor(file),
|
|
12018
12425
|
options.facts
|
|
12019
12426
|
);
|
|
12020
|
-
const delegate = (at) => ({
|
|
12427
|
+
const delegate = (at, to = null) => ({
|
|
12021
12428
|
terminal: {
|
|
12022
12429
|
kind: "delegate",
|
|
12023
12430
|
statusCode: null,
|
|
@@ -12026,18 +12433,18 @@ function wrapperUnit(target, declared, options) {
|
|
|
12026
12433
|
message: null,
|
|
12027
12434
|
component: null,
|
|
12028
12435
|
renderTree: null,
|
|
12029
|
-
delegateTarget:
|
|
12436
|
+
delegateTarget: to,
|
|
12030
12437
|
emitEvent: null,
|
|
12031
12438
|
location: rangeOf(at)
|
|
12032
12439
|
},
|
|
12033
12440
|
location: rangeOf(at)
|
|
12034
12441
|
});
|
|
12035
12442
|
const respond = (statement) => returnBranch(statement, {
|
|
12036
|
-
pattern
|
|
12443
|
+
pattern,
|
|
12037
12444
|
responseShape: { reading: import_extractor17.absentReading },
|
|
12038
12445
|
declaredStatus: {
|
|
12039
12446
|
reading: import_extractor17.absentReading,
|
|
12040
|
-
...
|
|
12447
|
+
...pattern.defaultStatusCode !== void 0 ? { libraryDefault: pattern.defaultStatusCode } : {}
|
|
12041
12448
|
},
|
|
12042
12449
|
module: file.module,
|
|
12043
12450
|
facts: options.facts
|
|
@@ -12049,7 +12456,10 @@ function wrapperUnit(target, declared, options) {
|
|
|
12049
12456
|
location: rangeOf(terminal.statement)
|
|
12050
12457
|
};
|
|
12051
12458
|
}
|
|
12052
|
-
if (terminal.type === "continuation"
|
|
12459
|
+
if (terminal.type === "continuation") {
|
|
12460
|
+
return delegate(terminal.statement, reading.continuationName);
|
|
12461
|
+
}
|
|
12462
|
+
if (reading.form !== null && returnHandsOn(terminal.statement, reading.form)) {
|
|
12053
12463
|
return delegate(terminal.statement);
|
|
12054
12464
|
}
|
|
12055
12465
|
return respond(terminal.statement);
|
|
@@ -12066,7 +12476,7 @@ function wrapperUnit(target, declared, options) {
|
|
|
12066
12476
|
return {
|
|
12067
12477
|
identity: {
|
|
12068
12478
|
name,
|
|
12069
|
-
nameKind:
|
|
12479
|
+
nameKind: reading.nameKind,
|
|
12070
12480
|
kind: "middleware",
|
|
12071
12481
|
file: file.displayPath,
|
|
12072
12482
|
range,
|
|
@@ -12102,23 +12512,45 @@ function continuationStatements(node, form) {
|
|
|
12102
12512
|
const params = children(field(node, "parameters"));
|
|
12103
12513
|
const param = params[form.continuationParam];
|
|
12104
12514
|
const continuation = param === void 0 ? null : field(param, "name")?.text ?? (param.type === "identifier" ? param.text : null);
|
|
12105
|
-
|
|
12106
|
-
|
|
12107
|
-
|
|
12515
|
+
return continuation === null ? [] : callsThrough(node, continuation);
|
|
12516
|
+
}
|
|
12517
|
+
function callsThrough(node, callee) {
|
|
12108
12518
|
const body = field(node, "body");
|
|
12109
12519
|
if (body === null) {
|
|
12110
12520
|
return [];
|
|
12111
12521
|
}
|
|
12112
12522
|
const found = [];
|
|
12113
12523
|
for (const call of bodyCalls(body)) {
|
|
12114
|
-
const
|
|
12115
|
-
const statement =
|
|
12524
|
+
const called = field(call, "function");
|
|
12525
|
+
const statement = called?.type === "identifier" && called.text === callee ? enclosingStatement(call, body) : null;
|
|
12116
12526
|
if (statement !== null) {
|
|
12117
12527
|
found.push(statement);
|
|
12118
12528
|
}
|
|
12119
12529
|
}
|
|
12120
12530
|
return found;
|
|
12121
12531
|
}
|
|
12532
|
+
function returnsCallTo(statement, callee) {
|
|
12533
|
+
if (statement.type !== "return_statement") {
|
|
12534
|
+
return false;
|
|
12535
|
+
}
|
|
12536
|
+
const value = statement.namedChild(0);
|
|
12537
|
+
const call = value?.type === "await" ? value.namedChild(0) : value;
|
|
12538
|
+
return call?.type === "call" && field(call, "function")?.text === callee;
|
|
12539
|
+
}
|
|
12540
|
+
function closureReturnedBy(decorator) {
|
|
12541
|
+
const statements = children(field(decorator, "body"));
|
|
12542
|
+
const returned = statements.find((statement) => statement.type === "return_statement")?.namedChild(0);
|
|
12543
|
+
if (returned?.type !== "identifier") {
|
|
12544
|
+
return null;
|
|
12545
|
+
}
|
|
12546
|
+
for (const statement of statements) {
|
|
12547
|
+
const { definition } = stripDecorators(statement);
|
|
12548
|
+
if (definition.type === "function_definition" && field(definition, "name")?.text === returned.text) {
|
|
12549
|
+
return definition;
|
|
12550
|
+
}
|
|
12551
|
+
}
|
|
12552
|
+
return null;
|
|
12553
|
+
}
|
|
12122
12554
|
|
|
12123
12555
|
// src/project.ts
|
|
12124
12556
|
function keptPythonParses() {
|
|
@@ -12213,7 +12645,7 @@ async function extractPythonProject(options) {
|
|
|
12213
12645
|
const { roots, unreadManifests } = rootsOfRun(options);
|
|
12214
12646
|
const timer = options.onTiming !== void 0 ? (0, import_extractor18.createTimer)() : (0, import_extractor18.noopTimer)();
|
|
12215
12647
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
12216
|
-
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ?
|
|
12648
|
+
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? (0, import_extractor18.extractionCacheDirFor)(options.projectRoot) : null)
|
|
12217
12649
|
);
|
|
12218
12650
|
const layer = (0, import_extractor18.createCacheLayer)(cacheDir);
|
|
12219
12651
|
const packsDigest = `${adapterStamp.packsDigest(
|
|
@@ -12236,11 +12668,14 @@ async function extractPythonProject(options) {
|
|
|
12236
12668
|
"cache.lookup",
|
|
12237
12669
|
() => layer.lookup(input)
|
|
12238
12670
|
);
|
|
12671
|
+
const composed = (stored) => (0, import_extractor18.composeWrappers)(stored, {
|
|
12672
|
+
gapHandling: options.gapHandling ?? "permissive"
|
|
12673
|
+
});
|
|
12239
12674
|
if (lookup.kind === "hit") {
|
|
12240
12675
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
12241
12676
|
options.onTiming?.(timer.report());
|
|
12242
12677
|
return {
|
|
12243
|
-
summaries: lookup.summaries,
|
|
12678
|
+
summaries: composed(lookup.summaries),
|
|
12244
12679
|
facts: new import_datalog2.Database(),
|
|
12245
12680
|
roots,
|
|
12246
12681
|
unreadManifests
|
|
@@ -12255,7 +12690,7 @@ async function extractPythonProject(options) {
|
|
|
12255
12690
|
options.onCacheDiagnostic?.({ kind: "hit" });
|
|
12256
12691
|
options.onTiming?.(timer.report());
|
|
12257
12692
|
return {
|
|
12258
|
-
summaries: plan.allSummaries(),
|
|
12693
|
+
summaries: composed(plan.allSummaries()),
|
|
12259
12694
|
facts: new import_datalog2.Database(),
|
|
12260
12695
|
roots,
|
|
12261
12696
|
unreadManifests
|
|
@@ -12437,15 +12872,10 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12437
12872
|
});
|
|
12438
12873
|
let registering = null;
|
|
12439
12874
|
if (ledger !== null) {
|
|
12440
|
-
wrapperIndex.onRegistered = (target,
|
|
12441
|
-
const
|
|
12442
|
-
if (registering !== null &&
|
|
12443
|
-
registering.push(
|
|
12444
|
-
key: nodeId(target.file.file, target.node),
|
|
12445
|
-
name: target.name,
|
|
12446
|
-
exportPath: target.exportPath,
|
|
12447
|
-
form
|
|
12448
|
-
});
|
|
12875
|
+
wrapperIndex.onRegistered = (target, how) => {
|
|
12876
|
+
const stored = storedRegistration(target, how, positions);
|
|
12877
|
+
if (registering !== null && stored !== null) {
|
|
12878
|
+
registering.push(stored);
|
|
12449
12879
|
}
|
|
12450
12880
|
};
|
|
12451
12881
|
}
|
|
@@ -12458,12 +12888,11 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12458
12888
|
if (record !== void 0) {
|
|
12459
12889
|
discoveries.set(file, record);
|
|
12460
12890
|
for (const registration of record.registrations) {
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
}
|
|
12466
|
-
wrapperIndex.registered(target, declared);
|
|
12891
|
+
registerAgain(registration, {
|
|
12892
|
+
positions,
|
|
12893
|
+
wrapperIndex,
|
|
12894
|
+
target: storedFunction(registration, definitions, filesByPath)
|
|
12895
|
+
});
|
|
12467
12896
|
}
|
|
12468
12897
|
continue;
|
|
12469
12898
|
}
|
|
@@ -12632,6 +13061,7 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12632
13061
|
}
|
|
12633
13062
|
(0, import_behavioral_ir10.placeCalls)(summary, reached.targetsByKey.get(key));
|
|
12634
13063
|
(0, import_behavioral_ir10.placeArgTargets)(summary, reached.argTargetsByKey.get(key));
|
|
13064
|
+
(0, import_behavioral_ir10.placePossibleCalls)(summary, reached.possibleTargetsByKey.get(key));
|
|
12635
13065
|
(0, import_behavioral_ir10.placeCalleeParameters)(summary, reached.parameterCallsByKey.get(key));
|
|
12636
13066
|
};
|
|
12637
13067
|
for (const [key, owners] of summariesBySeed) {
|
|
@@ -12721,16 +13151,20 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12721
13151
|
markExitCodeFunctions(summaries, exits, db, options.workspaceRoot);
|
|
12722
13152
|
return (0, import_extractor18.composeWrappers)(summaries, { gapHandling });
|
|
12723
13153
|
});
|
|
13154
|
+
const walkedFiles = new Map(
|
|
13155
|
+
bound.map(({ file, displayPath }) => [displayPath, file])
|
|
13156
|
+
);
|
|
12724
13157
|
await timer.timeAsync("cache.write", async () => {
|
|
12725
|
-
if (cacheDir === null ||
|
|
13158
|
+
if (cacheDir === null || summaries.length === 0) {
|
|
12726
13159
|
return;
|
|
12727
13160
|
}
|
|
12728
13161
|
try {
|
|
12729
13162
|
await cache.layer.write(
|
|
12730
13163
|
cache.input,
|
|
12731
|
-
|
|
13164
|
+
summaries,
|
|
12732
13165
|
log === null || ledger === null || overBudget ? void 0 : pythonAttribution({
|
|
12733
|
-
|
|
13166
|
+
summaries,
|
|
13167
|
+
walkedFileOf: (locationFile) => walkedFiles.get(locationFile),
|
|
12734
13168
|
discoveries,
|
|
12735
13169
|
charges,
|
|
12736
13170
|
unitDrafts,
|
|
@@ -12785,6 +13219,39 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12785
13219
|
options.onTiming?.(timer.report());
|
|
12786
13220
|
return { summaries: composed, facts: db };
|
|
12787
13221
|
}
|
|
13222
|
+
function storedRegistration(target, how, positions) {
|
|
13223
|
+
const at = {
|
|
13224
|
+
key: nodeId(target.file.file, target.node),
|
|
13225
|
+
name: target.name,
|
|
13226
|
+
exportPath: target.exportPath
|
|
13227
|
+
};
|
|
13228
|
+
if ("continuation" in how) {
|
|
13229
|
+
const pattern = positions.idOf(how.pattern);
|
|
13230
|
+
return pattern === void 0 ? null : { ...at, pattern, continuation: how.continuation };
|
|
13231
|
+
}
|
|
13232
|
+
const form = positions.positionOf(how);
|
|
13233
|
+
return form === void 0 ? null : { ...at, form };
|
|
13234
|
+
}
|
|
13235
|
+
function registerAgain(registration, context) {
|
|
13236
|
+
const { positions, wrapperIndex, target } = context;
|
|
13237
|
+
const how = howRegistered(registration, positions);
|
|
13238
|
+
if (target === null || how === null) {
|
|
13239
|
+
throw new ReplayFailed(registration.key);
|
|
13240
|
+
}
|
|
13241
|
+
if ("continuation" in how) {
|
|
13242
|
+
wrapperIndex.registeredClosure(target, how);
|
|
13243
|
+
return;
|
|
13244
|
+
}
|
|
13245
|
+
wrapperIndex.registered(target, how);
|
|
13246
|
+
}
|
|
13247
|
+
function howRegistered(registration, positions) {
|
|
13248
|
+
if (!("continuation" in registration)) {
|
|
13249
|
+
return positions.formAt(registration.form) ?? null;
|
|
13250
|
+
}
|
|
13251
|
+
const pack = positions.packOf(registration.pattern);
|
|
13252
|
+
const pattern = positions.patternOf(registration.pattern);
|
|
13253
|
+
return pack === void 0 || pattern === void 0 ? null : { pack, pattern, continuation: registration.continuation };
|
|
13254
|
+
}
|
|
12788
13255
|
function pythonAttribution(args) {
|
|
12789
13256
|
const walkedByFile = (0, import_resolution18.walkRecordsByFile)({
|
|
12790
13257
|
scans: args.reached.scans,
|
|
@@ -12813,7 +13280,10 @@ function pythonAttribution(args) {
|
|
|
12813
13280
|
}
|
|
12814
13281
|
};
|
|
12815
13282
|
});
|
|
12816
|
-
return {
|
|
13283
|
+
return {
|
|
13284
|
+
roots,
|
|
13285
|
+
owners: (0, import_extractor18.ownersWhereWritten)(args.summaries, args.walkedFileOf)
|
|
13286
|
+
};
|
|
12817
13287
|
}
|
|
12818
13288
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
12819
13289
|
"__pycache__",
|