@suss/adapter-python 0.22.3 → 0.23.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 +31 -1
- package/dist/index.cjs +769 -193
- package/dist/index.d.cts +162 -2
- package/dist/index.d.ts +162 -2
- package/dist/index.js +710 -135
- package/package.json +14 -12
package/dist/index.js
CHANGED
|
@@ -808,9 +808,7 @@ import {
|
|
|
808
808
|
absentReading,
|
|
809
809
|
ambiguousReading,
|
|
810
810
|
andThenReading,
|
|
811
|
-
enumerateOrDegrade as enumerateOrDegrade2,
|
|
812
811
|
firstWrittenReading,
|
|
813
|
-
guardsHoldOn,
|
|
814
812
|
mapReading,
|
|
815
813
|
unreadableReading,
|
|
816
814
|
valueToReadFurtherFrom,
|
|
@@ -1032,11 +1030,11 @@ function subjectConstructions(db, valueKeys) {
|
|
|
1032
1030
|
continue;
|
|
1033
1031
|
}
|
|
1034
1032
|
const deeper = calls.has(direct) ? writtenThroughCall.get(direct) : void 0;
|
|
1035
|
-
const
|
|
1033
|
+
const constructionKey2 = deeper ?? direct;
|
|
1036
1034
|
const originOf2 = deeper === void 0 ? valueKey2 : direct;
|
|
1037
|
-
const from = origins.get(`${originOf2}|${
|
|
1035
|
+
const from = origins.get(`${originOf2}|${constructionKey2}`);
|
|
1038
1036
|
if (from !== void 0) {
|
|
1039
|
-
found.set(valueKey2, { constructionKey, origins: from });
|
|
1037
|
+
found.set(valueKey2, { constructionKey: constructionKey2, origins: from });
|
|
1040
1038
|
}
|
|
1041
1039
|
}
|
|
1042
1040
|
return found;
|
|
@@ -1443,8 +1441,8 @@ function emitValueFacts(db, filePath, root) {
|
|
|
1443
1441
|
emitExpressionFacts(emitter, root);
|
|
1444
1442
|
}
|
|
1445
1443
|
|
|
1446
|
-
// src/paths/
|
|
1447
|
-
import { enumerateOrDegrade,
|
|
1444
|
+
// src/paths/bodyBranches.ts
|
|
1445
|
+
import { enumerateOrDegrade, guardsHoldOn } from "@suss/extractor";
|
|
1448
1446
|
|
|
1449
1447
|
// src/paths/lowering.ts
|
|
1450
1448
|
var EXIT_KINDS = {
|
|
@@ -1719,7 +1717,89 @@ function predicateOf(node) {
|
|
|
1719
1717
|
return opaqueOf(node);
|
|
1720
1718
|
}
|
|
1721
1719
|
|
|
1720
|
+
// src/paths/bodyBranches.ts
|
|
1721
|
+
function returnStatements(node, found = []) {
|
|
1722
|
+
for (const child of node?.namedChildren ?? []) {
|
|
1723
|
+
if (child === null) {
|
|
1724
|
+
continue;
|
|
1725
|
+
}
|
|
1726
|
+
if (child.type === "function_definition" || child.type === "lambda") {
|
|
1727
|
+
continue;
|
|
1728
|
+
}
|
|
1729
|
+
if (child.type === "return_statement") {
|
|
1730
|
+
found.push(child);
|
|
1731
|
+
}
|
|
1732
|
+
returnStatements(child, found);
|
|
1733
|
+
}
|
|
1734
|
+
return found;
|
|
1735
|
+
}
|
|
1736
|
+
function bodyTerminals(body, raised, continuations = []) {
|
|
1737
|
+
const handsOn = new NodeSet(continuations);
|
|
1738
|
+
const found = [
|
|
1739
|
+
...returnStatements(body).filter((statement) => !handsOn.has(statement)).map((statement) => ({ type: "return", statement })),
|
|
1740
|
+
...raised.map(
|
|
1741
|
+
(response) => ({
|
|
1742
|
+
type: "raise",
|
|
1743
|
+
statement: response.statement,
|
|
1744
|
+
terminal: response.terminal
|
|
1745
|
+
})
|
|
1746
|
+
),
|
|
1747
|
+
...continuations.map(
|
|
1748
|
+
(statement) => ({ type: "continuation", statement })
|
|
1749
|
+
)
|
|
1750
|
+
];
|
|
1751
|
+
return found.sort((a, b) => a.statement.startIndex - b.statement.startIndex);
|
|
1752
|
+
}
|
|
1753
|
+
function effectsReaching(effects, conditions) {
|
|
1754
|
+
return effects.filter(
|
|
1755
|
+
(effect) => guardsHoldOn(effect.preconditions, conditions)
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1758
|
+
function enumerateBodyBranches(options) {
|
|
1759
|
+
const statements = options.terminals.map((found) => found.statement);
|
|
1760
|
+
const leavesByCall = new NodeSet([
|
|
1761
|
+
...options.raised.filter((response) => response.thrownByCall).map((response) => response.statement),
|
|
1762
|
+
...options.terminals.filter((found) => found.type === "continuation").map((found) => found.statement)
|
|
1763
|
+
]);
|
|
1764
|
+
const lowered = lowerPythonBody(options.body, statements, leavesByCall);
|
|
1765
|
+
const enumerated = enumerateOrDegrade(
|
|
1766
|
+
{
|
|
1767
|
+
statements: lowered.statements,
|
|
1768
|
+
terminalsByStmt: lowered.terminalsByStmt
|
|
1769
|
+
},
|
|
1770
|
+
statements
|
|
1771
|
+
);
|
|
1772
|
+
const branches = [];
|
|
1773
|
+
const push = (branch, paths) => {
|
|
1774
|
+
for (const path6 of paths) {
|
|
1775
|
+
const conditions = path6.map((condition) => ({
|
|
1776
|
+
sourceText: condition.sourceText,
|
|
1777
|
+
structured: condition.expression === null ? null : predicateOf(condition.expression),
|
|
1778
|
+
polarity: condition.polarity,
|
|
1779
|
+
source: condition.source
|
|
1780
|
+
}));
|
|
1781
|
+
branches.push({
|
|
1782
|
+
...branch,
|
|
1783
|
+
conditions,
|
|
1784
|
+
effects: effectsReaching(options.effects, conditions),
|
|
1785
|
+
isDefault: path6.length === 0
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
};
|
|
1789
|
+
for (const found of options.terminals) {
|
|
1790
|
+
const paths = enumerated.byTerminal.get(found.statement);
|
|
1791
|
+
if (paths !== void 0) {
|
|
1792
|
+
push(options.branchOf(found), paths);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
if (options.fallthrough !== void 0) {
|
|
1796
|
+
push(options.fallthrough, enumerated.fallthrough);
|
|
1797
|
+
}
|
|
1798
|
+
return branches;
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1722
1801
|
// src/paths/effects.ts
|
|
1802
|
+
import { enumerateOrDegrade as enumerateOrDegrade2, sharedGatingConditions } from "@suss/extractor";
|
|
1723
1803
|
var NESTED_DEFINITION_TYPES = /* @__PURE__ */ new Set(["function_definition"]);
|
|
1724
1804
|
var LITERAL_ARGS = {
|
|
1725
1805
|
string: (node) => ({ kind: "string", value: node.text.slice(1, -1) }),
|
|
@@ -1798,7 +1878,7 @@ function invocationEffects(definitionNode) {
|
|
|
1798
1878
|
statements.push(statement);
|
|
1799
1879
|
}
|
|
1800
1880
|
const lowered = lowerPythonBody(body, statements);
|
|
1801
|
-
const enumerated =
|
|
1881
|
+
const enumerated = enumerateOrDegrade2(
|
|
1802
1882
|
{
|
|
1803
1883
|
statements: lowered.statements,
|
|
1804
1884
|
terminalsByStmt: lowered.terminalsByStmt
|
|
@@ -2708,6 +2788,18 @@ function raisedResponseOf(statement, options) {
|
|
|
2708
2788
|
terminal: terminalOf(statement, callee, call, declared, options.facts)
|
|
2709
2789
|
};
|
|
2710
2790
|
}
|
|
2791
|
+
function returnedResponseStatus(statement, options) {
|
|
2792
|
+
const returned = statement.namedChildren[0];
|
|
2793
|
+
if (options.calls.length === 0 || returned === void 0 || returned === null || returned.type !== "call") {
|
|
2794
|
+
return null;
|
|
2795
|
+
}
|
|
2796
|
+
const callee = field(returned, "function");
|
|
2797
|
+
if (callee === null) {
|
|
2798
|
+
return null;
|
|
2799
|
+
}
|
|
2800
|
+
const declared = declaredCallFor(callee, options);
|
|
2801
|
+
return declared === void 0 ? null : statusOf(declared, returned, options.facts);
|
|
2802
|
+
}
|
|
2711
2803
|
function calleeOf(expression, call) {
|
|
2712
2804
|
return call === null ? expression : field(call, "function") ?? expression;
|
|
2713
2805
|
}
|
|
@@ -3542,7 +3634,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module, optio
|
|
|
3542
3634
|
routePath: entry.routePath,
|
|
3543
3635
|
...entry.mount !== void 0 ? { mount: entry.mount } : {},
|
|
3544
3636
|
requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
|
|
3545
|
-
|
|
3637
|
+
pattern,
|
|
3546
3638
|
responseStatusCalls: pattern.responseStatusCalls ?? [],
|
|
3547
3639
|
facts: options.facts,
|
|
3548
3640
|
injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
|
|
@@ -3553,10 +3645,21 @@ function classRouteUnits(pattern, pack, classification, classNode, module, optio
|
|
|
3553
3645
|
skipReceiverParam: true,
|
|
3554
3646
|
responseShape: absentReading,
|
|
3555
3647
|
statusCode: defaultedStatus(
|
|
3556
|
-
readReturnedStatus(pattern, maybeMethod
|
|
3648
|
+
readReturnedStatus(pattern, maybeMethod, {
|
|
3649
|
+
module,
|
|
3650
|
+
facts: options.facts
|
|
3651
|
+
}),
|
|
3557
3652
|
pattern
|
|
3558
3653
|
),
|
|
3559
|
-
storage: options.storage
|
|
3654
|
+
storage: options.storage,
|
|
3655
|
+
wrappers: wrappersAround(
|
|
3656
|
+
pattern,
|
|
3657
|
+
pack,
|
|
3658
|
+
classification,
|
|
3659
|
+
maybeMethod,
|
|
3660
|
+
module,
|
|
3661
|
+
options
|
|
3662
|
+
)
|
|
3560
3663
|
},
|
|
3561
3664
|
options
|
|
3562
3665
|
)
|
|
@@ -3686,21 +3789,6 @@ function readStatusCode(pattern, classification) {
|
|
|
3686
3789
|
classification.range
|
|
3687
3790
|
);
|
|
3688
3791
|
}
|
|
3689
|
-
function returnStatements(node, found = []) {
|
|
3690
|
-
for (const child of node?.namedChildren ?? []) {
|
|
3691
|
-
if (child === null) {
|
|
3692
|
-
continue;
|
|
3693
|
-
}
|
|
3694
|
-
if (child.type === "function_definition" || child.type === "lambda") {
|
|
3695
|
-
continue;
|
|
3696
|
-
}
|
|
3697
|
-
if (child.type === "return_statement") {
|
|
3698
|
-
found.push(child);
|
|
3699
|
-
}
|
|
3700
|
-
returnStatements(child, found);
|
|
3701
|
-
}
|
|
3702
|
-
return found;
|
|
3703
|
-
}
|
|
3704
3792
|
function statusFromReturnedValue(node) {
|
|
3705
3793
|
if (node === void 0) {
|
|
3706
3794
|
return null;
|
|
@@ -3724,27 +3812,19 @@ function statusOfReturn(statement) {
|
|
|
3724
3812
|
const status = statusFromReturnedValue(returned.namedChildren[1]);
|
|
3725
3813
|
return status === null ? { kind: "unreadable" } : { kind: "status", value: status };
|
|
3726
3814
|
}
|
|
3727
|
-
function effectsReaching(effects, conditions) {
|
|
3728
|
-
return effects.filter(
|
|
3729
|
-
(effect) => guardsHoldOn(effect.preconditions, conditions)
|
|
3730
|
-
);
|
|
3731
|
-
}
|
|
3732
3815
|
function returnStatusReading(statement, ctx) {
|
|
3733
|
-
|
|
3734
|
-
return ctx.declaredStatus.reading;
|
|
3735
|
-
}
|
|
3736
|
-
const read = statusOfReturn(statement);
|
|
3816
|
+
const read = statusOfReturnIn(statement, ctx.pattern, ctx);
|
|
3737
3817
|
const range = rangeOf(statement);
|
|
3738
3818
|
if (read.kind === "status") {
|
|
3739
3819
|
return writtenReading(read.value, range);
|
|
3740
3820
|
}
|
|
3741
|
-
if (read.kind === "
|
|
3742
|
-
return
|
|
3821
|
+
if (read.kind === "unreadable") {
|
|
3822
|
+
return unreadableReading(
|
|
3823
|
+
"This return gives a status this reading cannot resolve to a number, so this outcome claims none",
|
|
3824
|
+
range
|
|
3825
|
+
);
|
|
3743
3826
|
}
|
|
3744
|
-
return
|
|
3745
|
-
"This return gives a status this reading cannot resolve to a number, so this outcome claims none",
|
|
3746
|
-
range
|
|
3747
|
-
);
|
|
3827
|
+
return ctx.pattern.statusFromReturnedTuple === true ? absentReading : ctx.declaredStatus.reading;
|
|
3748
3828
|
}
|
|
3749
3829
|
function returnBranch(statement, ctx) {
|
|
3750
3830
|
const range = rangeOf(statement);
|
|
@@ -3780,74 +3860,49 @@ function terminalBranchOf(found, ctx) {
|
|
|
3780
3860
|
raise: (variant) => ({
|
|
3781
3861
|
terminal: variant.terminal,
|
|
3782
3862
|
location: rangeOf(variant.statement)
|
|
3783
|
-
})
|
|
3863
|
+
}),
|
|
3864
|
+
// A route has no continuation, so none is ever collected for it.
|
|
3865
|
+
continuation: (variant) => returnBranch(variant.statement, ctx)
|
|
3784
3866
|
};
|
|
3785
3867
|
return dispatchByType(table, found);
|
|
3786
3868
|
}
|
|
3787
|
-
function routeTerminals(body, raised) {
|
|
3788
|
-
const found = [
|
|
3789
|
-
...returnStatements(body).map(
|
|
3790
|
-
(statement) => ({ type: "return", statement })
|
|
3791
|
-
),
|
|
3792
|
-
...raised.map(
|
|
3793
|
-
(response) => ({
|
|
3794
|
-
type: "raise",
|
|
3795
|
-
statement: response.statement,
|
|
3796
|
-
terminal: response.terminal
|
|
3797
|
-
})
|
|
3798
|
-
)
|
|
3799
|
-
];
|
|
3800
|
-
return found.sort((a, b) => a.statement.startIndex - b.statement.startIndex);
|
|
3801
|
-
}
|
|
3802
3869
|
function branchesPerTerminal(options) {
|
|
3803
3870
|
const body = field(options.definitionNode, "body");
|
|
3804
3871
|
const raised = raisedResponses(body, {
|
|
3805
3872
|
calls: options.responseStatusCalls,
|
|
3873
|
+
module: options.ctx.module,
|
|
3874
|
+
facts: options.ctx.facts
|
|
3875
|
+
});
|
|
3876
|
+
const terminals = bodyTerminals(body, raised);
|
|
3877
|
+
const soleReturnWritesBody = terminals.length === 1 && terminals[0]?.type === "return" && returnedBodyShape(terminals[0].statement) !== null;
|
|
3878
|
+
if (terminals.length < 2 && !soleReturnWritesBody) {
|
|
3879
|
+
return null;
|
|
3880
|
+
}
|
|
3881
|
+
const branches = enumerateBodyBranches({
|
|
3882
|
+
body,
|
|
3883
|
+
terminals,
|
|
3884
|
+
raised,
|
|
3885
|
+
effects: options.effects,
|
|
3886
|
+
branchOf: (found) => terminalBranchOf(found, options.ctx)
|
|
3887
|
+
});
|
|
3888
|
+
return branches.length > 1 || soleReturnWritesBody ? branches : null;
|
|
3889
|
+
}
|
|
3890
|
+
function statusOfReturnIn(statement, pattern, options) {
|
|
3891
|
+
const constructed = returnedResponseStatus(statement, {
|
|
3892
|
+
calls: pattern.responseConstructors ?? [],
|
|
3806
3893
|
module: options.module,
|
|
3807
3894
|
facts: options.facts
|
|
3808
3895
|
});
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
return null;
|
|
3896
|
+
if (constructed !== null) {
|
|
3897
|
+
return constructed.type === "literal" ? { kind: "status", value: constructed.value } : { kind: "unreadable" };
|
|
3812
3898
|
}
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
raised.filter((response) => response.thrownByCall).map((response) => response.statement)
|
|
3816
|
-
);
|
|
3817
|
-
const lowered = lowerPythonBody(body, statements, thrownByCall);
|
|
3818
|
-
const enumerated = enumerateOrDegrade2(
|
|
3819
|
-
{
|
|
3820
|
-
statements: lowered.statements,
|
|
3821
|
-
terminalsByStmt: lowered.terminalsByStmt
|
|
3822
|
-
},
|
|
3823
|
-
statements
|
|
3824
|
-
);
|
|
3825
|
-
const branches = [];
|
|
3826
|
-
for (const found of terminals) {
|
|
3827
|
-
const paths = enumerated.byTerminal.get(found.statement);
|
|
3828
|
-
if (paths === void 0) {
|
|
3829
|
-
continue;
|
|
3830
|
-
}
|
|
3831
|
-
const branch = terminalBranchOf(found, options.ctx);
|
|
3832
|
-
for (const path6 of paths) {
|
|
3833
|
-
const conditions = path6.map((condition) => ({
|
|
3834
|
-
sourceText: condition.sourceText,
|
|
3835
|
-
structured: condition.expression === null ? null : predicateOf(condition.expression),
|
|
3836
|
-
polarity: condition.polarity,
|
|
3837
|
-
source: condition.source
|
|
3838
|
-
}));
|
|
3839
|
-
branches.push({
|
|
3840
|
-
...branch,
|
|
3841
|
-
conditions,
|
|
3842
|
-
effects: effectsReaching(options.effects, conditions),
|
|
3843
|
-
isDefault: path6.length === 0
|
|
3844
|
-
});
|
|
3845
|
-
}
|
|
3899
|
+
if (pattern.statusFromReturnedTuple !== true) {
|
|
3900
|
+
return { kind: "none" };
|
|
3846
3901
|
}
|
|
3847
|
-
return
|
|
3902
|
+
return statusOfReturn(statement);
|
|
3848
3903
|
}
|
|
3849
|
-
function readReturnedStatus(pattern, definitionNode) {
|
|
3850
|
-
if (pattern.statusFromReturnedTuple !== true) {
|
|
3904
|
+
function readReturnedStatus(pattern, definitionNode, options) {
|
|
3905
|
+
if (pattern.statusFromReturnedTuple !== true && (pattern.responseConstructors ?? []).length === 0) {
|
|
3851
3906
|
return absentReading;
|
|
3852
3907
|
}
|
|
3853
3908
|
const range = rangeOf(definitionNode);
|
|
@@ -3855,7 +3910,7 @@ function readReturnedStatus(pattern, definitionNode) {
|
|
|
3855
3910
|
let plainReturns = 0;
|
|
3856
3911
|
let unreadable = 0;
|
|
3857
3912
|
for (const statement of returnStatements(field(definitionNode, "body"))) {
|
|
3858
|
-
const read =
|
|
3913
|
+
const read = statusOfReturnIn(statement, pattern, options);
|
|
3859
3914
|
if (read.kind === "status") {
|
|
3860
3915
|
statuses.add(read.value);
|
|
3861
3916
|
} else if (read.kind === "none") {
|
|
@@ -3943,7 +3998,7 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
3943
3998
|
routePath: entry.routePath,
|
|
3944
3999
|
...entry.mount !== void 0 ? { mount: entry.mount } : {},
|
|
3945
4000
|
requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
|
|
3946
|
-
|
|
4001
|
+
pattern,
|
|
3947
4002
|
responseStatusCalls: pattern.responseStatusCalls ?? [],
|
|
3948
4003
|
facts: options.facts,
|
|
3949
4004
|
injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
|
|
@@ -3956,17 +4011,41 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
3956
4011
|
statusCode: defaultedStatus(
|
|
3957
4012
|
declaredOrReturnedStatus(
|
|
3958
4013
|
readStatusCode(pattern, classification),
|
|
3959
|
-
readReturnedStatus(pattern, functionNode
|
|
4014
|
+
readReturnedStatus(pattern, functionNode, {
|
|
4015
|
+
module,
|
|
4016
|
+
facts: options.facts
|
|
4017
|
+
})
|
|
3960
4018
|
),
|
|
3961
4019
|
pattern
|
|
3962
4020
|
),
|
|
3963
4021
|
definitionsCtx: ctx,
|
|
3964
|
-
storage: options.storage
|
|
4022
|
+
storage: options.storage,
|
|
4023
|
+
wrappers: wrappersAround(
|
|
4024
|
+
pattern,
|
|
4025
|
+
pack,
|
|
4026
|
+
classification,
|
|
4027
|
+
functionNode,
|
|
4028
|
+
module,
|
|
4029
|
+
options
|
|
4030
|
+
)
|
|
3965
4031
|
},
|
|
3966
4032
|
options
|
|
3967
4033
|
)
|
|
3968
4034
|
);
|
|
3969
4035
|
}
|
|
4036
|
+
function wrappersAround(pattern, pack, classification, definitionNode, module, options) {
|
|
4037
|
+
if (options.wrappers === void 0) {
|
|
4038
|
+
return [];
|
|
4039
|
+
}
|
|
4040
|
+
return options.wrappers.wrappersFor({
|
|
4041
|
+
pack,
|
|
4042
|
+
pattern,
|
|
4043
|
+
file: options.absoluteFile ?? options.filePath,
|
|
4044
|
+
module,
|
|
4045
|
+
classification,
|
|
4046
|
+
definitionNode
|
|
4047
|
+
});
|
|
4048
|
+
}
|
|
3970
4049
|
function readResponseShape(declared, readAnnotation) {
|
|
3971
4050
|
if (declared.kind === "written") {
|
|
3972
4051
|
return { reading: declared, passedOver: [] };
|
|
@@ -4026,7 +4105,7 @@ function buildRouteUnit(options) {
|
|
|
4026
4105
|
method,
|
|
4027
4106
|
routePath,
|
|
4028
4107
|
requestBodyFromAnnotatedClass,
|
|
4029
|
-
|
|
4108
|
+
pattern,
|
|
4030
4109
|
injectedCallees,
|
|
4031
4110
|
definitionNode,
|
|
4032
4111
|
enclosingScope,
|
|
@@ -4057,10 +4136,14 @@ function buildRouteUnit(options) {
|
|
|
4057
4136
|
const perTerminal = branchesPerTerminal({
|
|
4058
4137
|
definitionNode,
|
|
4059
4138
|
effects,
|
|
4060
|
-
module,
|
|
4061
|
-
facts: options.facts,
|
|
4062
4139
|
responseStatusCalls: options.responseStatusCalls,
|
|
4063
|
-
ctx: {
|
|
4140
|
+
ctx: {
|
|
4141
|
+
pattern,
|
|
4142
|
+
responseShape,
|
|
4143
|
+
declaredStatus: statusCode,
|
|
4144
|
+
module,
|
|
4145
|
+
facts: options.facts
|
|
4146
|
+
}
|
|
4064
4147
|
});
|
|
4065
4148
|
const branches = (perTerminal ?? []).map(
|
|
4066
4149
|
(branch) => extra.length === 0 ? branch : { ...branch, extraEffects: extra }
|
|
@@ -4119,7 +4202,8 @@ function buildRouteUnit(options) {
|
|
|
4119
4202
|
...responseShape.passedOver
|
|
4120
4203
|
],
|
|
4121
4204
|
...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {},
|
|
4122
|
-
...options.mount !== void 0 ? { mount: options.mount } : {}
|
|
4205
|
+
...options.mount !== void 0 ? { mount: options.mount } : {},
|
|
4206
|
+
...options.wrappers !== void 0 && options.wrappers.length > 0 ? { wrappers: options.wrappers } : {}
|
|
4123
4207
|
};
|
|
4124
4208
|
}
|
|
4125
4209
|
function unreadRoleReadings(parameters, range) {
|
|
@@ -4479,6 +4563,7 @@ import {
|
|
|
4479
4563
|
import { Database as Database2 } from "@suss/datalog";
|
|
4480
4564
|
import {
|
|
4481
4565
|
assembleSummary as assembleSummary2,
|
|
4566
|
+
composeWrappers,
|
|
4482
4567
|
createCacheLayer,
|
|
4483
4568
|
createTimer,
|
|
4484
4569
|
moduleInitStructure,
|
|
@@ -5201,12 +5286,8 @@ function buildRouterIndex(files, packs, resolverOptions) {
|
|
|
5201
5286
|
}
|
|
5202
5287
|
return {
|
|
5203
5288
|
moduleDef(fromFile, spec, name) {
|
|
5204
|
-
const
|
|
5205
|
-
if (
|
|
5206
|
-
return null;
|
|
5207
|
-
}
|
|
5208
|
-
const bound = byFile.get(resolution.file);
|
|
5209
|
-
if (bound === void 0) {
|
|
5289
|
+
const bound = boundModuleAt(fromFile, spec, byFile, resolverOptions);
|
|
5290
|
+
if (bound === null) {
|
|
5210
5291
|
return null;
|
|
5211
5292
|
}
|
|
5212
5293
|
const binding = bound.module.moduleScope.bindings.get(name);
|
|
@@ -5232,12 +5313,12 @@ function buildRouterIndex(files, packs, resolverOptions) {
|
|
|
5232
5313
|
}
|
|
5233
5314
|
return composedPrefixOf(index, construction, displayPaths.get(module));
|
|
5234
5315
|
},
|
|
5235
|
-
resolveConstruction(pattern, module, constructorName,
|
|
5316
|
+
resolveConstruction(pattern, module, constructorName, constructionKey2) {
|
|
5236
5317
|
const index = byPattern.get(pattern);
|
|
5237
5318
|
if (index === void 0) {
|
|
5238
5319
|
return NOT_ROUTER;
|
|
5239
5320
|
}
|
|
5240
|
-
const construction = index.byValueKey.get(
|
|
5321
|
+
const construction = index.byValueKey.get(constructionKey2);
|
|
5241
5322
|
if (construction !== void 0) {
|
|
5242
5323
|
return composedPrefixOf(index, construction, displayPaths.get(module));
|
|
5243
5324
|
}
|
|
@@ -5473,6 +5554,13 @@ function buildPatternIndex(files, importModule, composition, resolverOptions) {
|
|
|
5473
5554
|
}
|
|
5474
5555
|
return index;
|
|
5475
5556
|
}
|
|
5557
|
+
function boundModuleAt(fromFile, spec, byFile, resolverOptions) {
|
|
5558
|
+
const resolution = resolveModule(fromFile, spec, resolverOptions);
|
|
5559
|
+
if (resolution.status !== "resolved") {
|
|
5560
|
+
return null;
|
|
5561
|
+
}
|
|
5562
|
+
return byFile.get(resolution.file) ?? null;
|
|
5563
|
+
}
|
|
5476
5564
|
function constructionOf(name, scope, importModule) {
|
|
5477
5565
|
const binding = resolveName(scope, name);
|
|
5478
5566
|
if (binding?.kind !== "assignment" || binding.value?.type !== "call") {
|
|
@@ -5681,16 +5769,13 @@ function constructionNamed(name, scope, scan, constructions = scan.index.constru
|
|
|
5681
5769
|
if (binding.kind !== "importFrom") {
|
|
5682
5770
|
return null;
|
|
5683
5771
|
}
|
|
5684
|
-
const
|
|
5772
|
+
const target = boundModuleAt(
|
|
5685
5773
|
scan.bound.file,
|
|
5686
5774
|
{ module: binding.module, relativeLevel: binding.relativeLevel },
|
|
5775
|
+
scan.byFile,
|
|
5687
5776
|
scan.resolverOptions
|
|
5688
5777
|
);
|
|
5689
|
-
if (
|
|
5690
|
-
return null;
|
|
5691
|
-
}
|
|
5692
|
-
const target = scan.byFile.get(resolution.file);
|
|
5693
|
-
if (target === void 0) {
|
|
5778
|
+
if (target === null) {
|
|
5694
5779
|
return null;
|
|
5695
5780
|
}
|
|
5696
5781
|
return constructions.get(target.module)?.get(binding.importedName) ?? null;
|
|
@@ -5708,10 +5793,10 @@ function constructionThroughFacts(name, scope, scan) {
|
|
|
5708
5793
|
return null;
|
|
5709
5794
|
}
|
|
5710
5795
|
const nameKey = `${scan.bound.file}#${name}`;
|
|
5711
|
-
const
|
|
5796
|
+
const constructionKey2 = subjectConstructions(facts, [nameKey]).get(
|
|
5712
5797
|
nameKey
|
|
5713
5798
|
)?.constructionKey;
|
|
5714
|
-
return
|
|
5799
|
+
return constructionKey2 === void 0 ? null : scan.index.byValueKey.get(constructionKey2) ?? null;
|
|
5715
5800
|
}
|
|
5716
5801
|
var MOUNT_STATE_BY_EFFECT = {
|
|
5717
5802
|
prefixes: (statedPrefix, site) => ({
|
|
@@ -5948,12 +6033,13 @@ function constructionThroughModule(arg, scope, scan) {
|
|
|
5948
6033
|
if (spec === null) {
|
|
5949
6034
|
return null;
|
|
5950
6035
|
}
|
|
5951
|
-
const
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
6036
|
+
const target = boundModuleAt(
|
|
6037
|
+
scan.bound.file,
|
|
6038
|
+
spec,
|
|
6039
|
+
scan.byFile,
|
|
6040
|
+
scan.resolverOptions
|
|
6041
|
+
);
|
|
6042
|
+
if (target === null) {
|
|
5957
6043
|
return null;
|
|
5958
6044
|
}
|
|
5959
6045
|
return scan.index.constructions.get(target.module)?.get(arg.attributeName) ?? null;
|
|
@@ -6304,6 +6390,472 @@ var adapterStamp = createAdapterStamp({
|
|
|
6304
6390
|
version: ADAPTER_VERSION
|
|
6305
6391
|
});
|
|
6306
6392
|
|
|
6393
|
+
// src/wrappers.ts
|
|
6394
|
+
import { absentReading as absentReading2, walkDescendants as walkDescendants4 } from "@suss/extractor";
|
|
6395
|
+
function buildWrapperIndex(files, options) {
|
|
6396
|
+
const forms = declaredForms(options.packs);
|
|
6397
|
+
const filesByPath = new Map(files.map((file) => [file.file, file]));
|
|
6398
|
+
const index = new PythonWrapperIndex(options, filesByPath);
|
|
6399
|
+
if (forms.length > 0) {
|
|
6400
|
+
for (const file of files) {
|
|
6401
|
+
for (const declared of forms) {
|
|
6402
|
+
registerFrom(file, declared, index);
|
|
6403
|
+
}
|
|
6404
|
+
}
|
|
6405
|
+
}
|
|
6406
|
+
return index;
|
|
6407
|
+
}
|
|
6408
|
+
function declaredForms(packs) {
|
|
6409
|
+
return packs.flatMap(
|
|
6410
|
+
(pack) => pack.discovery.flatMap(
|
|
6411
|
+
(pattern) => (pattern.wrappers ?? []).map((form) => ({ pack, pattern, form }))
|
|
6412
|
+
)
|
|
6413
|
+
);
|
|
6414
|
+
}
|
|
6415
|
+
var PythonWrapperIndex = class {
|
|
6416
|
+
constructor(options, filesByPath) {
|
|
6417
|
+
this.options = options;
|
|
6418
|
+
this.filesByPath = filesByPath;
|
|
6419
|
+
}
|
|
6420
|
+
options;
|
|
6421
|
+
filesByPath;
|
|
6422
|
+
/** By pack name: what the app registered, in the order the forms are declared and then the order the files were read. */
|
|
6423
|
+
everyRoute = /* @__PURE__ */ new Map();
|
|
6424
|
+
/** By construction key: what a router or a blueprint registered. */
|
|
6425
|
+
ownRoutes = /* @__PURE__ */ new Map();
|
|
6426
|
+
unitsByKey = /* @__PURE__ */ new Map();
|
|
6427
|
+
unitsByFile = /* @__PURE__ */ new Map();
|
|
6428
|
+
register(covers, target, declared) {
|
|
6429
|
+
const registered = this.registered(target, declared);
|
|
6430
|
+
const table = covers.kind === "everyRoute" ? this.everyRoute : this.ownRoutes;
|
|
6431
|
+
const key = covers.kind === "everyRoute" ? covers.pack : covers.key;
|
|
6432
|
+
const list = table.get(key) ?? [];
|
|
6433
|
+
list.push(registered);
|
|
6434
|
+
table.set(key, list);
|
|
6435
|
+
}
|
|
6436
|
+
/** The unit for a function, built once however many registrations point at it. */
|
|
6437
|
+
registered(target, declared) {
|
|
6438
|
+
const span = spanOf(target.node);
|
|
6439
|
+
const key = `${target.file.file}:${span.start}-${span.end}`;
|
|
6440
|
+
if (!this.unitsByKey.has(key)) {
|
|
6441
|
+
const unit = wrapperUnit(target, declared, this.options);
|
|
6442
|
+
this.unitsByKey.set(key, unit);
|
|
6443
|
+
const inFile = this.unitsByFile.get(target.file.file) ?? [];
|
|
6444
|
+
inFile.push(unit);
|
|
6445
|
+
this.unitsByFile.set(target.file.file, inFile);
|
|
6446
|
+
}
|
|
6447
|
+
return {
|
|
6448
|
+
reference: {
|
|
6449
|
+
file: target.file.displayPath,
|
|
6450
|
+
name: target.name,
|
|
6451
|
+
...isThrowForm(declared.form) ? { onThrow: true } : {}
|
|
6452
|
+
},
|
|
6453
|
+
form: declared.form
|
|
6454
|
+
};
|
|
6455
|
+
}
|
|
6456
|
+
wrappersFor(query) {
|
|
6457
|
+
const file = this.filesByPath.get(query.file);
|
|
6458
|
+
const forms = (query.pattern.wrappers ?? []).map((form) => ({
|
|
6459
|
+
pack: query.pack,
|
|
6460
|
+
pattern: query.pattern,
|
|
6461
|
+
form
|
|
6462
|
+
}));
|
|
6463
|
+
if (file === void 0 || forms.length === 0) {
|
|
6464
|
+
return [];
|
|
6465
|
+
}
|
|
6466
|
+
const found = [
|
|
6467
|
+
...this.everyRoute.get(query.pack.name) ?? [],
|
|
6468
|
+
...this.ownRoutesOf(query)
|
|
6469
|
+
];
|
|
6470
|
+
for (const declared of forms) {
|
|
6471
|
+
if (declared.form.type !== "dependency") {
|
|
6472
|
+
continue;
|
|
6473
|
+
}
|
|
6474
|
+
const site = {
|
|
6475
|
+
file,
|
|
6476
|
+
scope: query.module.moduleScope,
|
|
6477
|
+
rebound: /* @__PURE__ */ new Set()
|
|
6478
|
+
};
|
|
6479
|
+
const targets = [
|
|
6480
|
+
...decoratorDependencies(query.classification, declared.form),
|
|
6481
|
+
...parameterDependencies(query.definitionNode, declared.form)
|
|
6482
|
+
];
|
|
6483
|
+
for (const name of targets) {
|
|
6484
|
+
const target = resolveNamedFunctionArgument(name, site, {
|
|
6485
|
+
filesByPath: this.filesByPath,
|
|
6486
|
+
roots: this.options.roots
|
|
6487
|
+
});
|
|
6488
|
+
if (target !== null) {
|
|
6489
|
+
found.push(this.registered(target, declared));
|
|
6490
|
+
}
|
|
6491
|
+
}
|
|
6492
|
+
}
|
|
6493
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6494
|
+
const ordered = [];
|
|
6495
|
+
for (const wrapper of [...found].sort(
|
|
6496
|
+
(a, b) => runOrder(a.form) - runOrder(b.form)
|
|
6497
|
+
)) {
|
|
6498
|
+
const key = `${wrapper.reference.file}::${wrapper.reference.name}::${wrapper.reference.onThrow === true}`;
|
|
6499
|
+
if (seen.has(key)) {
|
|
6500
|
+
continue;
|
|
6501
|
+
}
|
|
6502
|
+
seen.add(key);
|
|
6503
|
+
ordered.push(wrapper.reference);
|
|
6504
|
+
}
|
|
6505
|
+
return ordered;
|
|
6506
|
+
}
|
|
6507
|
+
ownRoutesOf(query) {
|
|
6508
|
+
const site = this.objectSiteOf(query);
|
|
6509
|
+
if (site === null) {
|
|
6510
|
+
return [];
|
|
6511
|
+
}
|
|
6512
|
+
for (const form of query.pattern.wrappers ?? []) {
|
|
6513
|
+
const match = registrarOf(site.name, site.scope, {
|
|
6514
|
+
pack: query.pack,
|
|
6515
|
+
pattern: query.pattern,
|
|
6516
|
+
form
|
|
6517
|
+
});
|
|
6518
|
+
if (match !== null && match.registrar.covers === "ownRoutes") {
|
|
6519
|
+
return this.ownRoutes.get(constructionKey(site.file, match.call)) ?? [];
|
|
6520
|
+
}
|
|
6521
|
+
}
|
|
6522
|
+
return [];
|
|
6523
|
+
}
|
|
6524
|
+
/**
|
|
6525
|
+
* Where the decorator's object was built: the route's own file, the file
|
|
6526
|
+
* a project wrapper function is written in, or the file an imported
|
|
6527
|
+
* router comes from. The name is the one that file binds it under.
|
|
6528
|
+
*/
|
|
6529
|
+
objectSiteOf(query) {
|
|
6530
|
+
const name = query.classification.objectName;
|
|
6531
|
+
if (name === null) {
|
|
6532
|
+
return null;
|
|
6533
|
+
}
|
|
6534
|
+
const wrapperModule = query.classification.objectModule;
|
|
6535
|
+
if (wrapperModule !== void 0) {
|
|
6536
|
+
const file = this.fileOfModule(wrapperModule);
|
|
6537
|
+
return file === null ? null : { file, scope: wrapperModule.moduleScope, name };
|
|
6538
|
+
}
|
|
6539
|
+
const binding = resolveName(query.module.moduleScope, name);
|
|
6540
|
+
if (binding?.kind !== "importFrom") {
|
|
6541
|
+
return { file: query.file, scope: query.module.moduleScope, name };
|
|
6542
|
+
}
|
|
6543
|
+
const target = boundModuleAt(
|
|
6544
|
+
query.file,
|
|
6545
|
+
{ module: binding.module, relativeLevel: binding.relativeLevel },
|
|
6546
|
+
this.filesByPath,
|
|
6547
|
+
{ roots: this.options.roots }
|
|
6548
|
+
);
|
|
6549
|
+
return target === null ? null : {
|
|
6550
|
+
file: target.file,
|
|
6551
|
+
scope: target.module.moduleScope,
|
|
6552
|
+
name: binding.importedName
|
|
6553
|
+
};
|
|
6554
|
+
}
|
|
6555
|
+
fileOfModule(module) {
|
|
6556
|
+
for (const file of this.filesByPath.values()) {
|
|
6557
|
+
if (file.module === module) {
|
|
6558
|
+
return file.file;
|
|
6559
|
+
}
|
|
6560
|
+
}
|
|
6561
|
+
return null;
|
|
6562
|
+
}
|
|
6563
|
+
unitsIn(file) {
|
|
6564
|
+
return this.unitsByFile.get(file) ?? [];
|
|
6565
|
+
}
|
|
6566
|
+
};
|
|
6567
|
+
function isThrowForm(form) {
|
|
6568
|
+
return form.type === "decoratedWrapper" && form.throwParam !== void 0;
|
|
6569
|
+
}
|
|
6570
|
+
function runOrder(form) {
|
|
6571
|
+
if (isThrowForm(form)) {
|
|
6572
|
+
return 2;
|
|
6573
|
+
}
|
|
6574
|
+
return form.type === "decoratedWrapper" ? 0 : 1;
|
|
6575
|
+
}
|
|
6576
|
+
function registrarOf(name, scope, declared) {
|
|
6577
|
+
const modules = [
|
|
6578
|
+
...declared.pattern.importModule,
|
|
6579
|
+
...declared.form.registrars.flatMap(
|
|
6580
|
+
(registrar2) => registrar2.importModule ?? []
|
|
6581
|
+
)
|
|
6582
|
+
];
|
|
6583
|
+
const construction = constructionOf(name, scope, modules);
|
|
6584
|
+
if (construction === null) {
|
|
6585
|
+
return null;
|
|
6586
|
+
}
|
|
6587
|
+
const registrar = declared.form.registrars.find(
|
|
6588
|
+
(candidate) => candidate.constructorName === construction.constructorName
|
|
6589
|
+
);
|
|
6590
|
+
return registrar === void 0 ? null : { registrar, call: construction.call };
|
|
6591
|
+
}
|
|
6592
|
+
function constructionKey(file, call) {
|
|
6593
|
+
return `${file}#${call.startIndex}`;
|
|
6594
|
+
}
|
|
6595
|
+
function registerFrom(file, declared, index) {
|
|
6596
|
+
const table = {
|
|
6597
|
+
dependency: () => registerConstructorDependencies(
|
|
6598
|
+
file,
|
|
6599
|
+
declared,
|
|
6600
|
+
declared.form,
|
|
6601
|
+
index
|
|
6602
|
+
),
|
|
6603
|
+
decoratedWrapper: () => registerDecorated(
|
|
6604
|
+
file,
|
|
6605
|
+
declared,
|
|
6606
|
+
declared.form,
|
|
6607
|
+
index
|
|
6608
|
+
)
|
|
6609
|
+
};
|
|
6610
|
+
table[declared.form.type]();
|
|
6611
|
+
}
|
|
6612
|
+
function registerConstructorDependencies(file, declared, form, index) {
|
|
6613
|
+
const scope = file.module.moduleScope;
|
|
6614
|
+
for (const stmt of file.root.namedChildren) {
|
|
6615
|
+
const assignment2 = stmt?.type === "expression_statement" ? stmt.namedChildren.find((child) => child?.type === "assignment") : void 0;
|
|
6616
|
+
const left = assignment2 === void 0 || assignment2 === null ? null : field(assignment2, "left");
|
|
6617
|
+
if (left?.type !== "identifier") {
|
|
6618
|
+
continue;
|
|
6619
|
+
}
|
|
6620
|
+
const match = registrarOf(left.text, scope, declared);
|
|
6621
|
+
if (match === null) {
|
|
6622
|
+
continue;
|
|
6623
|
+
}
|
|
6624
|
+
const { keywordArgs } = readCallArguments(field(match.call, "arguments"));
|
|
6625
|
+
const listed = keywordArgs[form.keyword];
|
|
6626
|
+
if (listed === void 0) {
|
|
6627
|
+
continue;
|
|
6628
|
+
}
|
|
6629
|
+
const site = { file, scope, rebound: /* @__PURE__ */ new Set() };
|
|
6630
|
+
for (const name of dependencyNamesIn(listed.node, form)) {
|
|
6631
|
+
const target = resolveNamedFunctionArgument(name, site, {
|
|
6632
|
+
filesByPath: index.filesByPath,
|
|
6633
|
+
roots: index.options.roots
|
|
6634
|
+
});
|
|
6635
|
+
if (target !== null) {
|
|
6636
|
+
index.register(
|
|
6637
|
+
coverageOf(match, file, declared.pack),
|
|
6638
|
+
target,
|
|
6639
|
+
declared
|
|
6640
|
+
);
|
|
6641
|
+
}
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
function coverageOf(match, file, pack) {
|
|
6646
|
+
return match.registrar.covers === "everyRoute" ? { kind: "everyRoute", pack: pack.name } : { kind: "ownRoutes", key: constructionKey(file.file, match.call) };
|
|
6647
|
+
}
|
|
6648
|
+
function registerDecorated(file, declared, form, index) {
|
|
6649
|
+
walkDescendants4(file.root, file.module.moduleScope, {
|
|
6650
|
+
at: (node, scope) => {
|
|
6651
|
+
if (node.type !== "decorated_definition") {
|
|
6652
|
+
return;
|
|
6653
|
+
}
|
|
6654
|
+
const { definition, decorators } = stripDecorators(node);
|
|
6655
|
+
if (definition.type !== "function_definition") {
|
|
6656
|
+
return;
|
|
6657
|
+
}
|
|
6658
|
+
for (const decorator of decorators) {
|
|
6659
|
+
const receiver = decoratorReceiver(decorator);
|
|
6660
|
+
if (receiver === null || receiver.attributeName !== form.attribute || receiver.object.type !== "identifier") {
|
|
6661
|
+
continue;
|
|
6662
|
+
}
|
|
6663
|
+
const match = registrarOf(receiver.object.text, scope, declared);
|
|
6664
|
+
const name = field(definition, "name")?.text;
|
|
6665
|
+
if (match === null || name === void 0) {
|
|
6666
|
+
continue;
|
|
6667
|
+
}
|
|
6668
|
+
index.register(
|
|
6669
|
+
coverageOf(match, file, declared.pack),
|
|
6670
|
+
{ file, node: definition, name, exportPath: [name] },
|
|
6671
|
+
declared
|
|
6672
|
+
);
|
|
6673
|
+
}
|
|
6674
|
+
},
|
|
6675
|
+
into: (node, scope) => file.module.scopeFor.get(node.id) ?? scope
|
|
6676
|
+
});
|
|
6677
|
+
}
|
|
6678
|
+
function dependencyNamesIn(node, form) {
|
|
6679
|
+
const calls = node.type === "list" ? node.namedChildren : [node];
|
|
6680
|
+
const names = [];
|
|
6681
|
+
for (const call of calls) {
|
|
6682
|
+
const name = call === null ? null : dependencyNameOf(call, form);
|
|
6683
|
+
if (name !== null) {
|
|
6684
|
+
names.push(name);
|
|
6685
|
+
}
|
|
6686
|
+
}
|
|
6687
|
+
return names;
|
|
6688
|
+
}
|
|
6689
|
+
function dependencyNameOf(node, form) {
|
|
6690
|
+
if (node.type !== "call") {
|
|
6691
|
+
return null;
|
|
6692
|
+
}
|
|
6693
|
+
const callee = field(node, "function");
|
|
6694
|
+
const calleeName3 = callee?.type === "identifier" ? callee.text : callee?.type === "attribute" ? field(callee, "attribute")?.text ?? null : null;
|
|
6695
|
+
if (calleeName3 === null || !form.callees.includes(calleeName3)) {
|
|
6696
|
+
return null;
|
|
6697
|
+
}
|
|
6698
|
+
const first = field(node, "arguments")?.namedChildren[0];
|
|
6699
|
+
return first?.type === "identifier" ? first.text : null;
|
|
6700
|
+
}
|
|
6701
|
+
function decoratorDependencies(classification, form) {
|
|
6702
|
+
const listed = classification.keywordArgs[form.keyword];
|
|
6703
|
+
return listed === void 0 ? [] : dependencyNamesIn(listed.node, form);
|
|
6704
|
+
}
|
|
6705
|
+
var MAX_ANNOTATION_DEPTH2 = 6;
|
|
6706
|
+
function parameterDependencies(definitionNode, form) {
|
|
6707
|
+
const names = [];
|
|
6708
|
+
const findIn = (node, depth) => {
|
|
6709
|
+
if (node === null || depth > MAX_ANNOTATION_DEPTH2) {
|
|
6710
|
+
return null;
|
|
6711
|
+
}
|
|
6712
|
+
const direct = dependencyNameOf(node, form);
|
|
6713
|
+
if (direct !== null) {
|
|
6714
|
+
return direct;
|
|
6715
|
+
}
|
|
6716
|
+
for (const child of node.namedChildren) {
|
|
6717
|
+
const found = findIn(child, depth + 1);
|
|
6718
|
+
if (found !== null) {
|
|
6719
|
+
return found;
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
return null;
|
|
6723
|
+
};
|
|
6724
|
+
for (const param of field(definitionNode, "parameters")?.namedChildren ?? []) {
|
|
6725
|
+
if (param === null) {
|
|
6726
|
+
continue;
|
|
6727
|
+
}
|
|
6728
|
+
const inDefault = field(param, "value");
|
|
6729
|
+
const found = inDefault === null ? findIn(field(param, "type"), 0) : dependencyNameOf(inDefault, form);
|
|
6730
|
+
if (found !== null) {
|
|
6731
|
+
names.push(found);
|
|
6732
|
+
}
|
|
6733
|
+
}
|
|
6734
|
+
return names;
|
|
6735
|
+
}
|
|
6736
|
+
function wrapperUnit(target, declared, options) {
|
|
6737
|
+
const { file, node, name, exportPath } = target;
|
|
6738
|
+
const body = field(node, "body");
|
|
6739
|
+
const range = rangeOf(node);
|
|
6740
|
+
const raised = raisedResponses(body, {
|
|
6741
|
+
calls: declared.pattern.responseStatusCalls ?? [],
|
|
6742
|
+
module: file.module,
|
|
6743
|
+
facts: options.facts
|
|
6744
|
+
});
|
|
6745
|
+
const continuations = continuationStatements(node, declared.form);
|
|
6746
|
+
const terminals = bodyTerminals(body, raised, continuations);
|
|
6747
|
+
const effects = invocationEffects(node);
|
|
6748
|
+
const extra = recognizedBodyEffects(
|
|
6749
|
+
node,
|
|
6750
|
+
file.module,
|
|
6751
|
+
options.storageFor(file)
|
|
6752
|
+
);
|
|
6753
|
+
const delegate = (at) => ({
|
|
6754
|
+
terminal: {
|
|
6755
|
+
kind: "delegate",
|
|
6756
|
+
statusCode: null,
|
|
6757
|
+
body: null,
|
|
6758
|
+
exceptionType: null,
|
|
6759
|
+
message: null,
|
|
6760
|
+
component: null,
|
|
6761
|
+
renderTree: null,
|
|
6762
|
+
delegateTarget: null,
|
|
6763
|
+
emitEvent: null,
|
|
6764
|
+
location: rangeOf(at)
|
|
6765
|
+
},
|
|
6766
|
+
location: rangeOf(at)
|
|
6767
|
+
});
|
|
6768
|
+
const respond = (statement) => returnBranch(statement, {
|
|
6769
|
+
pattern: declared.pattern,
|
|
6770
|
+
responseShape: { reading: absentReading2 },
|
|
6771
|
+
declaredStatus: {
|
|
6772
|
+
reading: absentReading2,
|
|
6773
|
+
...declared.pattern.defaultStatusCode !== void 0 ? { libraryDefault: declared.pattern.defaultStatusCode } : {}
|
|
6774
|
+
},
|
|
6775
|
+
module: file.module,
|
|
6776
|
+
facts: options.facts
|
|
6777
|
+
});
|
|
6778
|
+
const branchOf = (terminal) => {
|
|
6779
|
+
if (terminal.type === "raise") {
|
|
6780
|
+
return {
|
|
6781
|
+
terminal: terminal.terminal,
|
|
6782
|
+
location: rangeOf(terminal.statement)
|
|
6783
|
+
};
|
|
6784
|
+
}
|
|
6785
|
+
if (terminal.type === "continuation" || returnHandsOn(terminal.statement, declared.form)) {
|
|
6786
|
+
return delegate(terminal.statement);
|
|
6787
|
+
}
|
|
6788
|
+
return respond(terminal.statement);
|
|
6789
|
+
};
|
|
6790
|
+
const branches = enumerateBodyBranches({
|
|
6791
|
+
body,
|
|
6792
|
+
terminals,
|
|
6793
|
+
raised,
|
|
6794
|
+
effects,
|
|
6795
|
+
branchOf,
|
|
6796
|
+
fallthrough: delegate(node)
|
|
6797
|
+
}).map(
|
|
6798
|
+
(branch) => extra.length === 0 ? branch : { ...branch, extraEffects: extra }
|
|
6799
|
+
);
|
|
6800
|
+
return {
|
|
6801
|
+
identity: {
|
|
6802
|
+
name,
|
|
6803
|
+
nameKind: "binding",
|
|
6804
|
+
kind: "middleware",
|
|
6805
|
+
file: file.displayPath,
|
|
6806
|
+
range,
|
|
6807
|
+
span: spanOf(node),
|
|
6808
|
+
exportName: exportPath[0] ?? name,
|
|
6809
|
+
exportPath
|
|
6810
|
+
},
|
|
6811
|
+
boundaryBinding: null,
|
|
6812
|
+
parameters: [],
|
|
6813
|
+
branches,
|
|
6814
|
+
bodyContent: body === null ? "absent" : bodyContentOf(body),
|
|
6815
|
+
dependencyCalls: [],
|
|
6816
|
+
declaredContract: null
|
|
6817
|
+
};
|
|
6818
|
+
}
|
|
6819
|
+
function returnHandsOn(statement, form) {
|
|
6820
|
+
if (form.type === "dependency") {
|
|
6821
|
+
return true;
|
|
6822
|
+
}
|
|
6823
|
+
if (form.continuationParam !== void 0 || form.throwParam !== void 0) {
|
|
6824
|
+
return false;
|
|
6825
|
+
}
|
|
6826
|
+
if (form.returnedValueResponds === true) {
|
|
6827
|
+
const returned = statement.namedChildren[0];
|
|
6828
|
+
return returned === void 0 || returned === null || returned.type === "none";
|
|
6829
|
+
}
|
|
6830
|
+
return true;
|
|
6831
|
+
}
|
|
6832
|
+
function continuationStatements(node, form) {
|
|
6833
|
+
if (form.type !== "decoratedWrapper" || form.continuationParam === void 0) {
|
|
6834
|
+
return [];
|
|
6835
|
+
}
|
|
6836
|
+
const params = (field(node, "parameters")?.namedChildren ?? []).filter(
|
|
6837
|
+
(param2) => param2 !== null
|
|
6838
|
+
);
|
|
6839
|
+
const param = params[form.continuationParam];
|
|
6840
|
+
const continuation = param === void 0 ? null : field(param, "name")?.text ?? (param.type === "identifier" ? param.text : null);
|
|
6841
|
+
if (continuation === null) {
|
|
6842
|
+
return [];
|
|
6843
|
+
}
|
|
6844
|
+
const body = field(node, "body");
|
|
6845
|
+
if (body === null) {
|
|
6846
|
+
return [];
|
|
6847
|
+
}
|
|
6848
|
+
const found = [];
|
|
6849
|
+
for (const call of bodyCalls(body)) {
|
|
6850
|
+
const callee = field(call, "function");
|
|
6851
|
+
const statement = callee?.type === "identifier" && callee.text === continuation ? enclosingStatement(call, body) : null;
|
|
6852
|
+
if (statement !== null) {
|
|
6853
|
+
found.push(statement);
|
|
6854
|
+
}
|
|
6855
|
+
}
|
|
6856
|
+
return found;
|
|
6857
|
+
}
|
|
6858
|
+
|
|
6307
6859
|
// src/project.ts
|
|
6308
6860
|
function reportUnresolvedProjectModules(options, db) {
|
|
6309
6861
|
const imported = new Set(db.facts("pyImport").map((row) => String(row[1])));
|
|
@@ -6401,24 +6953,43 @@ async function extractPythonProject(options) {
|
|
|
6401
6953
|
couldMatch,
|
|
6402
6954
|
rawSql: rawSqlPatterns
|
|
6403
6955
|
} : void 0;
|
|
6404
|
-
const
|
|
6405
|
-
|
|
6956
|
+
const wrapperIndex = timer.time(
|
|
6957
|
+
"discover",
|
|
6958
|
+
() => buildWrapperIndex(bound, {
|
|
6959
|
+
packs: options.packs,
|
|
6960
|
+
roots: options.roots,
|
|
6961
|
+
facts: needsValues ? db : void 0,
|
|
6962
|
+
storageFor
|
|
6963
|
+
})
|
|
6964
|
+
);
|
|
6965
|
+
const discovered = /* @__PURE__ */ new Map();
|
|
6406
6966
|
for (const boundFile of bound) {
|
|
6407
6967
|
const { file, root, module: moduleBinding } = boundFile;
|
|
6408
|
-
const displayPath = displayPathOf(file);
|
|
6409
6968
|
const storage = storageFor(boundFile);
|
|
6410
6969
|
const rawUnits = timer.time(
|
|
6411
6970
|
"discover",
|
|
6412
6971
|
() => discoverUnits(root, moduleBinding, {
|
|
6413
6972
|
packs: options.packs,
|
|
6414
|
-
filePath:
|
|
6973
|
+
filePath: displayPathOf(file),
|
|
6415
6974
|
absoluteFile: file,
|
|
6416
6975
|
routerIndex,
|
|
6417
6976
|
gapHandling,
|
|
6977
|
+
wrappers: wrapperIndex,
|
|
6418
6978
|
...needsValues ? { facts: db } : {},
|
|
6419
6979
|
...storage === void 0 ? {} : { storage }
|
|
6420
6980
|
})
|
|
6421
6981
|
);
|
|
6982
|
+
discovered.set(file, rawUnits);
|
|
6983
|
+
}
|
|
6984
|
+
const seeds = [];
|
|
6985
|
+
const summariesBySeed = /* @__PURE__ */ new Map();
|
|
6986
|
+
for (const boundFile of bound) {
|
|
6987
|
+
const { file, root, module: moduleBinding } = boundFile;
|
|
6988
|
+
const displayPath = displayPathOf(file);
|
|
6989
|
+
const rawUnits = [
|
|
6990
|
+
...discovered.get(file) ?? [],
|
|
6991
|
+
...wrapperIndex.unitsIn(file)
|
|
6992
|
+
];
|
|
6422
6993
|
for (const raw of rawUnits) {
|
|
6423
6994
|
const summary = timer.time(
|
|
6424
6995
|
"summarize",
|
|
@@ -6506,12 +7077,16 @@ async function extractPythonProject(options) {
|
|
|
6506
7077
|
}
|
|
6507
7078
|
disambiguateSummaryIds(summaries);
|
|
6508
7079
|
linkCallsToSummaries(summaries);
|
|
7080
|
+
const composed = timer.time(
|
|
7081
|
+
"summarize",
|
|
7082
|
+
() => composeWrappers(summaries, { gapHandling })
|
|
7083
|
+
);
|
|
6509
7084
|
await timer.timeAsync("cache.write", async () => {
|
|
6510
|
-
if (cacheDir === null ||
|
|
7085
|
+
if (cacheDir === null || composed.length === 0) {
|
|
6511
7086
|
return;
|
|
6512
7087
|
}
|
|
6513
7088
|
try {
|
|
6514
|
-
await cache.write(cacheInput,
|
|
7089
|
+
await cache.write(cacheInput, composed);
|
|
6515
7090
|
} catch {
|
|
6516
7091
|
}
|
|
6517
7092
|
});
|
|
@@ -6520,11 +7095,11 @@ async function extractPythonProject(options) {
|
|
|
6520
7095
|
packs: options.packs,
|
|
6521
7096
|
tallies,
|
|
6522
7097
|
filesWalked: options.files.length,
|
|
6523
|
-
summaries
|
|
7098
|
+
summaries: composed
|
|
6524
7099
|
})
|
|
6525
7100
|
);
|
|
6526
7101
|
options.onTiming?.(timer.report());
|
|
6527
|
-
return { summaries, facts: db };
|
|
7102
|
+
return { summaries: composed, facts: db };
|
|
6528
7103
|
}
|
|
6529
7104
|
function resolvedImportsOf(db, displayPathOf) {
|
|
6530
7105
|
const importsByFile = /* @__PURE__ */ new Map();
|