@suss/adapter-python 0.31.1 → 0.32.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 +1 -0
- package/dist/index.cjs +242 -47
- package/dist/index.js +236 -41
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ npx suss check --dir summaries/
|
|
|
26
26
|
- FastAPI and flask-restx routes, including a decorator a project re-exports through a wrapper module, with `response_model` and `status_code` taken as the declared contract.
|
|
27
27
|
- The path a route is served under, composed through `include_router` prefixes, however many mounts deep, including a mount written inside a function or spread out of a dictionary.
|
|
28
28
|
- SQLAlchemy calls, `requests` / `httpx` / `aiohttp` call sites, what a file reads from the environment, and what a handler calls out to, as facts the checker's rules run over.
|
|
29
|
+
- Environment reads written through a project helper: with `def env(key): return os.environ[key]`, a call to `env("DATABASE_URL")` is a read of `DATABASE_URL`, however many helpers the name is handed through on the way. Not covered: a name built with an f-string (`env(f"{prefix}_URL")`), a name the helper takes off a dict, and a callee that is a value rather than a function the project declares (`env = make_reader()`).
|
|
29
30
|
|
|
30
31
|
How each of those is decided, and where it stops: [how the Python adapter reads a project](./DESIGN.md).
|
|
31
32
|
|
package/dist/index.cjs
CHANGED
|
@@ -784,6 +784,9 @@ var import_resolution = require("@suss/resolution");
|
|
|
784
784
|
function resolveCalls(db, callKeys) {
|
|
785
785
|
(0, import_resolution.askResolution)(db, callKeys);
|
|
786
786
|
}
|
|
787
|
+
function resolveEnvSites(db, siteIds) {
|
|
788
|
+
(0, import_resolution.askResolution)(db, siteIds, "wantedEnvSite");
|
|
789
|
+
}
|
|
787
790
|
function writtenValueUnder(db, key, site) {
|
|
788
791
|
if ((0, import_resolution.askResolutionUnder)(db, [[key, site]]) === "abandoned") {
|
|
789
792
|
return null;
|
|
@@ -992,31 +995,46 @@ function emitCall(emitter, call) {
|
|
|
992
995
|
if (!emitter.insideMethod) {
|
|
993
996
|
add(emitter, "callOutsideMethod", callKey);
|
|
994
997
|
}
|
|
998
|
+
for (const argument of callArguments(call)) {
|
|
999
|
+
if (argument.kind === "keyword") {
|
|
1000
|
+
add(
|
|
1001
|
+
emitter,
|
|
1002
|
+
"callKeywordArg",
|
|
1003
|
+
callKey,
|
|
1004
|
+
argument.name,
|
|
1005
|
+
valueKey(emitter, argument.node)
|
|
1006
|
+
);
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
add(
|
|
1010
|
+
emitter,
|
|
1011
|
+
"callArg",
|
|
1012
|
+
callKey,
|
|
1013
|
+
String(argument.position),
|
|
1014
|
+
valueKey(emitter, argument.node)
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
function callArguments(call) {
|
|
1019
|
+
const args = field(call, "arguments");
|
|
1020
|
+
if (args === null) {
|
|
1021
|
+
return [];
|
|
1022
|
+
}
|
|
1023
|
+
const written = [];
|
|
995
1024
|
let position = 0;
|
|
996
1025
|
for (const argument of children(args)) {
|
|
997
1026
|
if (argument.type === "keyword_argument") {
|
|
998
1027
|
const name = field(argument, "name");
|
|
999
1028
|
const value = field(argument, "value");
|
|
1000
1029
|
if (name !== null && value !== null) {
|
|
1001
|
-
|
|
1002
|
-
emitter,
|
|
1003
|
-
"callKeywordArg",
|
|
1004
|
-
callKey,
|
|
1005
|
-
name.text,
|
|
1006
|
-
valueKey(emitter, value)
|
|
1007
|
-
);
|
|
1030
|
+
written.push({ kind: "keyword", name: name.text, node: value });
|
|
1008
1031
|
}
|
|
1009
1032
|
continue;
|
|
1010
1033
|
}
|
|
1011
|
-
|
|
1012
|
-
emitter,
|
|
1013
|
-
"callArg",
|
|
1014
|
-
callKey,
|
|
1015
|
-
String(position),
|
|
1016
|
-
valueKey(emitter, argument)
|
|
1017
|
-
);
|
|
1034
|
+
written.push({ kind: "positional", position, node: argument });
|
|
1018
1035
|
position += 1;
|
|
1019
1036
|
}
|
|
1037
|
+
return written;
|
|
1020
1038
|
}
|
|
1021
1039
|
function valueKey(emitter, value) {
|
|
1022
1040
|
if (value.type !== "identifier") {
|
|
@@ -2511,6 +2529,10 @@ function writtenNodeOf(node, db) {
|
|
|
2511
2529
|
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
2512
2530
|
return bound?.context.writtenTo(node) ?? null;
|
|
2513
2531
|
}
|
|
2532
|
+
function resolutionKeyOf(node, db) {
|
|
2533
|
+
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
2534
|
+
return bound?.keyOf(node) ?? null;
|
|
2535
|
+
}
|
|
2514
2536
|
var NOTHING_BUILT = { type: "noCall" };
|
|
2515
2537
|
function constructionBehind(node, db) {
|
|
2516
2538
|
if (db === void 0) {
|
|
@@ -2857,7 +2879,7 @@ function passesParametersThrough(def, inner) {
|
|
|
2857
2879
|
// src/discovery.ts
|
|
2858
2880
|
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
2859
2881
|
var import_extractor5 = require("@suss/extractor");
|
|
2860
|
-
var
|
|
2882
|
+
var import_values11 = require("@suss/values");
|
|
2861
2883
|
|
|
2862
2884
|
// src/clientCalls.ts
|
|
2863
2885
|
var import_behavioral_ir2 = require("@suss/behavioral-ir");
|
|
@@ -3575,14 +3597,22 @@ var import_behavioral_ir3 = require("@suss/behavioral-ir");
|
|
|
3575
3597
|
var import_extractor4 = require("@suss/extractor");
|
|
3576
3598
|
var PYTHON_ENV_RECOGNITION = "python-env";
|
|
3577
3599
|
var DEFERRED_BODY_TYPES = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
|
|
3578
|
-
function envReadEffects(root, module2) {
|
|
3579
|
-
const
|
|
3600
|
+
function envReadEffects(root, module2, facts) {
|
|
3601
|
+
const slots = [];
|
|
3602
|
+
const readsHelpers = facts !== void 0 && sitesByDb.has(facts);
|
|
3580
3603
|
const startScope = module2.scopeFor.get(root.id) ?? module2.moduleScope;
|
|
3581
3604
|
(0, import_extractor4.walkDescendants)(root, startScope, {
|
|
3582
3605
|
at: (node, scope) => {
|
|
3583
|
-
const
|
|
3584
|
-
if (
|
|
3585
|
-
|
|
3606
|
+
const syntax = envReadSyntaxAt(node, scope);
|
|
3607
|
+
if (syntax !== null) {
|
|
3608
|
+
const name = stringLiteralValue(syntax.name);
|
|
3609
|
+
if (name !== null) {
|
|
3610
|
+
slots.push({ read: { name, defaulted: syntax.defaulted } });
|
|
3611
|
+
}
|
|
3612
|
+
return;
|
|
3613
|
+
}
|
|
3614
|
+
if (readsHelpers && node.type === "call") {
|
|
3615
|
+
slots.push({ call: node });
|
|
3586
3616
|
}
|
|
3587
3617
|
},
|
|
3588
3618
|
into: (node, scope) => {
|
|
@@ -3592,7 +3622,16 @@ function envReadEffects(root, module2) {
|
|
|
3592
3622
|
return module2.scopeFor.get(node.id) ?? scope;
|
|
3593
3623
|
}
|
|
3594
3624
|
});
|
|
3595
|
-
|
|
3625
|
+
const throughHelpers = helperReadsByCall(
|
|
3626
|
+
slots.flatMap((slot) => "call" in slot ? [slot.call] : []),
|
|
3627
|
+
facts
|
|
3628
|
+
);
|
|
3629
|
+
return slots.flatMap((slot) => {
|
|
3630
|
+
if ("read" in slot) {
|
|
3631
|
+
return [configReadEffect(slot.read)];
|
|
3632
|
+
}
|
|
3633
|
+
return throughHelpers.get(slot.call.id) ?? [];
|
|
3634
|
+
});
|
|
3596
3635
|
}
|
|
3597
3636
|
function configReadEffect(read) {
|
|
3598
3637
|
return {
|
|
@@ -3610,7 +3649,7 @@ function configReadEffect(read) {
|
|
|
3610
3649
|
}
|
|
3611
3650
|
};
|
|
3612
3651
|
}
|
|
3613
|
-
function
|
|
3652
|
+
function envReadSyntaxAt(node, scope) {
|
|
3614
3653
|
if (node.type === "subscript") {
|
|
3615
3654
|
return subscriptRead(node, scope);
|
|
3616
3655
|
}
|
|
@@ -3625,11 +3664,10 @@ function subscriptRead(node, scope) {
|
|
|
3625
3664
|
if (value === null || index === null || !isEnviron(value, scope)) {
|
|
3626
3665
|
return null;
|
|
3627
3666
|
}
|
|
3628
|
-
|
|
3629
|
-
if (name === null || isAssignedTo(node)) {
|
|
3667
|
+
if (isAssignedTo(node)) {
|
|
3630
3668
|
return null;
|
|
3631
3669
|
}
|
|
3632
|
-
return { name, defaulted: isDefaultedAt(node) };
|
|
3670
|
+
return { name: index, defaulted: isDefaultedAt(node) };
|
|
3633
3671
|
}
|
|
3634
3672
|
function isAssignedTo(node) {
|
|
3635
3673
|
const parent = node.parent;
|
|
@@ -3643,22 +3681,20 @@ function isAssignedTo(node) {
|
|
|
3643
3681
|
}
|
|
3644
3682
|
function callRead(node, scope) {
|
|
3645
3683
|
const callee = field(node, "function");
|
|
3646
|
-
|
|
3647
|
-
if (callee === null || args === null || !isEnvGetter(callee, scope)) {
|
|
3684
|
+
if (callee === null || !isEnvGetter(callee, scope)) {
|
|
3648
3685
|
return null;
|
|
3649
3686
|
}
|
|
3650
|
-
const
|
|
3651
|
-
|
|
3687
|
+
const written = callArguments(node);
|
|
3688
|
+
const name = written.find(
|
|
3689
|
+
(argument) => argument.kind === "positional" && argument.position === 0
|
|
3652
3690
|
);
|
|
3653
|
-
|
|
3654
|
-
if (name === null) {
|
|
3691
|
+
if (name === void 0) {
|
|
3655
3692
|
return null;
|
|
3656
3693
|
}
|
|
3657
|
-
const
|
|
3658
|
-
(
|
|
3694
|
+
const hasDefault = written.some(
|
|
3695
|
+
(argument) => argument.kind === "positional" && argument.position === 1 || argument.kind === "keyword" && argument.name === "default"
|
|
3659
3696
|
);
|
|
3660
|
-
|
|
3661
|
-
return { name, defaulted: hasDefault || isDefaultedAt(node) };
|
|
3697
|
+
return { name: name.node, defaulted: hasDefault || isDefaultedAt(node) };
|
|
3662
3698
|
}
|
|
3663
3699
|
function isEnvGetter(callee, scope) {
|
|
3664
3700
|
if (callee.type === "attribute") {
|
|
@@ -3715,9 +3751,153 @@ function isDefaultedAt(node) {
|
|
|
3715
3751
|
}
|
|
3716
3752
|
return false;
|
|
3717
3753
|
}
|
|
3754
|
+
function envNameSites(filePath, root, module2) {
|
|
3755
|
+
const sites = [];
|
|
3756
|
+
(0, import_extractor4.walkDescendants)(root, module2.moduleScope, {
|
|
3757
|
+
at: (node, scope) => {
|
|
3758
|
+
const syntax = envReadSyntaxAt(node, scope);
|
|
3759
|
+
if (syntax === null || stringLiteralValue(syntax.name) !== null) {
|
|
3760
|
+
return;
|
|
3761
|
+
}
|
|
3762
|
+
sites.push({
|
|
3763
|
+
site: nodeId(filePath, node),
|
|
3764
|
+
nameKey: readKey(filePath, syntax.name, enclosingFunction(syntax.name)),
|
|
3765
|
+
defaulted: syntax.defaulted
|
|
3766
|
+
});
|
|
3767
|
+
},
|
|
3768
|
+
into: (node, scope) => module2.scopeFor.get(node.id) ?? scope
|
|
3769
|
+
});
|
|
3770
|
+
return sites;
|
|
3771
|
+
}
|
|
3772
|
+
var sitesByDb = /* @__PURE__ */ new WeakMap();
|
|
3773
|
+
function bindEnvNameSites(db, sites) {
|
|
3774
|
+
if (sites.length === 0) {
|
|
3775
|
+
return;
|
|
3776
|
+
}
|
|
3777
|
+
let index = sitesByDb.get(db);
|
|
3778
|
+
if (index === void 0) {
|
|
3779
|
+
index = { byId: /* @__PURE__ */ new Map(), sitesByParameter: null };
|
|
3780
|
+
sitesByDb.set(db, index);
|
|
3781
|
+
}
|
|
3782
|
+
for (const site of sites) {
|
|
3783
|
+
db.add("readsEnvNamed", [site.site, site.nameKey]);
|
|
3784
|
+
index.byId.set(site.site, site);
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
function sitesEachParameterNames(db, index) {
|
|
3788
|
+
if (index.sitesByParameter !== null) {
|
|
3789
|
+
return index.sitesByParameter;
|
|
3790
|
+
}
|
|
3791
|
+
resolveEnvSites(db, [...index.byId.keys()]);
|
|
3792
|
+
const found = /* @__PURE__ */ new Map();
|
|
3793
|
+
for (const row of db.facts("wantedParamNamesEnv")) {
|
|
3794
|
+
const parameter = String(row[0]);
|
|
3795
|
+
const named = found.get(parameter) ?? [];
|
|
3796
|
+
named.push(String(row[1]));
|
|
3797
|
+
found.set(parameter, named);
|
|
3798
|
+
}
|
|
3799
|
+
index.sitesByParameter = found;
|
|
3800
|
+
return found;
|
|
3801
|
+
}
|
|
3802
|
+
function helperReadsByCall(calls, db) {
|
|
3803
|
+
const found = /* @__PURE__ */ new Map();
|
|
3804
|
+
const index = db === void 0 ? void 0 : sitesByDb.get(db);
|
|
3805
|
+
if (db === void 0 || index === void 0 || calls.length === 0) {
|
|
3806
|
+
return found;
|
|
3807
|
+
}
|
|
3808
|
+
const named = sitesEachParameterNames(db, index);
|
|
3809
|
+
if (named.size === 0) {
|
|
3810
|
+
return found;
|
|
3811
|
+
}
|
|
3812
|
+
const calleeKeys = /* @__PURE__ */ new Map();
|
|
3813
|
+
for (const call of calls) {
|
|
3814
|
+
const callee = field(call, "function");
|
|
3815
|
+
const key = callee === null ? null : resolutionKeyOf(callee, db);
|
|
3816
|
+
if (key !== null) {
|
|
3817
|
+
calleeKeys.set(call.id, key);
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
if (calleeKeys.size === 0) {
|
|
3821
|
+
return found;
|
|
3822
|
+
}
|
|
3823
|
+
resolveCalls(db, [...new Set(calleeKeys.values())]);
|
|
3824
|
+
for (const call of calls) {
|
|
3825
|
+
const key = calleeKeys.get(call.id);
|
|
3826
|
+
if (key === void 0) {
|
|
3827
|
+
continue;
|
|
3828
|
+
}
|
|
3829
|
+
const argumentAt2 = argumentsByParameter(db, call, key);
|
|
3830
|
+
if (argumentAt2.size === 0) {
|
|
3831
|
+
continue;
|
|
3832
|
+
}
|
|
3833
|
+
const reads = readsThroughHelper(db, call, argumentAt2, index.byId, named);
|
|
3834
|
+
if (reads.length > 0) {
|
|
3835
|
+
found.set(call.id, reads);
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
return found;
|
|
3839
|
+
}
|
|
3840
|
+
function argumentsByParameter(db, call, calleeKey) {
|
|
3841
|
+
const written = callArguments(call);
|
|
3842
|
+
if (written.length === 0) {
|
|
3843
|
+
return /* @__PURE__ */ new Map();
|
|
3844
|
+
}
|
|
3845
|
+
const positional = /* @__PURE__ */ new Map();
|
|
3846
|
+
const byName = /* @__PURE__ */ new Map();
|
|
3847
|
+
for (const argument of written) {
|
|
3848
|
+
if (argument.kind === "keyword") {
|
|
3849
|
+
byName.set(argument.name, argument.node);
|
|
3850
|
+
continue;
|
|
3851
|
+
}
|
|
3852
|
+
positional.set(String(argument.position), argument.node);
|
|
3853
|
+
}
|
|
3854
|
+
const argumentAt2 = /* @__PURE__ */ new Map();
|
|
3855
|
+
for (const resolved of db.lookup("wantedResolves", 0, calleeKey)) {
|
|
3856
|
+
const callee = String(resolved[1]);
|
|
3857
|
+
for (const row of db.lookup("paramOf", 0, callee)) {
|
|
3858
|
+
const at = positional.get(String(row[1]));
|
|
3859
|
+
if (at !== void 0) {
|
|
3860
|
+
argumentAt2.set(String(row[2]), at);
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
for (const row of db.lookup("paramNamed", 0, callee)) {
|
|
3864
|
+
const at = byName.get(String(row[1]));
|
|
3865
|
+
if (at !== void 0) {
|
|
3866
|
+
argumentAt2.set(String(row[2]), at);
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
return argumentAt2;
|
|
3871
|
+
}
|
|
3872
|
+
function readsThroughHelper(db, call, argumentAt2, siteById, named) {
|
|
3873
|
+
const reads = /* @__PURE__ */ new Map();
|
|
3874
|
+
for (const [parameter, argument] of argumentAt2) {
|
|
3875
|
+
const sites = named.get(parameter);
|
|
3876
|
+
if (sites === void 0) {
|
|
3877
|
+
continue;
|
|
3878
|
+
}
|
|
3879
|
+
const name = stringLiteralValue(argument) ?? stringValueOf(argument, db);
|
|
3880
|
+
if (name === null) {
|
|
3881
|
+
continue;
|
|
3882
|
+
}
|
|
3883
|
+
for (const id of sites) {
|
|
3884
|
+
const site = siteById.get(id);
|
|
3885
|
+
if (site !== void 0) {
|
|
3886
|
+
reads.set(name, (reads.get(name) ?? true) && site.defaulted);
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
if (reads.size === 0) {
|
|
3891
|
+
return [];
|
|
3892
|
+
}
|
|
3893
|
+
const defaultedAtCall = isDefaultedAt(call);
|
|
3894
|
+
return [...reads].map(
|
|
3895
|
+
([name, defaulted]) => configReadEffect({ name, defaulted: defaulted || defaultedAtCall })
|
|
3896
|
+
);
|
|
3897
|
+
}
|
|
3718
3898
|
|
|
3719
3899
|
// src/paths/raisedResponses.ts
|
|
3720
|
-
var
|
|
3900
|
+
var import_values9 = require("@suss/values");
|
|
3721
3901
|
var NESTED_DEFINITION_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
|
|
3722
3902
|
function raisedResponses(body, options) {
|
|
3723
3903
|
if (body === null || options.calls.length === 0) {
|
|
@@ -3811,7 +3991,7 @@ function statusOf(declared, call, facts) {
|
|
|
3811
3991
|
if (written === null) {
|
|
3812
3992
|
return declared.defaultStatusCode === void 0 ? null : { type: "literal", value: declared.defaultStatusCode };
|
|
3813
3993
|
}
|
|
3814
|
-
const value = (0,
|
|
3994
|
+
const value = (0, import_values9.constantOf)(evaluatedValue(written, facts));
|
|
3815
3995
|
if (typeof value === "number") {
|
|
3816
3996
|
return { type: "literal", value };
|
|
3817
3997
|
}
|
|
@@ -4584,7 +4764,7 @@ function readPathArgument(classification, options) {
|
|
|
4584
4764
|
const first = classification.args[0];
|
|
4585
4765
|
if (first !== void 0) {
|
|
4586
4766
|
const value = evaluatedValue(first.node, options.facts);
|
|
4587
|
-
const path6 = (0,
|
|
4767
|
+
const path6 = (0, import_values11.literalOf)(value) ?? (0, import_values11.pathOf)(value);
|
|
4588
4768
|
if (path6 !== void 0) {
|
|
4589
4769
|
return (0, import_extractor5.writtenReading)(path6, classification.range);
|
|
4590
4770
|
}
|
|
@@ -4831,11 +5011,11 @@ function statusFromReturnedValue(node, facts) {
|
|
|
4831
5011
|
return null;
|
|
4832
5012
|
}
|
|
4833
5013
|
const value = evaluatedValue(node, facts);
|
|
4834
|
-
const number = (0,
|
|
5014
|
+
const number = (0, import_values11.constantOf)(value);
|
|
4835
5015
|
if (typeof number === "number") {
|
|
4836
5016
|
return Number.isInteger(number) ? number : null;
|
|
4837
5017
|
}
|
|
4838
|
-
const text2 = (0,
|
|
5018
|
+
const text2 = (0, import_values11.literalOf)(value);
|
|
4839
5019
|
if (text2 === null) {
|
|
4840
5020
|
return null;
|
|
4841
5021
|
}
|
|
@@ -5178,7 +5358,12 @@ function buildRouteUnit(options) {
|
|
|
5178
5358
|
() => readReturnAnnotation(definitionNode, enclosingScope, ctx)
|
|
5179
5359
|
);
|
|
5180
5360
|
const effects = invocationEffects(definitionNode, options.facts);
|
|
5181
|
-
const extra = recognizedBodyEffects(
|
|
5361
|
+
const extra = recognizedBodyEffects(
|
|
5362
|
+
definitionNode,
|
|
5363
|
+
module2,
|
|
5364
|
+
storageLookup,
|
|
5365
|
+
options.facts
|
|
5366
|
+
);
|
|
5182
5367
|
const perTerminal = branchesPerTerminal({
|
|
5183
5368
|
definitionNode,
|
|
5184
5369
|
effects,
|
|
@@ -5263,7 +5448,7 @@ function unreadRoleReadings(parameters, range) {
|
|
|
5263
5448
|
)
|
|
5264
5449
|
];
|
|
5265
5450
|
}
|
|
5266
|
-
function recognizedBodyEffects(definitionNode, module2, storageLookup) {
|
|
5451
|
+
function recognizedBodyEffects(definitionNode, module2, storageLookup, facts) {
|
|
5267
5452
|
const storage = storageLookup === void 0 ? [] : [
|
|
5268
5453
|
...storageEffects(bodyCalls(definitionNode), {
|
|
5269
5454
|
...storageLookup,
|
|
@@ -5275,7 +5460,7 @@ function recognizedBodyEffects(definitionNode, module2, storageLookup) {
|
|
|
5275
5460
|
patterns: storageLookup.rawSql ?? []
|
|
5276
5461
|
})
|
|
5277
5462
|
];
|
|
5278
|
-
return [...envReadEffects(definitionNode, module2), ...storage];
|
|
5463
|
+
return [...envReadEffects(definitionNode, module2, facts), ...storage];
|
|
5279
5464
|
}
|
|
5280
5465
|
function recognizedCallIds(definitionNode, storageLookup) {
|
|
5281
5466
|
if (storageLookup === void 0) {
|
|
@@ -6168,7 +6353,8 @@ function libraryUnit(target, options) {
|
|
|
6168
6353
|
const extra = recognizedBodyEffects(
|
|
6169
6354
|
node,
|
|
6170
6355
|
file.module,
|
|
6171
|
-
options.storageFor(file)
|
|
6356
|
+
options.storageFor(file),
|
|
6357
|
+
options.facts
|
|
6172
6358
|
);
|
|
6173
6359
|
const range = rangeOf(node);
|
|
6174
6360
|
return {
|
|
@@ -7749,7 +7935,8 @@ function wrapperUnit(target, declared, options) {
|
|
|
7749
7935
|
const extra = recognizedBodyEffects(
|
|
7750
7936
|
node,
|
|
7751
7937
|
file.module,
|
|
7752
|
-
options.storageFor(file)
|
|
7938
|
+
options.storageFor(file),
|
|
7939
|
+
options.facts
|
|
7753
7940
|
);
|
|
7754
7941
|
const delegate = (at) => ({
|
|
7755
7942
|
terminal: {
|
|
@@ -7907,6 +8094,10 @@ function factsForFile(options) {
|
|
|
7907
8094
|
files: [{ file: options.file, root: options.root, module: options.module }],
|
|
7908
8095
|
definitions
|
|
7909
8096
|
});
|
|
8097
|
+
bindEnvNameSites(
|
|
8098
|
+
db,
|
|
8099
|
+
envNameSites(options.file, options.root, options.module)
|
|
8100
|
+
);
|
|
7910
8101
|
(0, import_resolution7.addPackWords)(db, packWordsOf(options.packs));
|
|
7911
8102
|
return db;
|
|
7912
8103
|
}
|
|
@@ -7964,7 +8155,10 @@ async function extractPythonProject(options) {
|
|
|
7964
8155
|
(client) => (client.receiverConstructors ?? []).length > 0
|
|
7965
8156
|
)
|
|
7966
8157
|
);
|
|
7967
|
-
const
|
|
8158
|
+
const envSites = bound.flatMap(
|
|
8159
|
+
(boundFile) => envNameSites(boundFile.file, boundFile.root, boundFile.module)
|
|
8160
|
+
);
|
|
8161
|
+
const needsValues = discovers || mountsRouters || buildsReceivers || envSites.length > 0 || storagePatterns.length > 0 || modelQueries.length > 0;
|
|
7968
8162
|
const definitions = /* @__PURE__ */ new Map();
|
|
7969
8163
|
timer.time("discover", () => {
|
|
7970
8164
|
for (const { file, root, module: moduleBinding } of bound) {
|
|
@@ -7976,6 +8170,7 @@ async function extractPythonProject(options) {
|
|
|
7976
8170
|
}
|
|
7977
8171
|
if (needsValues) {
|
|
7978
8172
|
bindEvaluator(db, { files: bound, definitions });
|
|
8173
|
+
bindEnvNameSites(db, envSites);
|
|
7979
8174
|
}
|
|
7980
8175
|
(0, import_resolution7.addPackWords)(db, packWordsOf(options.packs));
|
|
7981
8176
|
});
|
|
@@ -8064,7 +8259,7 @@ async function extractPythonProject(options) {
|
|
|
8064
8259
|
}
|
|
8065
8260
|
const loadTimeReads = timer.time(
|
|
8066
8261
|
"discover",
|
|
8067
|
-
() => envReadEffects(root, moduleBinding)
|
|
8262
|
+
() => envReadEffects(root, moduleBinding, db)
|
|
8068
8263
|
);
|
|
8069
8264
|
if (loadTimeReads.length > 0) {
|
|
8070
8265
|
const summary = timer.time(
|
package/dist/index.js
CHANGED
|
@@ -724,6 +724,9 @@ import {
|
|
|
724
724
|
function resolveCalls(db, callKeys) {
|
|
725
725
|
askResolution(db, callKeys);
|
|
726
726
|
}
|
|
727
|
+
function resolveEnvSites(db, siteIds) {
|
|
728
|
+
askResolution(db, siteIds, "wantedEnvSite");
|
|
729
|
+
}
|
|
727
730
|
function writtenValueUnder(db, key, site) {
|
|
728
731
|
if (askResolutionUnder(db, [[key, site]]) === "abandoned") {
|
|
729
732
|
return null;
|
|
@@ -936,31 +939,46 @@ function emitCall(emitter, call) {
|
|
|
936
939
|
if (!emitter.insideMethod) {
|
|
937
940
|
add(emitter, "callOutsideMethod", callKey);
|
|
938
941
|
}
|
|
942
|
+
for (const argument of callArguments(call)) {
|
|
943
|
+
if (argument.kind === "keyword") {
|
|
944
|
+
add(
|
|
945
|
+
emitter,
|
|
946
|
+
"callKeywordArg",
|
|
947
|
+
callKey,
|
|
948
|
+
argument.name,
|
|
949
|
+
valueKey(emitter, argument.node)
|
|
950
|
+
);
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
add(
|
|
954
|
+
emitter,
|
|
955
|
+
"callArg",
|
|
956
|
+
callKey,
|
|
957
|
+
String(argument.position),
|
|
958
|
+
valueKey(emitter, argument.node)
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
function callArguments(call) {
|
|
963
|
+
const args = field(call, "arguments");
|
|
964
|
+
if (args === null) {
|
|
965
|
+
return [];
|
|
966
|
+
}
|
|
967
|
+
const written = [];
|
|
939
968
|
let position = 0;
|
|
940
969
|
for (const argument of children(args)) {
|
|
941
970
|
if (argument.type === "keyword_argument") {
|
|
942
971
|
const name = field(argument, "name");
|
|
943
972
|
const value = field(argument, "value");
|
|
944
973
|
if (name !== null && value !== null) {
|
|
945
|
-
|
|
946
|
-
emitter,
|
|
947
|
-
"callKeywordArg",
|
|
948
|
-
callKey,
|
|
949
|
-
name.text,
|
|
950
|
-
valueKey(emitter, value)
|
|
951
|
-
);
|
|
974
|
+
written.push({ kind: "keyword", name: name.text, node: value });
|
|
952
975
|
}
|
|
953
976
|
continue;
|
|
954
977
|
}
|
|
955
|
-
|
|
956
|
-
emitter,
|
|
957
|
-
"callArg",
|
|
958
|
-
callKey,
|
|
959
|
-
String(position),
|
|
960
|
-
valueKey(emitter, argument)
|
|
961
|
-
);
|
|
978
|
+
written.push({ kind: "positional", position, node: argument });
|
|
962
979
|
position += 1;
|
|
963
980
|
}
|
|
981
|
+
return written;
|
|
964
982
|
}
|
|
965
983
|
function valueKey(emitter, value) {
|
|
966
984
|
if (value.type !== "identifier") {
|
|
@@ -2476,6 +2494,10 @@ function writtenNodeOf(node, db) {
|
|
|
2476
2494
|
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
2477
2495
|
return bound?.context.writtenTo(node) ?? null;
|
|
2478
2496
|
}
|
|
2497
|
+
function resolutionKeyOf(node, db) {
|
|
2498
|
+
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
2499
|
+
return bound?.keyOf(node) ?? null;
|
|
2500
|
+
}
|
|
2479
2501
|
var NOTHING_BUILT = { type: "noCall" };
|
|
2480
2502
|
function constructionBehind(node, db) {
|
|
2481
2503
|
if (db === void 0) {
|
|
@@ -3550,14 +3572,22 @@ import { runtimeConfigBinding } from "@suss/behavioral-ir";
|
|
|
3550
3572
|
import { SKIP_CHILDREN, walkDescendants } from "@suss/extractor";
|
|
3551
3573
|
var PYTHON_ENV_RECOGNITION = "python-env";
|
|
3552
3574
|
var DEFERRED_BODY_TYPES = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
|
|
3553
|
-
function envReadEffects(root, module) {
|
|
3554
|
-
const
|
|
3575
|
+
function envReadEffects(root, module, facts) {
|
|
3576
|
+
const slots = [];
|
|
3577
|
+
const readsHelpers = facts !== void 0 && sitesByDb.has(facts);
|
|
3555
3578
|
const startScope = module.scopeFor.get(root.id) ?? module.moduleScope;
|
|
3556
3579
|
walkDescendants(root, startScope, {
|
|
3557
3580
|
at: (node, scope) => {
|
|
3558
|
-
const
|
|
3559
|
-
if (
|
|
3560
|
-
|
|
3581
|
+
const syntax = envReadSyntaxAt(node, scope);
|
|
3582
|
+
if (syntax !== null) {
|
|
3583
|
+
const name = stringLiteralValue(syntax.name);
|
|
3584
|
+
if (name !== null) {
|
|
3585
|
+
slots.push({ read: { name, defaulted: syntax.defaulted } });
|
|
3586
|
+
}
|
|
3587
|
+
return;
|
|
3588
|
+
}
|
|
3589
|
+
if (readsHelpers && node.type === "call") {
|
|
3590
|
+
slots.push({ call: node });
|
|
3561
3591
|
}
|
|
3562
3592
|
},
|
|
3563
3593
|
into: (node, scope) => {
|
|
@@ -3567,7 +3597,16 @@ function envReadEffects(root, module) {
|
|
|
3567
3597
|
return module.scopeFor.get(node.id) ?? scope;
|
|
3568
3598
|
}
|
|
3569
3599
|
});
|
|
3570
|
-
|
|
3600
|
+
const throughHelpers = helperReadsByCall(
|
|
3601
|
+
slots.flatMap((slot) => "call" in slot ? [slot.call] : []),
|
|
3602
|
+
facts
|
|
3603
|
+
);
|
|
3604
|
+
return slots.flatMap((slot) => {
|
|
3605
|
+
if ("read" in slot) {
|
|
3606
|
+
return [configReadEffect(slot.read)];
|
|
3607
|
+
}
|
|
3608
|
+
return throughHelpers.get(slot.call.id) ?? [];
|
|
3609
|
+
});
|
|
3571
3610
|
}
|
|
3572
3611
|
function configReadEffect(read) {
|
|
3573
3612
|
return {
|
|
@@ -3585,7 +3624,7 @@ function configReadEffect(read) {
|
|
|
3585
3624
|
}
|
|
3586
3625
|
};
|
|
3587
3626
|
}
|
|
3588
|
-
function
|
|
3627
|
+
function envReadSyntaxAt(node, scope) {
|
|
3589
3628
|
if (node.type === "subscript") {
|
|
3590
3629
|
return subscriptRead(node, scope);
|
|
3591
3630
|
}
|
|
@@ -3600,11 +3639,10 @@ function subscriptRead(node, scope) {
|
|
|
3600
3639
|
if (value === null || index === null || !isEnviron(value, scope)) {
|
|
3601
3640
|
return null;
|
|
3602
3641
|
}
|
|
3603
|
-
|
|
3604
|
-
if (name === null || isAssignedTo(node)) {
|
|
3642
|
+
if (isAssignedTo(node)) {
|
|
3605
3643
|
return null;
|
|
3606
3644
|
}
|
|
3607
|
-
return { name, defaulted: isDefaultedAt(node) };
|
|
3645
|
+
return { name: index, defaulted: isDefaultedAt(node) };
|
|
3608
3646
|
}
|
|
3609
3647
|
function isAssignedTo(node) {
|
|
3610
3648
|
const parent = node.parent;
|
|
@@ -3618,22 +3656,20 @@ function isAssignedTo(node) {
|
|
|
3618
3656
|
}
|
|
3619
3657
|
function callRead(node, scope) {
|
|
3620
3658
|
const callee = field(node, "function");
|
|
3621
|
-
|
|
3622
|
-
if (callee === null || args === null || !isEnvGetter(callee, scope)) {
|
|
3659
|
+
if (callee === null || !isEnvGetter(callee, scope)) {
|
|
3623
3660
|
return null;
|
|
3624
3661
|
}
|
|
3625
|
-
const
|
|
3626
|
-
|
|
3662
|
+
const written = callArguments(node);
|
|
3663
|
+
const name = written.find(
|
|
3664
|
+
(argument) => argument.kind === "positional" && argument.position === 0
|
|
3627
3665
|
);
|
|
3628
|
-
|
|
3629
|
-
if (name === null) {
|
|
3666
|
+
if (name === void 0) {
|
|
3630
3667
|
return null;
|
|
3631
3668
|
}
|
|
3632
|
-
const
|
|
3633
|
-
(
|
|
3669
|
+
const hasDefault = written.some(
|
|
3670
|
+
(argument) => argument.kind === "positional" && argument.position === 1 || argument.kind === "keyword" && argument.name === "default"
|
|
3634
3671
|
);
|
|
3635
|
-
|
|
3636
|
-
return { name, defaulted: hasDefault || isDefaultedAt(node) };
|
|
3672
|
+
return { name: name.node, defaulted: hasDefault || isDefaultedAt(node) };
|
|
3637
3673
|
}
|
|
3638
3674
|
function isEnvGetter(callee, scope) {
|
|
3639
3675
|
if (callee.type === "attribute") {
|
|
@@ -3690,6 +3726,150 @@ function isDefaultedAt(node) {
|
|
|
3690
3726
|
}
|
|
3691
3727
|
return false;
|
|
3692
3728
|
}
|
|
3729
|
+
function envNameSites(filePath, root, module) {
|
|
3730
|
+
const sites = [];
|
|
3731
|
+
walkDescendants(root, module.moduleScope, {
|
|
3732
|
+
at: (node, scope) => {
|
|
3733
|
+
const syntax = envReadSyntaxAt(node, scope);
|
|
3734
|
+
if (syntax === null || stringLiteralValue(syntax.name) !== null) {
|
|
3735
|
+
return;
|
|
3736
|
+
}
|
|
3737
|
+
sites.push({
|
|
3738
|
+
site: nodeId(filePath, node),
|
|
3739
|
+
nameKey: readKey(filePath, syntax.name, enclosingFunction(syntax.name)),
|
|
3740
|
+
defaulted: syntax.defaulted
|
|
3741
|
+
});
|
|
3742
|
+
},
|
|
3743
|
+
into: (node, scope) => module.scopeFor.get(node.id) ?? scope
|
|
3744
|
+
});
|
|
3745
|
+
return sites;
|
|
3746
|
+
}
|
|
3747
|
+
var sitesByDb = /* @__PURE__ */ new WeakMap();
|
|
3748
|
+
function bindEnvNameSites(db, sites) {
|
|
3749
|
+
if (sites.length === 0) {
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
let index = sitesByDb.get(db);
|
|
3753
|
+
if (index === void 0) {
|
|
3754
|
+
index = { byId: /* @__PURE__ */ new Map(), sitesByParameter: null };
|
|
3755
|
+
sitesByDb.set(db, index);
|
|
3756
|
+
}
|
|
3757
|
+
for (const site of sites) {
|
|
3758
|
+
db.add("readsEnvNamed", [site.site, site.nameKey]);
|
|
3759
|
+
index.byId.set(site.site, site);
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
function sitesEachParameterNames(db, index) {
|
|
3763
|
+
if (index.sitesByParameter !== null) {
|
|
3764
|
+
return index.sitesByParameter;
|
|
3765
|
+
}
|
|
3766
|
+
resolveEnvSites(db, [...index.byId.keys()]);
|
|
3767
|
+
const found = /* @__PURE__ */ new Map();
|
|
3768
|
+
for (const row of db.facts("wantedParamNamesEnv")) {
|
|
3769
|
+
const parameter = String(row[0]);
|
|
3770
|
+
const named = found.get(parameter) ?? [];
|
|
3771
|
+
named.push(String(row[1]));
|
|
3772
|
+
found.set(parameter, named);
|
|
3773
|
+
}
|
|
3774
|
+
index.sitesByParameter = found;
|
|
3775
|
+
return found;
|
|
3776
|
+
}
|
|
3777
|
+
function helperReadsByCall(calls, db) {
|
|
3778
|
+
const found = /* @__PURE__ */ new Map();
|
|
3779
|
+
const index = db === void 0 ? void 0 : sitesByDb.get(db);
|
|
3780
|
+
if (db === void 0 || index === void 0 || calls.length === 0) {
|
|
3781
|
+
return found;
|
|
3782
|
+
}
|
|
3783
|
+
const named = sitesEachParameterNames(db, index);
|
|
3784
|
+
if (named.size === 0) {
|
|
3785
|
+
return found;
|
|
3786
|
+
}
|
|
3787
|
+
const calleeKeys = /* @__PURE__ */ new Map();
|
|
3788
|
+
for (const call of calls) {
|
|
3789
|
+
const callee = field(call, "function");
|
|
3790
|
+
const key = callee === null ? null : resolutionKeyOf(callee, db);
|
|
3791
|
+
if (key !== null) {
|
|
3792
|
+
calleeKeys.set(call.id, key);
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
if (calleeKeys.size === 0) {
|
|
3796
|
+
return found;
|
|
3797
|
+
}
|
|
3798
|
+
resolveCalls(db, [...new Set(calleeKeys.values())]);
|
|
3799
|
+
for (const call of calls) {
|
|
3800
|
+
const key = calleeKeys.get(call.id);
|
|
3801
|
+
if (key === void 0) {
|
|
3802
|
+
continue;
|
|
3803
|
+
}
|
|
3804
|
+
const argumentAt2 = argumentsByParameter(db, call, key);
|
|
3805
|
+
if (argumentAt2.size === 0) {
|
|
3806
|
+
continue;
|
|
3807
|
+
}
|
|
3808
|
+
const reads = readsThroughHelper(db, call, argumentAt2, index.byId, named);
|
|
3809
|
+
if (reads.length > 0) {
|
|
3810
|
+
found.set(call.id, reads);
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
return found;
|
|
3814
|
+
}
|
|
3815
|
+
function argumentsByParameter(db, call, calleeKey) {
|
|
3816
|
+
const written = callArguments(call);
|
|
3817
|
+
if (written.length === 0) {
|
|
3818
|
+
return /* @__PURE__ */ new Map();
|
|
3819
|
+
}
|
|
3820
|
+
const positional = /* @__PURE__ */ new Map();
|
|
3821
|
+
const byName = /* @__PURE__ */ new Map();
|
|
3822
|
+
for (const argument of written) {
|
|
3823
|
+
if (argument.kind === "keyword") {
|
|
3824
|
+
byName.set(argument.name, argument.node);
|
|
3825
|
+
continue;
|
|
3826
|
+
}
|
|
3827
|
+
positional.set(String(argument.position), argument.node);
|
|
3828
|
+
}
|
|
3829
|
+
const argumentAt2 = /* @__PURE__ */ new Map();
|
|
3830
|
+
for (const resolved of db.lookup("wantedResolves", 0, calleeKey)) {
|
|
3831
|
+
const callee = String(resolved[1]);
|
|
3832
|
+
for (const row of db.lookup("paramOf", 0, callee)) {
|
|
3833
|
+
const at = positional.get(String(row[1]));
|
|
3834
|
+
if (at !== void 0) {
|
|
3835
|
+
argumentAt2.set(String(row[2]), at);
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
for (const row of db.lookup("paramNamed", 0, callee)) {
|
|
3839
|
+
const at = byName.get(String(row[1]));
|
|
3840
|
+
if (at !== void 0) {
|
|
3841
|
+
argumentAt2.set(String(row[2]), at);
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
return argumentAt2;
|
|
3846
|
+
}
|
|
3847
|
+
function readsThroughHelper(db, call, argumentAt2, siteById, named) {
|
|
3848
|
+
const reads = /* @__PURE__ */ new Map();
|
|
3849
|
+
for (const [parameter, argument] of argumentAt2) {
|
|
3850
|
+
const sites = named.get(parameter);
|
|
3851
|
+
if (sites === void 0) {
|
|
3852
|
+
continue;
|
|
3853
|
+
}
|
|
3854
|
+
const name = stringLiteralValue(argument) ?? stringValueOf(argument, db);
|
|
3855
|
+
if (name === null) {
|
|
3856
|
+
continue;
|
|
3857
|
+
}
|
|
3858
|
+
for (const id of sites) {
|
|
3859
|
+
const site = siteById.get(id);
|
|
3860
|
+
if (site !== void 0) {
|
|
3861
|
+
reads.set(name, (reads.get(name) ?? true) && site.defaulted);
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
if (reads.size === 0) {
|
|
3866
|
+
return [];
|
|
3867
|
+
}
|
|
3868
|
+
const defaultedAtCall = isDefaultedAt(call);
|
|
3869
|
+
return [...reads].map(
|
|
3870
|
+
([name, defaulted]) => configReadEffect({ name, defaulted: defaulted || defaultedAtCall })
|
|
3871
|
+
);
|
|
3872
|
+
}
|
|
3693
3873
|
|
|
3694
3874
|
// src/paths/raisedResponses.ts
|
|
3695
3875
|
import { constantOf as constantOf3 } from "@suss/values";
|
|
@@ -5153,7 +5333,12 @@ function buildRouteUnit(options) {
|
|
|
5153
5333
|
() => readReturnAnnotation(definitionNode, enclosingScope, ctx)
|
|
5154
5334
|
);
|
|
5155
5335
|
const effects = invocationEffects(definitionNode, options.facts);
|
|
5156
|
-
const extra = recognizedBodyEffects(
|
|
5336
|
+
const extra = recognizedBodyEffects(
|
|
5337
|
+
definitionNode,
|
|
5338
|
+
module,
|
|
5339
|
+
storageLookup,
|
|
5340
|
+
options.facts
|
|
5341
|
+
);
|
|
5157
5342
|
const perTerminal = branchesPerTerminal({
|
|
5158
5343
|
definitionNode,
|
|
5159
5344
|
effects,
|
|
@@ -5238,7 +5423,7 @@ function unreadRoleReadings(parameters, range) {
|
|
|
5238
5423
|
)
|
|
5239
5424
|
];
|
|
5240
5425
|
}
|
|
5241
|
-
function recognizedBodyEffects(definitionNode, module, storageLookup) {
|
|
5426
|
+
function recognizedBodyEffects(definitionNode, module, storageLookup, facts) {
|
|
5242
5427
|
const storage = storageLookup === void 0 ? [] : [
|
|
5243
5428
|
...storageEffects(bodyCalls(definitionNode), {
|
|
5244
5429
|
...storageLookup,
|
|
@@ -5250,7 +5435,7 @@ function recognizedBodyEffects(definitionNode, module, storageLookup) {
|
|
|
5250
5435
|
patterns: storageLookup.rawSql ?? []
|
|
5251
5436
|
})
|
|
5252
5437
|
];
|
|
5253
|
-
return [...envReadEffects(definitionNode, module), ...storage];
|
|
5438
|
+
return [...envReadEffects(definitionNode, module, facts), ...storage];
|
|
5254
5439
|
}
|
|
5255
5440
|
function recognizedCallIds(definitionNode, storageLookup) {
|
|
5256
5441
|
if (storageLookup === void 0) {
|
|
@@ -6182,7 +6367,8 @@ function libraryUnit(target, options) {
|
|
|
6182
6367
|
const extra = recognizedBodyEffects(
|
|
6183
6368
|
node,
|
|
6184
6369
|
file.module,
|
|
6185
|
-
options.storageFor(file)
|
|
6370
|
+
options.storageFor(file),
|
|
6371
|
+
options.facts
|
|
6186
6372
|
);
|
|
6187
6373
|
const range = rangeOf(node);
|
|
6188
6374
|
return {
|
|
@@ -7763,7 +7949,8 @@ function wrapperUnit(target, declared, options) {
|
|
|
7763
7949
|
const extra = recognizedBodyEffects(
|
|
7764
7950
|
node,
|
|
7765
7951
|
file.module,
|
|
7766
|
-
options.storageFor(file)
|
|
7952
|
+
options.storageFor(file),
|
|
7953
|
+
options.facts
|
|
7767
7954
|
);
|
|
7768
7955
|
const delegate = (at) => ({
|
|
7769
7956
|
terminal: {
|
|
@@ -7921,6 +8108,10 @@ function factsForFile(options) {
|
|
|
7921
8108
|
files: [{ file: options.file, root: options.root, module: options.module }],
|
|
7922
8109
|
definitions
|
|
7923
8110
|
});
|
|
8111
|
+
bindEnvNameSites(
|
|
8112
|
+
db,
|
|
8113
|
+
envNameSites(options.file, options.root, options.module)
|
|
8114
|
+
);
|
|
7924
8115
|
addPackWords(db, packWordsOf(options.packs));
|
|
7925
8116
|
return db;
|
|
7926
8117
|
}
|
|
@@ -7978,7 +8169,10 @@ async function extractPythonProject(options) {
|
|
|
7978
8169
|
(client) => (client.receiverConstructors ?? []).length > 0
|
|
7979
8170
|
)
|
|
7980
8171
|
);
|
|
7981
|
-
const
|
|
8172
|
+
const envSites = bound.flatMap(
|
|
8173
|
+
(boundFile) => envNameSites(boundFile.file, boundFile.root, boundFile.module)
|
|
8174
|
+
);
|
|
8175
|
+
const needsValues = discovers || mountsRouters || buildsReceivers || envSites.length > 0 || storagePatterns.length > 0 || modelQueries.length > 0;
|
|
7982
8176
|
const definitions = /* @__PURE__ */ new Map();
|
|
7983
8177
|
timer.time("discover", () => {
|
|
7984
8178
|
for (const { file, root, module: moduleBinding } of bound) {
|
|
@@ -7990,6 +8184,7 @@ async function extractPythonProject(options) {
|
|
|
7990
8184
|
}
|
|
7991
8185
|
if (needsValues) {
|
|
7992
8186
|
bindEvaluator(db, { files: bound, definitions });
|
|
8187
|
+
bindEnvNameSites(db, envSites);
|
|
7993
8188
|
}
|
|
7994
8189
|
addPackWords(db, packWordsOf(options.packs));
|
|
7995
8190
|
});
|
|
@@ -8078,7 +8273,7 @@ async function extractPythonProject(options) {
|
|
|
8078
8273
|
}
|
|
8079
8274
|
const loadTimeReads = timer.time(
|
|
8080
8275
|
"discover",
|
|
8081
|
-
() => envReadEffects(root, moduleBinding)
|
|
8276
|
+
() => envReadEffects(root, moduleBinding, db)
|
|
8082
8277
|
);
|
|
8083
8278
|
if (loadTimeReads.length > 0) {
|
|
8084
8279
|
const summary = timer.time(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suss/adapter-python",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Read a Python codebase with suss and check what each FastAPI or Flask route returns against the clients, specs and infrastructure that depend on it.",
|
|
6
6
|
"keywords": [
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
"typecheck": "tsc --noEmit"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@suss/behavioral-ir": "0.
|
|
53
|
-
"@suss/datalog": "0.
|
|
54
|
-
"@suss/extractor": "0.
|
|
55
|
-
"@suss/ir-core": "0.
|
|
56
|
-
"@suss/resolution": "0.
|
|
57
|
-
"@suss/sql": "0.
|
|
58
|
-
"@suss/values": "0.
|
|
52
|
+
"@suss/behavioral-ir": "0.32.0",
|
|
53
|
+
"@suss/datalog": "0.32.0",
|
|
54
|
+
"@suss/extractor": "0.32.0",
|
|
55
|
+
"@suss/ir-core": "0.32.0",
|
|
56
|
+
"@suss/resolution": "0.32.0",
|
|
57
|
+
"@suss/sql": "0.32.0",
|
|
58
|
+
"@suss/values": "0.32.0",
|
|
59
59
|
"web-tree-sitter": "^0.26.11"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|