@suss/adapter-python 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/index.cjs +654 -224
- package/dist/index.d.cts +65 -1
- package/dist/index.d.ts +65 -1
- package/dist/index.js +652 -221
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -29,6 +29,12 @@ var LATER_BODY_TYPES = /* @__PURE__ */ new Set([
|
|
|
29
29
|
"lambda",
|
|
30
30
|
"class_definition"
|
|
31
31
|
]);
|
|
32
|
+
function isModule(node) {
|
|
33
|
+
return node.type === "module";
|
|
34
|
+
}
|
|
35
|
+
function runsAtModuleLoad(node) {
|
|
36
|
+
return !LATER_BODY_TYPES.has(node.type) && node.type !== "decorator";
|
|
37
|
+
}
|
|
32
38
|
function enclosingFunction(node) {
|
|
33
39
|
let current = node.parent;
|
|
34
40
|
while (current !== null) {
|
|
@@ -724,8 +730,14 @@ import {
|
|
|
724
730
|
function resolveCalls(db, callKeys) {
|
|
725
731
|
askResolution(db, callKeys);
|
|
726
732
|
}
|
|
727
|
-
function
|
|
728
|
-
askResolution(db,
|
|
733
|
+
function resolveEnvObjects(db, objectKeys) {
|
|
734
|
+
askResolution(db, objectKeys, "wantedEnvObject");
|
|
735
|
+
}
|
|
736
|
+
function resolvedFunctions(db, key) {
|
|
737
|
+
return [
|
|
738
|
+
...db.lookup("wantedResolves", 0, key),
|
|
739
|
+
...db.lookup("wantedGivesBack", 0, key)
|
|
740
|
+
].map((row) => String(row[1]));
|
|
729
741
|
}
|
|
730
742
|
function writtenValueUnder(db, key, site) {
|
|
731
743
|
if (askResolutionUnder(db, [[key, site]]) === "abandoned") {
|
|
@@ -745,6 +757,13 @@ function writtenValuesOf(db, key) {
|
|
|
745
757
|
resolveCalls(db, [key]);
|
|
746
758
|
return sharedWrittenValuesOf(db, key, (keys) => resolveCalls(db, keys));
|
|
747
759
|
}
|
|
760
|
+
function settleWrittenValues(db, keys) {
|
|
761
|
+
if (keys.length === 0) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
resolveCalls(db, keys);
|
|
765
|
+
writtenValuesByKey(db, keys, (behind) => resolveCalls(db, behind));
|
|
766
|
+
}
|
|
748
767
|
function originsOf(db, nameKey2) {
|
|
749
768
|
askResolution(db, [nameKey2], "wantedOrigin");
|
|
750
769
|
return db.facts("wantedComesFrom").filter((row) => String(row[0]) === nameKey2).map((row) => ({ module: String(row[1]), name: String(row[2]) }));
|
|
@@ -1045,9 +1064,51 @@ function walkExpressions(emitter, node, visit) {
|
|
|
1045
1064
|
walkExpressions(emitter, child, visit);
|
|
1046
1065
|
}
|
|
1047
1066
|
}
|
|
1067
|
+
var WRITTEN_KEY_TYPES = /* @__PURE__ */ new Set(["string", "integer", "concatenated_string"]);
|
|
1068
|
+
function emitKeyedRead(emitter, site, container, key) {
|
|
1069
|
+
if (WRITTEN_KEY_TYPES.has(key.type)) {
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
add(
|
|
1073
|
+
emitter,
|
|
1074
|
+
"readsKeyed",
|
|
1075
|
+
nodeId(emitter.filePath, site),
|
|
1076
|
+
valueKey(emitter, container),
|
|
1077
|
+
valueKey(emitter, key)
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
function singleSubscript(node) {
|
|
1081
|
+
const written = fields(node, "subscript");
|
|
1082
|
+
return written.length === 1 ? written[0] ?? null : null;
|
|
1083
|
+
}
|
|
1084
|
+
function mappingGetRead(call) {
|
|
1085
|
+
const callee = field(call, "function");
|
|
1086
|
+
if (callee === null || callee.type !== "attribute") {
|
|
1087
|
+
return null;
|
|
1088
|
+
}
|
|
1089
|
+
const container = field(callee, "object");
|
|
1090
|
+
if (container === null || field(callee, "attribute")?.text !== "get") {
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
const first = callArguments(call).find(
|
|
1094
|
+
(argument) => argument.kind === "positional" && argument.position === 0
|
|
1095
|
+
);
|
|
1096
|
+
return first === void 0 ? null : { container, key: first.node };
|
|
1097
|
+
}
|
|
1048
1098
|
function emitExpressionFact(emitter, child) {
|
|
1049
1099
|
if (child.type === "call") {
|
|
1050
1100
|
emitCall(emitter, child);
|
|
1101
|
+
const mapping = mappingGetRead(child);
|
|
1102
|
+
if (mapping !== null) {
|
|
1103
|
+
emitKeyedRead(emitter, child, mapping.container, mapping.key);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (child.type === "subscript") {
|
|
1107
|
+
const index = singleSubscript(child);
|
|
1108
|
+
const container = field(child, "value");
|
|
1109
|
+
if (index !== null && container !== null) {
|
|
1110
|
+
emitKeyedRead(emitter, child, container, index);
|
|
1111
|
+
}
|
|
1051
1112
|
}
|
|
1052
1113
|
if (child.type === "dictionary") {
|
|
1053
1114
|
emitDictionary(emitter, child);
|
|
@@ -1115,6 +1176,9 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1115
1176
|
return funcKey;
|
|
1116
1177
|
}
|
|
1117
1178
|
emitNestedDefinitions(inside, body);
|
|
1179
|
+
if (fn.type === "lambda") {
|
|
1180
|
+
emitExpressionFact(inside, body);
|
|
1181
|
+
}
|
|
1118
1182
|
let statesReturn = false;
|
|
1119
1183
|
const stores = /* @__PURE__ */ new Map();
|
|
1120
1184
|
walkExpressions(inside, body, (child) => {
|
|
@@ -2532,8 +2596,17 @@ function askWrittenValues(nodes, db) {
|
|
|
2532
2596
|
if (bound === void 0) {
|
|
2533
2597
|
return;
|
|
2534
2598
|
}
|
|
2535
|
-
|
|
2536
|
-
|
|
2599
|
+
settleWrittenValues(db, resolutionKeysOf(nodes, bound));
|
|
2600
|
+
}
|
|
2601
|
+
function resolutionKeysOf(nodes, bound) {
|
|
2602
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2603
|
+
for (const node of nodes) {
|
|
2604
|
+
const key = bound.keyOf(node);
|
|
2605
|
+
if (key !== null) {
|
|
2606
|
+
keys.add(key);
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
return [...keys];
|
|
2537
2610
|
}
|
|
2538
2611
|
function evaluatedValue(node, db, site) {
|
|
2539
2612
|
const evaluator = evaluatorFor(node, db);
|
|
@@ -2601,7 +2674,7 @@ function projectOver(db, nodes) {
|
|
|
2601
2674
|
filesByRoot.set(entry.root.id, entry);
|
|
2602
2675
|
rootsByFile.set(entry.file, entry.root);
|
|
2603
2676
|
}
|
|
2604
|
-
const
|
|
2677
|
+
const keyOf3 = (node) => {
|
|
2605
2678
|
const entry = filesByRoot.get(node.tree.rootNode.id);
|
|
2606
2679
|
if (entry === void 0) {
|
|
2607
2680
|
return null;
|
|
@@ -2610,7 +2683,7 @@ function projectOver(db, nodes) {
|
|
|
2610
2683
|
};
|
|
2611
2684
|
const context = {
|
|
2612
2685
|
writtenTo: (node, site) => {
|
|
2613
|
-
const key =
|
|
2686
|
+
const key = keyOf3(node);
|
|
2614
2687
|
if (key === null) {
|
|
2615
2688
|
return null;
|
|
2616
2689
|
}
|
|
@@ -2619,17 +2692,17 @@ function projectOver(db, nodes) {
|
|
|
2619
2692
|
},
|
|
2620
2693
|
callable: (call) => {
|
|
2621
2694
|
const callee = field(call, "function");
|
|
2622
|
-
const key = callee === null ? null :
|
|
2695
|
+
const key = callee === null ? null : keyOf3(callee);
|
|
2623
2696
|
if (key === null) {
|
|
2624
2697
|
return null;
|
|
2625
2698
|
}
|
|
2626
2699
|
resolveCalls(db, [key]);
|
|
2627
|
-
const resolved = db.
|
|
2628
|
-
const settled = resolved.length === 1 ? resolved[0] : void 0;
|
|
2700
|
+
const resolved = db.lookup("wantedResolves", 0, key);
|
|
2701
|
+
const settled = resolved.length === 1 ? String(resolved[0]?.[1]) : void 0;
|
|
2629
2702
|
return settled === void 0 ? null : nodes.definitions.get(settled) ?? null;
|
|
2630
2703
|
}
|
|
2631
2704
|
};
|
|
2632
|
-
return { keyOf:
|
|
2705
|
+
return { keyOf: keyOf3, roots: rootsByFile, context };
|
|
2633
2706
|
}
|
|
2634
2707
|
|
|
2635
2708
|
// src/decorators.ts
|
|
@@ -3267,6 +3340,18 @@ function bodyCalls(node, found = []) {
|
|
|
3267
3340
|
}
|
|
3268
3341
|
return found;
|
|
3269
3342
|
}
|
|
3343
|
+
function moduleLoadCalls(node, found = []) {
|
|
3344
|
+
for (const child of node.namedChildren) {
|
|
3345
|
+
if (child === null || !runsAtModuleLoad(child)) {
|
|
3346
|
+
continue;
|
|
3347
|
+
}
|
|
3348
|
+
if (child.type === "call") {
|
|
3349
|
+
found.push(child);
|
|
3350
|
+
}
|
|
3351
|
+
moduleLoadCalls(child, found);
|
|
3352
|
+
}
|
|
3353
|
+
return found;
|
|
3354
|
+
}
|
|
3270
3355
|
function enclosingStatement(call, body) {
|
|
3271
3356
|
let current = call;
|
|
3272
3357
|
while (current !== null && current.parent !== null) {
|
|
@@ -3291,15 +3376,18 @@ function argOf(node, facts) {
|
|
|
3291
3376
|
}
|
|
3292
3377
|
return { kind: "identifier", name: node.text };
|
|
3293
3378
|
}
|
|
3294
|
-
function
|
|
3379
|
+
function argumentNodes(call) {
|
|
3295
3380
|
const args = field(call, "arguments");
|
|
3296
3381
|
if (args === null) {
|
|
3297
3382
|
return [];
|
|
3298
3383
|
}
|
|
3299
3384
|
return args.namedChildren.filter((child) => child !== null).map(
|
|
3300
|
-
(child) => child.type === "keyword_argument" ?
|
|
3385
|
+
(child) => child.type === "keyword_argument" ? field(child, "value") ?? child : child
|
|
3301
3386
|
);
|
|
3302
3387
|
}
|
|
3388
|
+
function argsOf(call, facts) {
|
|
3389
|
+
return argumentNodes(call).map((node) => argOf(node, facts));
|
|
3390
|
+
}
|
|
3303
3391
|
function calleeText(call) {
|
|
3304
3392
|
return field(call, "function")?.text ?? call.text;
|
|
3305
3393
|
}
|
|
@@ -3308,7 +3396,40 @@ function invocationEffects(definitionNode, facts) {
|
|
|
3308
3396
|
if (body === null) {
|
|
3309
3397
|
return [];
|
|
3310
3398
|
}
|
|
3311
|
-
|
|
3399
|
+
return invocationEffectsIn(body, bodyCalls(body), facts);
|
|
3400
|
+
}
|
|
3401
|
+
function moduleLoadInvocationEffects(moduleNode, facts) {
|
|
3402
|
+
return invocationEffectsIn(moduleNode, moduleLoadCalls(moduleNode), facts);
|
|
3403
|
+
}
|
|
3404
|
+
var ASKED_ABOUT_TYPES = /* @__PURE__ */ new Set(["identifier", "attribute", "call"]);
|
|
3405
|
+
function askedNodesUnder(node, found = []) {
|
|
3406
|
+
if (ASKED_ABOUT_TYPES.has(node.type)) {
|
|
3407
|
+
found.push(node);
|
|
3408
|
+
}
|
|
3409
|
+
for (const child of node.namedChildren) {
|
|
3410
|
+
if (child !== null && !NESTED_DEFINITION_TYPES.has(child.type)) {
|
|
3411
|
+
askedNodesUnder(child, found);
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
return found;
|
|
3415
|
+
}
|
|
3416
|
+
function bodyValueNodes(definitionNode) {
|
|
3417
|
+
const body = field(definitionNode, "body");
|
|
3418
|
+
return body === null ? [] : askedNodesUnder(body);
|
|
3419
|
+
}
|
|
3420
|
+
function effectValueNodes(call, gating) {
|
|
3421
|
+
const found = argumentNodes(call).flatMap((node) => askedNodesUnder(node));
|
|
3422
|
+
for (const path6 of gating ?? []) {
|
|
3423
|
+
for (const condition of path6) {
|
|
3424
|
+
if (condition.expression !== null) {
|
|
3425
|
+
askedNodesUnder(condition.expression, found);
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
return found;
|
|
3430
|
+
}
|
|
3431
|
+
function invocationEffectsIn(body, written, facts) {
|
|
3432
|
+
const calls = [...written].sort((a, b) => a.endIndex - b.endIndex);
|
|
3312
3433
|
if (calls.length === 0) {
|
|
3313
3434
|
return [];
|
|
3314
3435
|
}
|
|
@@ -3330,10 +3451,17 @@ function invocationEffects(definitionNode, facts) {
|
|
|
3330
3451
|
},
|
|
3331
3452
|
statements
|
|
3332
3453
|
);
|
|
3333
|
-
|
|
3454
|
+
const gatingOf = calls.map((call) => {
|
|
3334
3455
|
const statement = statementOf3.get(call.id);
|
|
3456
|
+
return statement === void 0 ? void 0 : enumerated.byTerminal.get(statement);
|
|
3457
|
+
});
|
|
3458
|
+
askWrittenValues(
|
|
3459
|
+
calls.flatMap((call, index) => effectValueNodes(call, gatingOf[index])),
|
|
3460
|
+
facts
|
|
3461
|
+
);
|
|
3462
|
+
return calls.map((call, index) => {
|
|
3335
3463
|
const conditions = sharedGatingConditions(
|
|
3336
|
-
|
|
3464
|
+
gatingOf[index],
|
|
3337
3465
|
(condition) => predicateOf(condition, facts)
|
|
3338
3466
|
);
|
|
3339
3467
|
return {
|
|
@@ -3364,6 +3492,22 @@ function clientCallUnits(root, module, pack, pattern, options) {
|
|
|
3364
3492
|
}
|
|
3365
3493
|
return units;
|
|
3366
3494
|
}
|
|
3495
|
+
function clientCallReceivers(root, module) {
|
|
3496
|
+
const found = [];
|
|
3497
|
+
for (const definition of functionDefinitions(root)) {
|
|
3498
|
+
for (const call of bodyCalls(definition)) {
|
|
3499
|
+
const callee = field(call, "function");
|
|
3500
|
+
if (callee === null || originOf(callee, module) !== null) {
|
|
3501
|
+
continue;
|
|
3502
|
+
}
|
|
3503
|
+
const object = field(callee, "object");
|
|
3504
|
+
if (object !== null && field(callee, "attribute") !== null) {
|
|
3505
|
+
found.push(object);
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
return found;
|
|
3510
|
+
}
|
|
3367
3511
|
function functionDefinitions(node, found = []) {
|
|
3368
3512
|
for (const child of children(node)) {
|
|
3369
3513
|
if (isFunction(child)) {
|
|
@@ -3726,44 +3870,91 @@ function isDefaultedAt(node) {
|
|
|
3726
3870
|
}
|
|
3727
3871
|
return false;
|
|
3728
3872
|
}
|
|
3729
|
-
function
|
|
3730
|
-
const
|
|
3873
|
+
function envFactsIn(filePath, root, module) {
|
|
3874
|
+
const found = { sites: [], objects: [] };
|
|
3731
3875
|
walkDescendants(root, module.moduleScope, {
|
|
3732
3876
|
at: (node, scope) => {
|
|
3877
|
+
if (isEnviron(node, scope) && handsOnward(node)) {
|
|
3878
|
+
found.objects.push(keyOf(filePath, node));
|
|
3879
|
+
}
|
|
3733
3880
|
const syntax = envReadSyntaxAt(node, scope);
|
|
3734
3881
|
if (syntax === null || stringLiteralValue(syntax.name) !== null) {
|
|
3735
3882
|
return;
|
|
3736
3883
|
}
|
|
3737
|
-
sites.push({
|
|
3884
|
+
found.sites.push({
|
|
3738
3885
|
site: nodeId(filePath, node),
|
|
3739
|
-
nameKey:
|
|
3740
|
-
defaulted: syntax.defaulted
|
|
3886
|
+
nameKey: keyOf(filePath, syntax.name),
|
|
3887
|
+
defaulted: syntax.defaulted,
|
|
3888
|
+
functionKey: functionReadKey(filePath, node, scope)
|
|
3741
3889
|
});
|
|
3742
3890
|
},
|
|
3743
3891
|
into: (node, scope) => module.scopeFor.get(node.id) ?? scope
|
|
3744
3892
|
});
|
|
3745
|
-
return
|
|
3893
|
+
return found;
|
|
3894
|
+
}
|
|
3895
|
+
var keyOf = (filePath, node) => readKey(filePath, node, enclosingFunction(node));
|
|
3896
|
+
function functionReadKey(filePath, node, scope) {
|
|
3897
|
+
if (node.type !== "call") {
|
|
3898
|
+
return null;
|
|
3899
|
+
}
|
|
3900
|
+
const callee = field(node, "function");
|
|
3901
|
+
if (callee === null || isEnviron(field(callee, "object") ?? callee, scope)) {
|
|
3902
|
+
return null;
|
|
3903
|
+
}
|
|
3904
|
+
return keyOf(filePath, callee);
|
|
3905
|
+
}
|
|
3906
|
+
function handsOnward(node) {
|
|
3907
|
+
const parent = node.parent;
|
|
3908
|
+
if (parent === null) {
|
|
3909
|
+
return true;
|
|
3910
|
+
}
|
|
3911
|
+
if (parent.type === "subscript" && field(parent, "value")?.id === node.id) {
|
|
3912
|
+
return !writesTheKey(field(parent, "subscript"));
|
|
3913
|
+
}
|
|
3914
|
+
if (parent.type === "attribute" && field(parent, "object")?.id === node.id) {
|
|
3915
|
+
const call = parent.parent;
|
|
3916
|
+
return field(parent, "attribute")?.text === "get" && call !== null && call.type === "call" && !writesTheKey(firstArgumentOf(call));
|
|
3917
|
+
}
|
|
3918
|
+
return true;
|
|
3919
|
+
}
|
|
3920
|
+
var writesTheKey = (key) => key !== null && stringLiteralValue(key) !== null;
|
|
3921
|
+
function firstArgumentOf(call) {
|
|
3922
|
+
const first = callArguments(call).find(
|
|
3923
|
+
(argument) => argument.kind === "positional" && argument.position === 0
|
|
3924
|
+
);
|
|
3925
|
+
return first?.node ?? null;
|
|
3746
3926
|
}
|
|
3747
3927
|
var sitesByDb = /* @__PURE__ */ new WeakMap();
|
|
3748
|
-
function
|
|
3749
|
-
|
|
3928
|
+
function bindEnvFacts(db, found) {
|
|
3929
|
+
const sites = found.flatMap((one) => one.sites);
|
|
3930
|
+
const objects = found.flatMap((one) => one.objects);
|
|
3931
|
+
if (sites.length === 0 && objects.length === 0) {
|
|
3750
3932
|
return;
|
|
3751
3933
|
}
|
|
3752
3934
|
let index = sitesByDb.get(db);
|
|
3753
3935
|
if (index === void 0) {
|
|
3754
|
-
index = { byId: /* @__PURE__ */ new Map(), sitesByParameter: null };
|
|
3936
|
+
index = { byId: /* @__PURE__ */ new Map(), objects: /* @__PURE__ */ new Set(), sitesByParameter: null };
|
|
3755
3937
|
sitesByDb.set(db, index);
|
|
3756
3938
|
}
|
|
3939
|
+
for (const object of objects) {
|
|
3940
|
+
db.add("environmentObject", [object]);
|
|
3941
|
+
index.objects.add(object);
|
|
3942
|
+
}
|
|
3757
3943
|
for (const site of sites) {
|
|
3758
|
-
db.add("readsEnvNamed", [site.site, site.nameKey]);
|
|
3759
3944
|
index.byId.set(site.site, site);
|
|
3945
|
+
if (site.functionKey === null) {
|
|
3946
|
+
continue;
|
|
3947
|
+
}
|
|
3948
|
+
db.add("environmentObject", [site.functionKey]);
|
|
3949
|
+
db.add("readsKeyed", [site.site, site.functionKey, site.nameKey]);
|
|
3950
|
+
index.objects.add(site.functionKey);
|
|
3760
3951
|
}
|
|
3761
3952
|
}
|
|
3762
3953
|
function sitesEachParameterNames(db, index) {
|
|
3763
3954
|
if (index.sitesByParameter !== null) {
|
|
3764
3955
|
return index.sitesByParameter;
|
|
3765
3956
|
}
|
|
3766
|
-
|
|
3957
|
+
resolveEnvObjects(db, [...index.objects]);
|
|
3767
3958
|
const found = /* @__PURE__ */ new Map();
|
|
3768
3959
|
for (const row of db.facts("wantedParamNamesEnv")) {
|
|
3769
3960
|
const parameter = String(row[0]);
|
|
@@ -3827,8 +4018,7 @@ function argumentsByParameter(db, call, calleeKey) {
|
|
|
3827
4018
|
positional.set(String(argument.position), argument.node);
|
|
3828
4019
|
}
|
|
3829
4020
|
const argumentAt2 = /* @__PURE__ */ new Map();
|
|
3830
|
-
for (const
|
|
3831
|
-
const callee = String(resolved[1]);
|
|
4021
|
+
for (const callee of resolvedFunctions(db, calleeKey)) {
|
|
3832
4022
|
for (const row of db.lookup("paramOf", 0, callee)) {
|
|
3833
4023
|
const at = positional.get(String(row[1]));
|
|
3834
4024
|
if (at !== void 0) {
|
|
@@ -3856,10 +4046,8 @@ function readsThroughHelper(db, call, argumentAt2, siteById, named) {
|
|
|
3856
4046
|
continue;
|
|
3857
4047
|
}
|
|
3858
4048
|
for (const id of sites) {
|
|
3859
|
-
const
|
|
3860
|
-
|
|
3861
|
-
reads.set(name, (reads.get(name) ?? true) && site.defaulted);
|
|
3862
|
-
}
|
|
4049
|
+
const defaulted = siteById.get(id)?.defaulted ?? false;
|
|
4050
|
+
reads.set(name, (reads.get(name) ?? true) && defaulted);
|
|
3863
4051
|
}
|
|
3864
4052
|
}
|
|
3865
4053
|
if (reads.size === 0) {
|
|
@@ -4078,72 +4266,302 @@ function returnedBodyShape(statement) {
|
|
|
4078
4266
|
|
|
4079
4267
|
// src/rawSql.ts
|
|
4080
4268
|
import { storageBinding } from "@suss/ir-core";
|
|
4081
|
-
import { readSqlAccess, sqlFromParts } from "@suss/sql";
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4269
|
+
import { readSqlAccess, splitQualifiedTable, sqlFromParts } from "@suss/sql";
|
|
4270
|
+
import { force as force2 } from "@suss/values";
|
|
4271
|
+
|
|
4272
|
+
// src/receiverTypes.ts
|
|
4273
|
+
var UNDECLARED_MODULE = "builtins";
|
|
4274
|
+
function annotationTarget(annotation) {
|
|
4275
|
+
if (annotation.type === "type" && annotation.namedChildren[0]) {
|
|
4276
|
+
return annotationTarget(annotation.namedChildren[0]);
|
|
4085
4277
|
}
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4278
|
+
if (annotation.type === "binary_operator") {
|
|
4279
|
+
const named = [field(annotation, "left"), field(annotation, "right")].find(
|
|
4280
|
+
(side) => side !== null && side.type !== "none"
|
|
4281
|
+
);
|
|
4282
|
+
return named === void 0 || named === null ? null : annotationTarget(named);
|
|
4283
|
+
}
|
|
4284
|
+
if (annotation.type === "generic_type") {
|
|
4285
|
+
const outer = annotation.namedChildren[0];
|
|
4286
|
+
const first = genericTypeArgs(annotation)[0];
|
|
4287
|
+
if ((outer?.text === "Annotated" || outer?.text === "Optional") && first !== void 0) {
|
|
4288
|
+
return annotationTarget(first);
|
|
4091
4289
|
}
|
|
4092
|
-
|
|
4093
|
-
|
|
4290
|
+
return outer ?? null;
|
|
4291
|
+
}
|
|
4292
|
+
return annotation;
|
|
4293
|
+
}
|
|
4294
|
+
function typeNameOf(annotation) {
|
|
4295
|
+
const target = annotationTarget(annotation);
|
|
4296
|
+
if (target === null) {
|
|
4297
|
+
return null;
|
|
4298
|
+
}
|
|
4299
|
+
return target.type === "identifier" ? target.text : stringLiteralValue(target);
|
|
4300
|
+
}
|
|
4301
|
+
function firstInBody(node, read) {
|
|
4302
|
+
const here = read(node);
|
|
4303
|
+
if (here !== null) {
|
|
4304
|
+
return here;
|
|
4305
|
+
}
|
|
4306
|
+
for (const child of children(node)) {
|
|
4307
|
+
if (child.type === "function_definition" || child.type === "lambda") {
|
|
4094
4308
|
continue;
|
|
4095
4309
|
}
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4310
|
+
const found = firstInBody(child, read);
|
|
4311
|
+
if (found !== null) {
|
|
4312
|
+
return found;
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
return null;
|
|
4316
|
+
}
|
|
4317
|
+
function statedBy(statement, name) {
|
|
4318
|
+
if (statement.type === "assignment") {
|
|
4319
|
+
const annotation = field(statement, "type");
|
|
4320
|
+
return field(statement, "left")?.text === name ? annotation : null;
|
|
4321
|
+
}
|
|
4322
|
+
if (statement.type === "as_pattern") {
|
|
4323
|
+
const alias = field(statement, "alias");
|
|
4324
|
+
const value = statement.namedChildren[0] ?? null;
|
|
4325
|
+
const callee = value?.type === "call" ? field(value, "function") : null;
|
|
4326
|
+
return alias?.text === name ? callee : null;
|
|
4327
|
+
}
|
|
4328
|
+
return null;
|
|
4329
|
+
}
|
|
4330
|
+
function statedTypeNode(name, from) {
|
|
4331
|
+
const fn = enclosingFunction(from);
|
|
4332
|
+
if (fn === null) {
|
|
4333
|
+
return null;
|
|
4334
|
+
}
|
|
4335
|
+
const params = field(fn, "parameters");
|
|
4336
|
+
for (const param of params === null ? [] : children(params)) {
|
|
4337
|
+
const info = parameterNameAndType(param);
|
|
4338
|
+
if (info?.name === name && info.typeNode !== null) {
|
|
4339
|
+
return info.typeNode;
|
|
4116
4340
|
}
|
|
4117
4341
|
}
|
|
4118
|
-
|
|
4342
|
+
const body = field(fn, "body");
|
|
4343
|
+
return body === null ? null : firstInBody(body, (statement) => statedBy(statement, name));
|
|
4344
|
+
}
|
|
4345
|
+
function statedTypeName(name, from) {
|
|
4346
|
+
const stated = statedTypeNode(name, from);
|
|
4347
|
+
return stated === null ? null : typeNameOf(stated);
|
|
4348
|
+
}
|
|
4349
|
+
function statedOrigins(stated, options) {
|
|
4350
|
+
const name = typeNameOf(stated);
|
|
4351
|
+
const byRule = name === null ? [] : originsOf(options.facts, `${options.filePath}#${name}`);
|
|
4352
|
+
const target = annotationTarget(stated);
|
|
4353
|
+
const imported = target === null ? null : originOf(target, moduleOf(target));
|
|
4354
|
+
if (imported === null || imported.module === UNDECLARED_MODULE) {
|
|
4355
|
+
return byRule;
|
|
4356
|
+
}
|
|
4357
|
+
return [...byRule, imported];
|
|
4358
|
+
}
|
|
4359
|
+
function receiverTypeOrigins(receiver, options) {
|
|
4360
|
+
const stated = statedTypeNode(receiver.text, receiver);
|
|
4361
|
+
if (stated !== null) {
|
|
4362
|
+
return statedOrigins(stated, options);
|
|
4363
|
+
}
|
|
4364
|
+
const built = constructionBehind(receiver, options.facts);
|
|
4365
|
+
if (built.type === "oneCall") {
|
|
4366
|
+
return [built.construction.origin];
|
|
4367
|
+
}
|
|
4368
|
+
const key = nameKeyIn(
|
|
4369
|
+
options.filePath,
|
|
4370
|
+
enclosingFunction(receiver),
|
|
4371
|
+
receiver.text
|
|
4372
|
+
);
|
|
4373
|
+
return subjectConstructions(options.facts, [key]).get(key)?.origins ?? [];
|
|
4374
|
+
}
|
|
4375
|
+
|
|
4376
|
+
// src/rawSql.ts
|
|
4377
|
+
function rawSqlEffects(calls, options) {
|
|
4378
|
+
return matchesIn(calls, options).flatMap(
|
|
4379
|
+
(match) => match.accesses.flatMap((access) => effectFor(match, access))
|
|
4380
|
+
);
|
|
4381
|
+
}
|
|
4382
|
+
function rawSqlCallIds(calls, options) {
|
|
4383
|
+
return new Set(matchesIn(calls, options).map((match) => match.call.id));
|
|
4384
|
+
}
|
|
4385
|
+
function matchesIn(calls, options) {
|
|
4386
|
+
if (options.patterns.length === 0 && (options.clients ?? []).length === 0) {
|
|
4387
|
+
return [];
|
|
4388
|
+
}
|
|
4389
|
+
const matched = [];
|
|
4390
|
+
for (const call of calls) {
|
|
4391
|
+
const one = importedFunctionMatch(call, options) ?? clientMatch(call, options);
|
|
4392
|
+
if (one !== null) {
|
|
4393
|
+
matched.push(one);
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
return matched;
|
|
4397
|
+
}
|
|
4398
|
+
function effectFor(match, access) {
|
|
4399
|
+
const operation = field(match.call, "function")?.text ?? "";
|
|
4400
|
+
return [
|
|
4401
|
+
{
|
|
4402
|
+
type: "interaction",
|
|
4403
|
+
binding: storageBinding({
|
|
4404
|
+
recognition: match.recognition,
|
|
4405
|
+
storageSystem: match.storageSystem,
|
|
4406
|
+
scope: access.qualifier[access.qualifier.length - 1] ?? NO_GROUP,
|
|
4407
|
+
container: access.table
|
|
4408
|
+
}),
|
|
4409
|
+
callee: operation,
|
|
4410
|
+
interaction: {
|
|
4411
|
+
class: "storage-access",
|
|
4412
|
+
kind: access.kind,
|
|
4413
|
+
fields: access.fields,
|
|
4414
|
+
...access.selector.length > 0 ? { selector: access.selector } : {},
|
|
4415
|
+
operation
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
];
|
|
4119
4419
|
}
|
|
4120
|
-
|
|
4420
|
+
var NO_GROUP = "default";
|
|
4421
|
+
function importedFunctionMatch(call, options) {
|
|
4121
4422
|
const callee = field(call, "function");
|
|
4122
4423
|
if (callee === null || callee.type !== "identifier") {
|
|
4123
|
-
return
|
|
4424
|
+
return null;
|
|
4124
4425
|
}
|
|
4125
4426
|
const from = options.facts.facts("pyImportedName").find((row) => String(row[0]) === `${options.filePath}#${callee.text}`);
|
|
4126
4427
|
if (from === void 0) {
|
|
4127
|
-
return
|
|
4428
|
+
return null;
|
|
4128
4429
|
}
|
|
4129
4430
|
const module = String(from[1]);
|
|
4130
|
-
|
|
4131
|
-
(
|
|
4431
|
+
const pattern = options.patterns.find(
|
|
4432
|
+
(candidate) => candidate.module === module && candidate.functions.includes(callee.text)
|
|
4132
4433
|
);
|
|
4133
|
-
|
|
4134
|
-
|
|
4434
|
+
if (pattern === void 0) {
|
|
4435
|
+
return null;
|
|
4436
|
+
}
|
|
4135
4437
|
const args = field(call, "arguments");
|
|
4136
4438
|
const first = args?.namedChildren.find((child) => child !== null) ?? null;
|
|
4137
|
-
|
|
4439
|
+
const statement = first === null ? null : statementAt(first, void 0, options.facts);
|
|
4440
|
+
if (statement === null) {
|
|
4441
|
+
return null;
|
|
4442
|
+
}
|
|
4443
|
+
return {
|
|
4444
|
+
call,
|
|
4445
|
+
recognition: `python-${pattern.module}`,
|
|
4446
|
+
storageSystem: pattern.storageSystem,
|
|
4447
|
+
accesses: readSqlAccess(statement, { dialect: pattern.storageSystem })
|
|
4448
|
+
};
|
|
4449
|
+
}
|
|
4450
|
+
function clientMatch(call, options) {
|
|
4451
|
+
const callee = field(call, "function");
|
|
4452
|
+
if (callee === null || callee.type !== "attribute") {
|
|
4138
4453
|
return null;
|
|
4139
4454
|
}
|
|
4140
|
-
const
|
|
4455
|
+
const method = field(callee, "attribute")?.text ?? "";
|
|
4456
|
+
const receiver = field(callee, "object");
|
|
4457
|
+
if (receiver === null) {
|
|
4458
|
+
return null;
|
|
4459
|
+
}
|
|
4460
|
+
for (const pattern of options.clients ?? []) {
|
|
4461
|
+
const accesses = accessesOf(call, method, pattern, options);
|
|
4462
|
+
if (accesses === null || !isClientOf(receiver, pattern, options)) {
|
|
4463
|
+
continue;
|
|
4464
|
+
}
|
|
4465
|
+
return {
|
|
4466
|
+
call,
|
|
4467
|
+
recognition: `python-${pattern.module}`,
|
|
4468
|
+
storageSystem: pattern.storageSystem,
|
|
4469
|
+
accesses
|
|
4470
|
+
};
|
|
4471
|
+
}
|
|
4472
|
+
return null;
|
|
4473
|
+
}
|
|
4474
|
+
function accessesOf(call, method, pattern, options) {
|
|
4475
|
+
const dialect = pattern.dialect ?? pattern.storageSystem;
|
|
4476
|
+
for (const takes of pattern.statements ?? []) {
|
|
4477
|
+
if (takes.method !== method) {
|
|
4478
|
+
continue;
|
|
4479
|
+
}
|
|
4480
|
+
const written = argumentNode(call, takes);
|
|
4481
|
+
const statement = written === null ? null : statementAt(written, takes.path, options.facts);
|
|
4482
|
+
return statement === null ? [] : readSqlAccess(statement, { dialect });
|
|
4483
|
+
}
|
|
4484
|
+
for (const takes of pattern.tables ?? []) {
|
|
4485
|
+
if (takes.method !== method) {
|
|
4486
|
+
continue;
|
|
4487
|
+
}
|
|
4488
|
+
const written = argumentNode(call, takes);
|
|
4489
|
+
const name = written === null ? null : stringValueOf(written, options.facts);
|
|
4490
|
+
const split = name === null ? null : splitQualifiedTable(name);
|
|
4491
|
+
return split === null ? [] : [{ ...split, kind: takes.kind, fields: [], selector: [] }];
|
|
4492
|
+
}
|
|
4493
|
+
return null;
|
|
4494
|
+
}
|
|
4495
|
+
function isClientOf(receiver, pattern, options) {
|
|
4496
|
+
return receiverOrigins(receiver, options).some(
|
|
4497
|
+
(origin) => origin.module === pattern.module && pattern.clientTypes.includes(origin.name)
|
|
4498
|
+
);
|
|
4499
|
+
}
|
|
4500
|
+
function receiverOrigins(receiver, options) {
|
|
4501
|
+
if (receiver.type === "identifier") {
|
|
4502
|
+
return receiverTypeOrigins(receiver, options);
|
|
4503
|
+
}
|
|
4504
|
+
return receiver.type === "call" ? handedBack(receiver, options) : [];
|
|
4505
|
+
}
|
|
4506
|
+
function handedBack(call, options) {
|
|
4507
|
+
const callee = field(call, "function");
|
|
4508
|
+
if (callee === null || callee.type !== "attribute") {
|
|
4509
|
+
return [];
|
|
4510
|
+
}
|
|
4511
|
+
const method = field(callee, "attribute")?.text ?? "";
|
|
4512
|
+
const inner = field(callee, "object");
|
|
4513
|
+
if (inner === null) {
|
|
4514
|
+
return [];
|
|
4515
|
+
}
|
|
4516
|
+
const found = [];
|
|
4517
|
+
for (const pattern of options.clients ?? []) {
|
|
4518
|
+
const handoff = (pattern.handsBack ?? []).find(
|
|
4519
|
+
(one) => one.method === method
|
|
4520
|
+
);
|
|
4521
|
+
if (handoff !== void 0 && isClientOf(inner, pattern, options)) {
|
|
4522
|
+
found.push({ module: handoff.module, name: handoff.name });
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
return found;
|
|
4526
|
+
}
|
|
4527
|
+
function argumentNode(call, at) {
|
|
4528
|
+
const args = field(call, "arguments");
|
|
4529
|
+
const written = args === null ? [] : children(args);
|
|
4530
|
+
const named = written.find(
|
|
4531
|
+
(one) => one.type === "keyword_argument" && at.keyword !== void 0 && field(one, "name")?.text === at.keyword
|
|
4532
|
+
);
|
|
4533
|
+
const value = named === void 0 ? null : field(named, "value");
|
|
4534
|
+
if (value !== null) {
|
|
4535
|
+
return value;
|
|
4536
|
+
}
|
|
4537
|
+
if (at.argument === void 0) {
|
|
4538
|
+
return null;
|
|
4539
|
+
}
|
|
4540
|
+
return written.filter((one) => one.type !== "keyword_argument")[at.argument] ?? null;
|
|
4541
|
+
}
|
|
4542
|
+
function statementAt(node, path6, facts) {
|
|
4543
|
+
const reached = valueAt(evaluatedValue(node, facts), path6 ?? []);
|
|
4544
|
+
const parts = reached === null ? null : literalParts(reached);
|
|
4141
4545
|
if (parts === null) {
|
|
4142
4546
|
return null;
|
|
4143
4547
|
}
|
|
4144
4548
|
const statement = sqlFromParts(parts);
|
|
4145
4549
|
return statement.trim() === "" ? null : statement;
|
|
4146
4550
|
}
|
|
4551
|
+
function valueAt(value, path6) {
|
|
4552
|
+
let reached = value;
|
|
4553
|
+
for (const key of path6) {
|
|
4554
|
+
if (reached.kind !== "record") {
|
|
4555
|
+
return null;
|
|
4556
|
+
}
|
|
4557
|
+
const item = reached.fields.get(key);
|
|
4558
|
+
if (item === void 0) {
|
|
4559
|
+
return null;
|
|
4560
|
+
}
|
|
4561
|
+
reached = force2(item.value);
|
|
4562
|
+
}
|
|
4563
|
+
return reached;
|
|
4564
|
+
}
|
|
4147
4565
|
function literalParts(value) {
|
|
4148
4566
|
if (value.kind !== "string") {
|
|
4149
4567
|
return null;
|
|
@@ -4241,78 +4659,7 @@ function receiverName(chain) {
|
|
|
4241
4659
|
return null;
|
|
4242
4660
|
}
|
|
4243
4661
|
const object = field(callee, "object");
|
|
4244
|
-
return object !== null && object.type === "identifier" ? object
|
|
4245
|
-
}
|
|
4246
|
-
function typeNameOf(annotation) {
|
|
4247
|
-
if (annotation.type === "type" && annotation.namedChildren[0]) {
|
|
4248
|
-
return typeNameOf(annotation.namedChildren[0]);
|
|
4249
|
-
}
|
|
4250
|
-
if (annotation.type === "identifier") {
|
|
4251
|
-
return annotation.text;
|
|
4252
|
-
}
|
|
4253
|
-
const quoted = stringLiteralValue(annotation);
|
|
4254
|
-
if (quoted !== null) {
|
|
4255
|
-
return quoted;
|
|
4256
|
-
}
|
|
4257
|
-
if (annotation.type === "binary_operator") {
|
|
4258
|
-
const named = [field(annotation, "left"), field(annotation, "right")].find(
|
|
4259
|
-
(side) => side !== null && side.type !== "none"
|
|
4260
|
-
);
|
|
4261
|
-
return named === void 0 || named === null ? null : typeNameOf(named);
|
|
4262
|
-
}
|
|
4263
|
-
if (annotation.type === "generic_type") {
|
|
4264
|
-
const outer = annotation.namedChildren[0];
|
|
4265
|
-
const first = genericTypeArgs(annotation)[0];
|
|
4266
|
-
if ((outer?.text === "Annotated" || outer?.text === "Optional") && first !== void 0) {
|
|
4267
|
-
return typeNameOf(first);
|
|
4268
|
-
}
|
|
4269
|
-
return outer?.type === "identifier" ? outer.text : null;
|
|
4270
|
-
}
|
|
4271
|
-
return null;
|
|
4272
|
-
}
|
|
4273
|
-
function statedTypeName(name, from) {
|
|
4274
|
-
const fn = enclosingFunction(from);
|
|
4275
|
-
if (fn === null) {
|
|
4276
|
-
return null;
|
|
4277
|
-
}
|
|
4278
|
-
const params = field(fn, "parameters");
|
|
4279
|
-
for (const param of params === null ? [] : children(params)) {
|
|
4280
|
-
const info = parameterNameAndType(param);
|
|
4281
|
-
if (info?.name === name && info.typeNode !== null) {
|
|
4282
|
-
return typeNameOf(info.typeNode);
|
|
4283
|
-
}
|
|
4284
|
-
}
|
|
4285
|
-
const body = field(fn, "body");
|
|
4286
|
-
return body === null ? null : firstInBody(body, (statement) => statedBy(statement, name));
|
|
4287
|
-
}
|
|
4288
|
-
function firstInBody(node, read) {
|
|
4289
|
-
const here = read(node);
|
|
4290
|
-
if (here !== null) {
|
|
4291
|
-
return here;
|
|
4292
|
-
}
|
|
4293
|
-
for (const child of children(node)) {
|
|
4294
|
-
if (child.type === "function_definition" || child.type === "lambda") {
|
|
4295
|
-
continue;
|
|
4296
|
-
}
|
|
4297
|
-
const found = firstInBody(child, read);
|
|
4298
|
-
if (found !== null) {
|
|
4299
|
-
return found;
|
|
4300
|
-
}
|
|
4301
|
-
}
|
|
4302
|
-
return null;
|
|
4303
|
-
}
|
|
4304
|
-
function statedBy(statement, name) {
|
|
4305
|
-
if (statement.type === "assignment") {
|
|
4306
|
-
const annotation = field(statement, "type");
|
|
4307
|
-
return field(statement, "left")?.text === name && annotation !== null ? typeNameOf(annotation) : null;
|
|
4308
|
-
}
|
|
4309
|
-
if (statement.type === "as_pattern") {
|
|
4310
|
-
const alias = field(statement, "alias");
|
|
4311
|
-
const value = statement.namedChildren[0] ?? null;
|
|
4312
|
-
const callee = value?.type === "call" ? field(value, "function") : null;
|
|
4313
|
-
return alias?.text === name && callee?.type === "identifier" ? callee.text : null;
|
|
4314
|
-
}
|
|
4315
|
-
return null;
|
|
4662
|
+
return object !== null && object.type === "identifier" ? object : null;
|
|
4316
4663
|
}
|
|
4317
4664
|
function builtType(call, options) {
|
|
4318
4665
|
const root = rootOf(call);
|
|
@@ -4360,7 +4707,7 @@ function typedReceiverPattern(options, chain) {
|
|
|
4360
4707
|
if (receiver === null) {
|
|
4361
4708
|
return void 0;
|
|
4362
4709
|
}
|
|
4363
|
-
for (const origin of receiverTypeOrigins(
|
|
4710
|
+
for (const origin of receiverTypeOrigins(receiver, options)) {
|
|
4364
4711
|
const pattern = queryTypePattern(options, origin.module, origin.name);
|
|
4365
4712
|
if (pattern !== void 0) {
|
|
4366
4713
|
return pattern;
|
|
@@ -4368,14 +4715,6 @@ function typedReceiverPattern(options, chain) {
|
|
|
4368
4715
|
}
|
|
4369
4716
|
return void 0;
|
|
4370
4717
|
}
|
|
4371
|
-
function receiverTypeOrigins(options, name, from) {
|
|
4372
|
-
const stated = statedTypeName(name, from);
|
|
4373
|
-
if (stated !== null) {
|
|
4374
|
-
return originsOf(options.facts, `${options.filePath}#${stated}`);
|
|
4375
|
-
}
|
|
4376
|
-
const key = nameKeyIn(options.filePath, enclosingFunction(from), name);
|
|
4377
|
-
return subjectConstructions(options.facts, [key]).get(key)?.origins ?? [];
|
|
4378
|
-
}
|
|
4379
4718
|
function queryTypePattern(options, module, name) {
|
|
4380
4719
|
return options.patterns.find(
|
|
4381
4720
|
(pattern) => module === pattern.module && pattern.queryTypes.includes(name)
|
|
@@ -4497,7 +4836,7 @@ function classBehind(typeName, options) {
|
|
|
4497
4836
|
function isClassName(name) {
|
|
4498
4837
|
return /^[A-Z][A-Za-z0-9_]*$/.test(name) && name !== name.toUpperCase();
|
|
4499
4838
|
}
|
|
4500
|
-
function
|
|
4839
|
+
function effectFor2(pattern, chain, operation, options) {
|
|
4501
4840
|
const valueMethods = pattern.valueMethods ?? [];
|
|
4502
4841
|
const picked = selectorOf(chain, valueMethods);
|
|
4503
4842
|
return {
|
|
@@ -4607,7 +4946,7 @@ function storageCallIds(calls, options) {
|
|
|
4607
4946
|
}
|
|
4608
4947
|
function storageEffects(calls, options) {
|
|
4609
4948
|
return matchedChains(calls, options).flatMap(
|
|
4610
|
-
({ chain, pattern, operation }) => operation === null ? [] : [
|
|
4949
|
+
({ chain, pattern, operation }) => operation === null ? [] : [effectFor2(pattern, chain, operation, options)]
|
|
4611
4950
|
);
|
|
4612
4951
|
}
|
|
4613
4952
|
|
|
@@ -4642,8 +4981,10 @@ function decoratedStatements(root, module, facts) {
|
|
|
4642
4981
|
}));
|
|
4643
4982
|
}
|
|
4644
4983
|
function discoverUnits(root, module, options) {
|
|
4984
|
+
const decorated = decoratedStatements(root, module, options.facts);
|
|
4985
|
+
askWrittenValues(clientCallReceivers(root, module), options.facts);
|
|
4645
4986
|
return [
|
|
4646
|
-
...
|
|
4987
|
+
...decorated.flatMap(
|
|
4647
4988
|
(decoratedStatement) => decoratedUnits(decoratedStatement, module, options)
|
|
4648
4989
|
),
|
|
4649
4990
|
...clientUnits(root, module, options)
|
|
@@ -5429,22 +5770,29 @@ function recognizedBodyEffects(definitionNode, module, storageLookup, facts) {
|
|
|
5429
5770
|
...storageLookup,
|
|
5430
5771
|
filePath: storageLookup.factsPath
|
|
5431
5772
|
}),
|
|
5432
|
-
...rawSqlEffects(bodyCalls(definitionNode),
|
|
5433
|
-
facts: storageLookup.facts,
|
|
5434
|
-
filePath: storageLookup.factsPath,
|
|
5435
|
-
patterns: storageLookup.rawSql ?? []
|
|
5436
|
-
})
|
|
5773
|
+
...rawSqlEffects(bodyCalls(definitionNode), rawSqlOf(storageLookup))
|
|
5437
5774
|
];
|
|
5438
5775
|
return [...envReadEffects(definitionNode, module, facts), ...storage];
|
|
5439
5776
|
}
|
|
5440
|
-
function
|
|
5777
|
+
function rawSqlOf(storageLookup) {
|
|
5778
|
+
return {
|
|
5779
|
+
facts: storageLookup.facts,
|
|
5780
|
+
filePath: storageLookup.factsPath,
|
|
5781
|
+
patterns: storageLookup.rawSql ?? [],
|
|
5782
|
+
clients: storageLookup.sqlClients ?? []
|
|
5783
|
+
};
|
|
5784
|
+
}
|
|
5785
|
+
function recognizedCallIds(calls, storageLookup) {
|
|
5441
5786
|
if (storageLookup === void 0) {
|
|
5442
5787
|
return /* @__PURE__ */ new Set();
|
|
5443
5788
|
}
|
|
5444
|
-
return
|
|
5445
|
-
...
|
|
5446
|
-
|
|
5447
|
-
|
|
5789
|
+
return /* @__PURE__ */ new Set([
|
|
5790
|
+
...storageCallIds(calls, {
|
|
5791
|
+
...storageLookup,
|
|
5792
|
+
filePath: storageLookup.factsPath
|
|
5793
|
+
}),
|
|
5794
|
+
...rawSqlCallIds(calls, rawSqlOf(storageLookup))
|
|
5795
|
+
]);
|
|
5448
5796
|
}
|
|
5449
5797
|
function bodyContentOf(bodyNode) {
|
|
5450
5798
|
for (const stmt of bodyStatements(bodyNode)) {
|
|
@@ -5784,6 +6132,7 @@ import {
|
|
|
5784
6132
|
composeWrappers,
|
|
5785
6133
|
createCacheLayer,
|
|
5786
6134
|
createTimer,
|
|
6135
|
+
effectToIR,
|
|
5787
6136
|
moduleInitStructure,
|
|
5788
6137
|
noopTimer,
|
|
5789
6138
|
runDigest,
|
|
@@ -5916,11 +6265,14 @@ function resolveCallee2(call, site, ctx, read) {
|
|
|
5916
6265
|
const outcome = read?.outcomes.get(spelling.key) ?? calleeOutcomeOf(ctx.facts, spelling.key);
|
|
5917
6266
|
return asCallee(outcome, site.owner, ctx);
|
|
5918
6267
|
}
|
|
5919
|
-
function
|
|
6268
|
+
function namedOutcomes(keys, ctx) {
|
|
6269
|
+
return calleeOutcomes(ctx.facts, [...new Set(keys)]);
|
|
6270
|
+
}
|
|
6271
|
+
function functionNamed(nameKey2, ctx, read) {
|
|
5920
6272
|
if (assignedElsewhere(ctx.facts, nameKey2)) {
|
|
5921
6273
|
return null;
|
|
5922
6274
|
}
|
|
5923
|
-
const outcome = calleeOutcomeOf(ctx.facts, nameKey2);
|
|
6275
|
+
const outcome = read?.get(nameKey2) ?? calleeOutcomeOf(ctx.facts, nameKey2);
|
|
5924
6276
|
return outcome.kind === "function" ? functionAt(outcome.key, ctx) : null;
|
|
5925
6277
|
}
|
|
5926
6278
|
function assignedElsewhere(facts, nameKey2) {
|
|
@@ -6128,6 +6480,7 @@ function reachedFunctions(seeds, options) {
|
|
|
6128
6480
|
const stopsByKey = /* @__PURE__ */ new Map();
|
|
6129
6481
|
const argTargetsByKey = /* @__PURE__ */ new Map();
|
|
6130
6482
|
const parameterCallsByKey = /* @__PURE__ */ new Map();
|
|
6483
|
+
const callsByKey = /* @__PURE__ */ new Map();
|
|
6131
6484
|
const passedPositions = /* @__PURE__ */ new Set();
|
|
6132
6485
|
for (const seed of seeds) {
|
|
6133
6486
|
seedKeys.add(seed.key);
|
|
@@ -6154,12 +6507,21 @@ function reachedFunctions(seeds, options) {
|
|
|
6154
6507
|
bodies.flatMap((body) => body.written),
|
|
6155
6508
|
ctx
|
|
6156
6509
|
);
|
|
6510
|
+
const passed = namedOutcomes(
|
|
6511
|
+
bodies.flatMap(
|
|
6512
|
+
({ source, written }) => written.flatMap(({ call }) => passedNameKeys(source.file, call))
|
|
6513
|
+
),
|
|
6514
|
+
ctx
|
|
6515
|
+
);
|
|
6157
6516
|
for (const { key, source, body, written } of bodies) {
|
|
6158
6517
|
const scan = scanBody(
|
|
6159
6518
|
source,
|
|
6160
6519
|
ctx,
|
|
6161
|
-
recognizedCallIds(
|
|
6162
|
-
|
|
6520
|
+
recognizedCallIds(
|
|
6521
|
+
written.map(({ call }) => call),
|
|
6522
|
+
options.storageFor(source.file)
|
|
6523
|
+
),
|
|
6524
|
+
{ body, written, spellings, passed }
|
|
6163
6525
|
);
|
|
6164
6526
|
if (scan.stops.length > 0) {
|
|
6165
6527
|
stopsByKey.set(key, scan.stops);
|
|
@@ -6172,21 +6534,27 @@ function reachedFunctions(seeds, options) {
|
|
|
6172
6534
|
for (const position of scan.passedPositions) {
|
|
6173
6535
|
passedPositions.add(position);
|
|
6174
6536
|
}
|
|
6537
|
+
const called = [];
|
|
6175
6538
|
for (const target of scan.followed) {
|
|
6176
|
-
const calleeKey =
|
|
6539
|
+
const calleeKey = keyOf2(target);
|
|
6177
6540
|
if (!functionByKey.has(calleeKey)) {
|
|
6178
6541
|
functionByKey.set(calleeKey, target);
|
|
6179
6542
|
}
|
|
6180
6543
|
db.add("calls", [key, calleeKey]);
|
|
6544
|
+
called.push(calleeKey);
|
|
6545
|
+
}
|
|
6546
|
+
if (called.length > 0) {
|
|
6547
|
+
callsByKey.set(key, called);
|
|
6181
6548
|
}
|
|
6182
6549
|
}
|
|
6183
6550
|
}
|
|
6551
|
+
const reached = db.facts("reachable").map(([keyAtom]) => String(keyAtom)).filter((key) => !seedKeys.has(key));
|
|
6552
|
+
settleBodyValues(reached, functionByKey, options.facts);
|
|
6184
6553
|
const summaries = [];
|
|
6185
6554
|
const summariesByKey = /* @__PURE__ */ new Map();
|
|
6186
|
-
for (const
|
|
6187
|
-
const key = String(keyAtom);
|
|
6555
|
+
for (const key of reached) {
|
|
6188
6556
|
const target = functionByKey.get(key);
|
|
6189
|
-
if (
|
|
6557
|
+
if (target === void 0) {
|
|
6190
6558
|
continue;
|
|
6191
6559
|
}
|
|
6192
6560
|
const summary = assembleSummary(libraryUnit(target, options), {
|
|
@@ -6211,10 +6579,11 @@ function reachedFunctions(seeds, options) {
|
|
|
6211
6579
|
stopsByKey,
|
|
6212
6580
|
argTargetsByKey,
|
|
6213
6581
|
parameterCallsByKey,
|
|
6582
|
+
callsByKey,
|
|
6214
6583
|
passedPositions
|
|
6215
6584
|
};
|
|
6216
6585
|
}
|
|
6217
|
-
function
|
|
6586
|
+
function keyOf2(target) {
|
|
6218
6587
|
return nodeId(target.file.file, target.node);
|
|
6219
6588
|
}
|
|
6220
6589
|
var EMPTY_SCAN = {
|
|
@@ -6227,15 +6596,53 @@ var EMPTY_SCAN = {
|
|
|
6227
6596
|
};
|
|
6228
6597
|
function bodyOf(source) {
|
|
6229
6598
|
const { file, node } = source;
|
|
6230
|
-
const body = field(node, "body");
|
|
6599
|
+
const body = isModule(node) ? node : field(node, "body");
|
|
6231
6600
|
if (body === null) {
|
|
6232
6601
|
return { body, written: [] };
|
|
6233
6602
|
}
|
|
6234
6603
|
return {
|
|
6235
6604
|
body,
|
|
6236
|
-
written: callsWritten(file, body, scopeAt2(file, node),
|
|
6605
|
+
written: callsWritten(file, body, scopeAt2(file, node), keyOf2(source), {
|
|
6606
|
+
descendsInto: isModule(node) ? runsAtModuleLoad : outsideNestedDef
|
|
6607
|
+
})
|
|
6237
6608
|
};
|
|
6238
6609
|
}
|
|
6610
|
+
function outsideNestedDef(node) {
|
|
6611
|
+
return node.type !== "function_definition";
|
|
6612
|
+
}
|
|
6613
|
+
function settleBodyValues(reached, functionByKey, facts) {
|
|
6614
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
6615
|
+
for (const key of reached) {
|
|
6616
|
+
const target = functionByKey.get(key);
|
|
6617
|
+
if (target === void 0) {
|
|
6618
|
+
continue;
|
|
6619
|
+
}
|
|
6620
|
+
const listed = byFile.get(target.file.file) ?? [];
|
|
6621
|
+
for (const node of bodyValueNodes(target.node)) {
|
|
6622
|
+
listed.push(node);
|
|
6623
|
+
}
|
|
6624
|
+
byFile.set(target.file.file, listed);
|
|
6625
|
+
}
|
|
6626
|
+
for (const nodes of byFile.values()) {
|
|
6627
|
+
askWrittenValues(nodes, facts);
|
|
6628
|
+
}
|
|
6629
|
+
}
|
|
6630
|
+
function passedNameKeyOf(file, arg) {
|
|
6631
|
+
if (arg === null || arg.type !== "identifier") {
|
|
6632
|
+
return null;
|
|
6633
|
+
}
|
|
6634
|
+
return readKey(file.file, arg, enclosingFunction(arg));
|
|
6635
|
+
}
|
|
6636
|
+
function passedNameKeys(file, call) {
|
|
6637
|
+
const args = field(call, "arguments");
|
|
6638
|
+
if (args === null) {
|
|
6639
|
+
return [];
|
|
6640
|
+
}
|
|
6641
|
+
return args.namedChildren.flatMap((arg) => {
|
|
6642
|
+
const key = passedNameKeyOf(file, arg);
|
|
6643
|
+
return key === null ? [] : [key];
|
|
6644
|
+
});
|
|
6645
|
+
}
|
|
6239
6646
|
function scanBody(source, ctx, recognized, read) {
|
|
6240
6647
|
const followed = [];
|
|
6241
6648
|
const stops = [];
|
|
@@ -6256,17 +6663,15 @@ function scanBody(source, ctx, recognized, read) {
|
|
|
6256
6663
|
return;
|
|
6257
6664
|
}
|
|
6258
6665
|
args.namedChildren.forEach((arg, position) => {
|
|
6259
|
-
|
|
6666
|
+
const nameKey2 = passedNameKeyOf(file, arg);
|
|
6667
|
+
if (nameKey2 === null) {
|
|
6260
6668
|
return;
|
|
6261
6669
|
}
|
|
6262
|
-
const resolved = functionNamed(
|
|
6263
|
-
readKey(file.file, arg, enclosingFunction(arg)),
|
|
6264
|
-
ctx
|
|
6265
|
-
);
|
|
6670
|
+
const resolved = functionNamed(nameKey2, ctx, read.passed);
|
|
6266
6671
|
if (resolved === null) {
|
|
6267
6672
|
return;
|
|
6268
6673
|
}
|
|
6269
|
-
const key =
|
|
6674
|
+
const key = keyOf2(resolved);
|
|
6270
6675
|
if (!seen.has(key)) {
|
|
6271
6676
|
seen.add(key);
|
|
6272
6677
|
followed.push(resolved);
|
|
@@ -6291,7 +6696,7 @@ function scanBody(source, ctx, recognized, read) {
|
|
|
6291
6696
|
recordPassedArgs(
|
|
6292
6697
|
call,
|
|
6293
6698
|
callee,
|
|
6294
|
-
outcome.kind === "followed" ?
|
|
6699
|
+
outcome.kind === "followed" ? keyOf2(outcome.target) : null
|
|
6295
6700
|
);
|
|
6296
6701
|
if (outcome.kind === "stopped") {
|
|
6297
6702
|
const stopKey = `${outcome.reason}:${callee}`;
|
|
@@ -6308,7 +6713,7 @@ function scanBody(source, ctx, recognized, read) {
|
|
|
6308
6713
|
}
|
|
6309
6714
|
return;
|
|
6310
6715
|
}
|
|
6311
|
-
const key =
|
|
6716
|
+
const key = keyOf2(outcome.target);
|
|
6312
6717
|
if (!seen.has(key)) {
|
|
6313
6718
|
seen.add(key);
|
|
6314
6719
|
followed.push(outcome.target);
|
|
@@ -6326,7 +6731,7 @@ function scanBody(source, ctx, recognized, read) {
|
|
|
6326
6731
|
passedPositions
|
|
6327
6732
|
};
|
|
6328
6733
|
}
|
|
6329
|
-
function callsWritten(file, body, outer, owner) {
|
|
6734
|
+
function callsWritten(file, body, outer, owner, limit) {
|
|
6330
6735
|
const found = [];
|
|
6331
6736
|
walkDescendants3(body, outer, {
|
|
6332
6737
|
at: (child, scope) => {
|
|
@@ -6334,7 +6739,7 @@ function callsWritten(file, body, outer, owner) {
|
|
|
6334
6739
|
found.push({ call: child, site: { file, scope, owner } });
|
|
6335
6740
|
}
|
|
6336
6741
|
},
|
|
6337
|
-
into: (child, scope) => child
|
|
6742
|
+
into: (child, scope) => limit.descendsInto(child) ? file.module.scopeFor.get(child.id) ?? scope : SKIP_CHILDREN2
|
|
6338
6743
|
});
|
|
6339
6744
|
return found;
|
|
6340
6745
|
}
|
|
@@ -8108,10 +8513,7 @@ function factsForFile(options) {
|
|
|
8108
8513
|
files: [{ file: options.file, root: options.root, module: options.module }],
|
|
8109
8514
|
definitions
|
|
8110
8515
|
});
|
|
8111
|
-
|
|
8112
|
-
db,
|
|
8113
|
-
envNameSites(options.file, options.root, options.module)
|
|
8114
|
-
);
|
|
8516
|
+
bindEnvFacts(db, [envFactsIn(options.file, options.root, options.module)]);
|
|
8115
8517
|
addPackWords(db, packWordsOf(options.packs));
|
|
8116
8518
|
return db;
|
|
8117
8519
|
}
|
|
@@ -8162,6 +8564,7 @@ async function extractPythonProject(options) {
|
|
|
8162
8564
|
);
|
|
8163
8565
|
const storagePatterns = options.packs.flatMap((pack) => pack.storage ?? []);
|
|
8164
8566
|
const rawSqlPatterns = options.packs.flatMap((pack) => pack.rawSql ?? []);
|
|
8567
|
+
const sqlClients = options.packs.flatMap((pack) => pack.sqlClients ?? []);
|
|
8165
8568
|
const modelQueries = options.packs.flatMap((pack) => pack.models ?? []);
|
|
8166
8569
|
const discovers = options.packs.some((pack) => pack.discovery.length > 0);
|
|
8167
8570
|
const buildsReceivers = options.packs.some(
|
|
@@ -8169,10 +8572,15 @@ async function extractPythonProject(options) {
|
|
|
8169
8572
|
(client) => (client.receiverConstructors ?? []).length > 0
|
|
8170
8573
|
)
|
|
8171
8574
|
);
|
|
8172
|
-
const
|
|
8173
|
-
(boundFile) =>
|
|
8575
|
+
const envFacts = bound.map(
|
|
8576
|
+
(boundFile) => envFactsIn(boundFile.file, boundFile.root, boundFile.module)
|
|
8577
|
+
);
|
|
8578
|
+
const readsEnvThroughNames = envFacts.some(
|
|
8579
|
+
(one) => one.sites.length > 0 || one.objects.length > 0
|
|
8174
8580
|
);
|
|
8175
|
-
const needsValues = discovers || mountsRouters || buildsReceivers ||
|
|
8581
|
+
const needsValues = discovers || mountsRouters || buildsReceivers || readsEnvThroughNames || storagePatterns.length > 0 || modelQueries.length > 0 || // A statement written as SQL is a value, and so is the client the
|
|
8582
|
+
// call that hands it over is read off.
|
|
8583
|
+
rawSqlPatterns.length > 0 || sqlClients.length > 0;
|
|
8176
8584
|
const definitions = /* @__PURE__ */ new Map();
|
|
8177
8585
|
timer.time("discover", () => {
|
|
8178
8586
|
for (const { file, root, module: moduleBinding } of bound) {
|
|
@@ -8184,7 +8592,7 @@ async function extractPythonProject(options) {
|
|
|
8184
8592
|
}
|
|
8185
8593
|
if (needsValues) {
|
|
8186
8594
|
bindEvaluator(db, { files: bound, definitions });
|
|
8187
|
-
|
|
8595
|
+
bindEnvFacts(db, envFacts);
|
|
8188
8596
|
}
|
|
8189
8597
|
addPackWords(db, packWordsOf(options.packs));
|
|
8190
8598
|
});
|
|
@@ -8200,13 +8608,14 @@ async function extractPythonProject(options) {
|
|
|
8200
8608
|
...mountsRouters ? { facts: db } : {}
|
|
8201
8609
|
})
|
|
8202
8610
|
);
|
|
8203
|
-
const storageFor = (file) => storagePatterns.length > 0 || rawSqlPatterns.length > 0 ? {
|
|
8611
|
+
const storageFor = (file) => storagePatterns.length > 0 || rawSqlPatterns.length > 0 || sqlClients.length > 0 ? {
|
|
8204
8612
|
facts: db,
|
|
8205
8613
|
factsPath: file.file,
|
|
8206
8614
|
patterns: storagePatterns,
|
|
8207
8615
|
definitionAt: (key) => definitions.get(key),
|
|
8208
8616
|
couldMatch,
|
|
8209
|
-
rawSql: rawSqlPatterns
|
|
8617
|
+
rawSql: rawSqlPatterns,
|
|
8618
|
+
sqlClients
|
|
8210
8619
|
} : void 0;
|
|
8211
8620
|
const wrapperIndex = timer.time(
|
|
8212
8621
|
"discover",
|
|
@@ -8241,6 +8650,7 @@ async function extractPythonProject(options) {
|
|
|
8241
8650
|
}
|
|
8242
8651
|
const seeds = [];
|
|
8243
8652
|
const summariesBySeed = /* @__PURE__ */ new Map();
|
|
8653
|
+
const moduleRoots = [];
|
|
8244
8654
|
for (const boundFile of bound) {
|
|
8245
8655
|
const { file, root, module: moduleBinding } = boundFile;
|
|
8246
8656
|
const displayPath = displayPathOf(file);
|
|
@@ -8275,21 +8685,15 @@ async function extractPythonProject(options) {
|
|
|
8275
8685
|
"discover",
|
|
8276
8686
|
() => envReadEffects(root, moduleBinding, db)
|
|
8277
8687
|
);
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
}),
|
|
8288
|
-
{ gapHandling }
|
|
8289
|
-
)
|
|
8290
|
-
);
|
|
8291
|
-
summary.confidence = { source: "inferred_static", level: "low" };
|
|
8292
|
-
summaries.push(summary);
|
|
8688
|
+
const moduleKey = nodeId(file, root);
|
|
8689
|
+
if (!summariesBySeed.has(moduleKey)) {
|
|
8690
|
+
seeds.push({ key: moduleKey, file: boundFile, node: root });
|
|
8691
|
+
moduleRoots.push({
|
|
8692
|
+
boundFile,
|
|
8693
|
+
displayPath,
|
|
8694
|
+
key: moduleKey,
|
|
8695
|
+
loadTimeReads
|
|
8696
|
+
});
|
|
8293
8697
|
}
|
|
8294
8698
|
}
|
|
8295
8699
|
const reached = timer.time(
|
|
@@ -8303,16 +8707,19 @@ async function extractPythonProject(options) {
|
|
|
8303
8707
|
definitions
|
|
8304
8708
|
})
|
|
8305
8709
|
);
|
|
8710
|
+
const placeWhatItReached = (summary, key) => {
|
|
8711
|
+
if (gapHandling !== "silent") {
|
|
8712
|
+
summary.gaps.push(
|
|
8713
|
+
...(reached.stopsByKey.get(key) ?? []).map(unfollowedCallGap2)
|
|
8714
|
+
);
|
|
8715
|
+
}
|
|
8716
|
+
placeCalls2(summary, reached.targetsByKey.get(key));
|
|
8717
|
+
placeArgTargets2(summary, reached.argTargetsByKey.get(key));
|
|
8718
|
+
placeCalleeParameters2(summary, reached.parameterCallsByKey.get(key));
|
|
8719
|
+
};
|
|
8306
8720
|
for (const [key, owners] of summariesBySeed) {
|
|
8307
8721
|
for (const summary of owners) {
|
|
8308
|
-
|
|
8309
|
-
summary.gaps.push(
|
|
8310
|
-
...(reached.stopsByKey.get(key) ?? []).map(unfollowedCallGap2)
|
|
8311
|
-
);
|
|
8312
|
-
}
|
|
8313
|
-
placeCalls2(summary, reached.targetsByKey.get(key));
|
|
8314
|
-
placeArgTargets2(summary, reached.argTargetsByKey.get(key));
|
|
8315
|
-
placeCalleeParameters2(summary, reached.parameterCallsByKey.get(key));
|
|
8722
|
+
placeWhatItReached(summary, key);
|
|
8316
8723
|
}
|
|
8317
8724
|
}
|
|
8318
8725
|
if (gapHandling !== "silent") {
|
|
@@ -8322,6 +8729,30 @@ async function extractPythonProject(options) {
|
|
|
8322
8729
|
reached.passedPositions
|
|
8323
8730
|
);
|
|
8324
8731
|
}
|
|
8732
|
+
for (const { boundFile, displayPath, key, loadTimeReads } of moduleRoots) {
|
|
8733
|
+
const calledAtLoad = reached.callsByKey.get(key) ?? [];
|
|
8734
|
+
if (loadTimeReads.length === 0 && calledAtLoad.length === 0) {
|
|
8735
|
+
continue;
|
|
8736
|
+
}
|
|
8737
|
+
const summary = timer.time(
|
|
8738
|
+
"summarize",
|
|
8739
|
+
() => assembleSummary2(
|
|
8740
|
+
moduleInitStructure({
|
|
8741
|
+
name: path3.basename(displayPath),
|
|
8742
|
+
file: displayPath,
|
|
8743
|
+
range: rangeOf(boundFile.root),
|
|
8744
|
+
effects: [
|
|
8745
|
+
...loadTimeReads,
|
|
8746
|
+
...moduleLoadInvocationEffects(boundFile.root, db).map(effectToIR)
|
|
8747
|
+
]
|
|
8748
|
+
}),
|
|
8749
|
+
{ gapHandling }
|
|
8750
|
+
)
|
|
8751
|
+
);
|
|
8752
|
+
summary.confidence = { source: "inferred_static", level: "low" };
|
|
8753
|
+
placeWhatItReached(summary, key);
|
|
8754
|
+
summaries.push(summary);
|
|
8755
|
+
}
|
|
8325
8756
|
summaries.push(...reached.summaries);
|
|
8326
8757
|
const resolvedImports = resolvedImportsOf(db, displayPathOf);
|
|
8327
8758
|
stampModuleImports(summaries, (file) => resolvedImports.get(file) ?? []);
|