@suss/adapter-python 0.22.4 → 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 +8 -8
package/dist/index.cjs
CHANGED
|
@@ -870,7 +870,7 @@ function passesParametersThrough(def, inner) {
|
|
|
870
870
|
|
|
871
871
|
// src/discovery.ts
|
|
872
872
|
var import_behavioral_ir2 = require("@suss/behavioral-ir");
|
|
873
|
-
var
|
|
873
|
+
var import_extractor5 = require("@suss/extractor");
|
|
874
874
|
var import_values7 = require("@suss/values");
|
|
875
875
|
|
|
876
876
|
// src/envReads.ts
|
|
@@ -1079,11 +1079,11 @@ function subjectConstructions(db, valueKeys) {
|
|
|
1079
1079
|
continue;
|
|
1080
1080
|
}
|
|
1081
1081
|
const deeper = calls.has(direct) ? writtenThroughCall.get(direct) : void 0;
|
|
1082
|
-
const
|
|
1082
|
+
const constructionKey2 = deeper ?? direct;
|
|
1083
1083
|
const originOf2 = deeper === void 0 ? valueKey2 : direct;
|
|
1084
|
-
const from = origins.get(`${originOf2}|${
|
|
1084
|
+
const from = origins.get(`${originOf2}|${constructionKey2}`);
|
|
1085
1085
|
if (from !== void 0) {
|
|
1086
|
-
found.set(valueKey2, { constructionKey, origins: from });
|
|
1086
|
+
found.set(valueKey2, { constructionKey: constructionKey2, origins: from });
|
|
1087
1087
|
}
|
|
1088
1088
|
}
|
|
1089
1089
|
return found;
|
|
@@ -1490,7 +1490,7 @@ function emitValueFacts(db, filePath, root) {
|
|
|
1490
1490
|
emitExpressionFacts(emitter, root);
|
|
1491
1491
|
}
|
|
1492
1492
|
|
|
1493
|
-
// src/paths/
|
|
1493
|
+
// src/paths/bodyBranches.ts
|
|
1494
1494
|
var import_extractor3 = require("@suss/extractor");
|
|
1495
1495
|
|
|
1496
1496
|
// src/paths/lowering.ts
|
|
@@ -1766,7 +1766,89 @@ function predicateOf(node) {
|
|
|
1766
1766
|
return opaqueOf(node);
|
|
1767
1767
|
}
|
|
1768
1768
|
|
|
1769
|
+
// src/paths/bodyBranches.ts
|
|
1770
|
+
function returnStatements(node, found = []) {
|
|
1771
|
+
for (const child of node?.namedChildren ?? []) {
|
|
1772
|
+
if (child === null) {
|
|
1773
|
+
continue;
|
|
1774
|
+
}
|
|
1775
|
+
if (child.type === "function_definition" || child.type === "lambda") {
|
|
1776
|
+
continue;
|
|
1777
|
+
}
|
|
1778
|
+
if (child.type === "return_statement") {
|
|
1779
|
+
found.push(child);
|
|
1780
|
+
}
|
|
1781
|
+
returnStatements(child, found);
|
|
1782
|
+
}
|
|
1783
|
+
return found;
|
|
1784
|
+
}
|
|
1785
|
+
function bodyTerminals(body, raised, continuations = []) {
|
|
1786
|
+
const handsOn = new NodeSet(continuations);
|
|
1787
|
+
const found = [
|
|
1788
|
+
...returnStatements(body).filter((statement) => !handsOn.has(statement)).map((statement) => ({ type: "return", statement })),
|
|
1789
|
+
...raised.map(
|
|
1790
|
+
(response) => ({
|
|
1791
|
+
type: "raise",
|
|
1792
|
+
statement: response.statement,
|
|
1793
|
+
terminal: response.terminal
|
|
1794
|
+
})
|
|
1795
|
+
),
|
|
1796
|
+
...continuations.map(
|
|
1797
|
+
(statement) => ({ type: "continuation", statement })
|
|
1798
|
+
)
|
|
1799
|
+
];
|
|
1800
|
+
return found.sort((a, b) => a.statement.startIndex - b.statement.startIndex);
|
|
1801
|
+
}
|
|
1802
|
+
function effectsReaching(effects, conditions) {
|
|
1803
|
+
return effects.filter(
|
|
1804
|
+
(effect) => (0, import_extractor3.guardsHoldOn)(effect.preconditions, conditions)
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
function enumerateBodyBranches(options) {
|
|
1808
|
+
const statements = options.terminals.map((found) => found.statement);
|
|
1809
|
+
const leavesByCall = new NodeSet([
|
|
1810
|
+
...options.raised.filter((response) => response.thrownByCall).map((response) => response.statement),
|
|
1811
|
+
...options.terminals.filter((found) => found.type === "continuation").map((found) => found.statement)
|
|
1812
|
+
]);
|
|
1813
|
+
const lowered = lowerPythonBody(options.body, statements, leavesByCall);
|
|
1814
|
+
const enumerated = (0, import_extractor3.enumerateOrDegrade)(
|
|
1815
|
+
{
|
|
1816
|
+
statements: lowered.statements,
|
|
1817
|
+
terminalsByStmt: lowered.terminalsByStmt
|
|
1818
|
+
},
|
|
1819
|
+
statements
|
|
1820
|
+
);
|
|
1821
|
+
const branches = [];
|
|
1822
|
+
const push = (branch, paths) => {
|
|
1823
|
+
for (const path6 of paths) {
|
|
1824
|
+
const conditions = path6.map((condition) => ({
|
|
1825
|
+
sourceText: condition.sourceText,
|
|
1826
|
+
structured: condition.expression === null ? null : predicateOf(condition.expression),
|
|
1827
|
+
polarity: condition.polarity,
|
|
1828
|
+
source: condition.source
|
|
1829
|
+
}));
|
|
1830
|
+
branches.push({
|
|
1831
|
+
...branch,
|
|
1832
|
+
conditions,
|
|
1833
|
+
effects: effectsReaching(options.effects, conditions),
|
|
1834
|
+
isDefault: path6.length === 0
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
};
|
|
1838
|
+
for (const found of options.terminals) {
|
|
1839
|
+
const paths = enumerated.byTerminal.get(found.statement);
|
|
1840
|
+
if (paths !== void 0) {
|
|
1841
|
+
push(options.branchOf(found), paths);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
if (options.fallthrough !== void 0) {
|
|
1845
|
+
push(options.fallthrough, enumerated.fallthrough);
|
|
1846
|
+
}
|
|
1847
|
+
return branches;
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1769
1850
|
// src/paths/effects.ts
|
|
1851
|
+
var import_extractor4 = require("@suss/extractor");
|
|
1770
1852
|
var NESTED_DEFINITION_TYPES = /* @__PURE__ */ new Set(["function_definition"]);
|
|
1771
1853
|
var LITERAL_ARGS = {
|
|
1772
1854
|
string: (node) => ({ kind: "string", value: node.text.slice(1, -1) }),
|
|
@@ -1845,7 +1927,7 @@ function invocationEffects(definitionNode) {
|
|
|
1845
1927
|
statements.push(statement);
|
|
1846
1928
|
}
|
|
1847
1929
|
const lowered = lowerPythonBody(body, statements);
|
|
1848
|
-
const enumerated = (0,
|
|
1930
|
+
const enumerated = (0, import_extractor4.enumerateOrDegrade)(
|
|
1849
1931
|
{
|
|
1850
1932
|
statements: lowered.statements,
|
|
1851
1933
|
terminalsByStmt: lowered.terminalsByStmt
|
|
@@ -1854,7 +1936,7 @@ function invocationEffects(definitionNode) {
|
|
|
1854
1936
|
);
|
|
1855
1937
|
return calls.map((call) => {
|
|
1856
1938
|
const statement = statementOf2.get(call.id);
|
|
1857
|
-
const conditions = (0,
|
|
1939
|
+
const conditions = (0, import_extractor4.sharedGatingConditions)(
|
|
1858
1940
|
statement === void 0 ? void 0 : enumerated.byTerminal.get(statement),
|
|
1859
1941
|
predicateOf
|
|
1860
1942
|
);
|
|
@@ -2734,6 +2816,18 @@ function raisedResponseOf(statement, options) {
|
|
|
2734
2816
|
terminal: terminalOf(statement, callee, call, declared, options.facts)
|
|
2735
2817
|
};
|
|
2736
2818
|
}
|
|
2819
|
+
function returnedResponseStatus(statement, options) {
|
|
2820
|
+
const returned = statement.namedChildren[0];
|
|
2821
|
+
if (options.calls.length === 0 || returned === void 0 || returned === null || returned.type !== "call") {
|
|
2822
|
+
return null;
|
|
2823
|
+
}
|
|
2824
|
+
const callee = field(returned, "function");
|
|
2825
|
+
if (callee === null) {
|
|
2826
|
+
return null;
|
|
2827
|
+
}
|
|
2828
|
+
const declared = declaredCallFor(callee, options);
|
|
2829
|
+
return declared === void 0 ? null : statusOf(declared, returned, options.facts);
|
|
2830
|
+
}
|
|
2737
2831
|
function calleeOf(expression, call) {
|
|
2738
2832
|
return call === null ? expression : field(call, "function") ?? expression;
|
|
2739
2833
|
}
|
|
@@ -3310,7 +3404,7 @@ function storageEffects(calls, options) {
|
|
|
3310
3404
|
// src/discovery.ts
|
|
3311
3405
|
function decoratedStatements(root, module2) {
|
|
3312
3406
|
const found = [];
|
|
3313
|
-
(0,
|
|
3407
|
+
(0, import_extractor5.walkDescendants)(
|
|
3314
3408
|
root,
|
|
3315
3409
|
{ scope: module2.moduleScope, enclosingFunction: null },
|
|
3316
3410
|
{
|
|
@@ -3489,10 +3583,10 @@ function readPathArgument(classification, options) {
|
|
|
3489
3583
|
const value = evaluatedValue(first.node, options.facts);
|
|
3490
3584
|
const path6 = (0, import_values7.literalOf)(value) ?? (0, import_values7.pathOf)(value);
|
|
3491
3585
|
if (path6 !== void 0) {
|
|
3492
|
-
return (0,
|
|
3586
|
+
return (0, import_extractor5.writtenReading)(path6, classification.range);
|
|
3493
3587
|
}
|
|
3494
3588
|
}
|
|
3495
|
-
return (0,
|
|
3589
|
+
return (0, import_extractor5.unreadableReading)(
|
|
3496
3590
|
"The path in this route's decorator is not a string literal, so the binding names no path and nothing pairs with it",
|
|
3497
3591
|
classification.range
|
|
3498
3592
|
);
|
|
@@ -3517,16 +3611,16 @@ var PATH_TEMPLATE_READERS = {
|
|
|
3517
3611
|
function readPathTemplate(pattern, path6, range) {
|
|
3518
3612
|
const syntax = pattern.pathParamSyntax;
|
|
3519
3613
|
if (syntax === void 0) {
|
|
3520
|
-
return (0,
|
|
3614
|
+
return (0, import_extractor5.writtenReading)({ path: path6, paramNames: NO_PATH_PARAMS }, range);
|
|
3521
3615
|
}
|
|
3522
3616
|
const reader = PATH_TEMPLATE_READERS[syntax];
|
|
3523
3617
|
if (reader === void 0) {
|
|
3524
|
-
return (0,
|
|
3618
|
+
return (0, import_extractor5.unreadableReading)(
|
|
3525
3619
|
`The route's pack declares path-parameter syntax "${syntax}", which this adapter has no reader for, so the binding names no path and nothing pairs with it`,
|
|
3526
3620
|
range
|
|
3527
3621
|
);
|
|
3528
3622
|
}
|
|
3529
|
-
return (0,
|
|
3623
|
+
return (0, import_extractor5.writtenReading)(reader(path6), range);
|
|
3530
3624
|
}
|
|
3531
3625
|
function classRouteUnits(pattern, pack, classification, classNode, module2, options) {
|
|
3532
3626
|
const pathArgument = readPathArgument(classification, options);
|
|
@@ -3568,7 +3662,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
3568
3662
|
routePath: entry.routePath,
|
|
3569
3663
|
...entry.mount !== void 0 ? { mount: entry.mount } : {},
|
|
3570
3664
|
requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
|
|
3571
|
-
|
|
3665
|
+
pattern,
|
|
3572
3666
|
responseStatusCalls: pattern.responseStatusCalls ?? [],
|
|
3573
3667
|
facts: options.facts,
|
|
3574
3668
|
injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
|
|
@@ -3577,12 +3671,23 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
3577
3671
|
module: module2,
|
|
3578
3672
|
filePath: options.filePath,
|
|
3579
3673
|
skipReceiverParam: true,
|
|
3580
|
-
responseShape:
|
|
3674
|
+
responseShape: import_extractor5.absentReading,
|
|
3581
3675
|
statusCode: defaultedStatus(
|
|
3582
|
-
readReturnedStatus(pattern, maybeMethod
|
|
3676
|
+
readReturnedStatus(pattern, maybeMethod, {
|
|
3677
|
+
module: module2,
|
|
3678
|
+
facts: options.facts
|
|
3679
|
+
}),
|
|
3583
3680
|
pattern
|
|
3584
3681
|
),
|
|
3585
|
-
storage: options.storage
|
|
3682
|
+
storage: options.storage,
|
|
3683
|
+
wrappers: wrappersAround(
|
|
3684
|
+
pattern,
|
|
3685
|
+
pack,
|
|
3686
|
+
classification,
|
|
3687
|
+
maybeMethod,
|
|
3688
|
+
module2,
|
|
3689
|
+
options
|
|
3690
|
+
)
|
|
3586
3691
|
},
|
|
3587
3692
|
options
|
|
3588
3693
|
)
|
|
@@ -3592,11 +3697,11 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
3592
3697
|
return units;
|
|
3593
3698
|
}
|
|
3594
3699
|
function readRoutePath(pattern, pathArgument, classification, module2, options) {
|
|
3595
|
-
const composed = (0,
|
|
3700
|
+
const composed = (0, import_extractor5.andThenReading)(
|
|
3596
3701
|
pathArgument,
|
|
3597
3702
|
(literal, range) => composeRoutePath(pattern, classification, module2, options, literal, range)
|
|
3598
3703
|
);
|
|
3599
|
-
return (0,
|
|
3704
|
+
return (0, import_extractor5.andThenReading)(
|
|
3600
3705
|
composed,
|
|
3601
3706
|
(path6, range) => readPathTemplate(pattern, path6, range)
|
|
3602
3707
|
);
|
|
@@ -3622,10 +3727,10 @@ function readRoutePaths(pattern, pathArgument, classification, module2, options)
|
|
|
3622
3727
|
];
|
|
3623
3728
|
}
|
|
3624
3729
|
return resolution.values.map((prefix) => ({
|
|
3625
|
-
routePath: (0,
|
|
3626
|
-
(0,
|
|
3730
|
+
routePath: (0, import_extractor5.andThenReading)(
|
|
3731
|
+
(0, import_extractor5.andThenReading)(
|
|
3627
3732
|
pathArgument,
|
|
3628
|
-
(literal, range) => (0,
|
|
3733
|
+
(literal, range) => (0, import_extractor5.writtenReading)(servedSpelling(pattern, prefix + literal), range)
|
|
3629
3734
|
),
|
|
3630
3735
|
(path6, range) => readPathTemplate(pattern, path6, range)
|
|
3631
3736
|
),
|
|
@@ -3661,9 +3766,9 @@ function composeRoutePath(pattern, classification, module2, options, literal, ra
|
|
|
3661
3766
|
range
|
|
3662
3767
|
);
|
|
3663
3768
|
if (prefix.kind === "absent") {
|
|
3664
|
-
return (0,
|
|
3769
|
+
return (0, import_extractor5.writtenReading)(servedSpelling(pattern, literal), range);
|
|
3665
3770
|
}
|
|
3666
|
-
return (0,
|
|
3771
|
+
return (0, import_extractor5.mapReading)(
|
|
3667
3772
|
prefix,
|
|
3668
3773
|
(value) => servedSpelling(pattern, value + literal)
|
|
3669
3774
|
);
|
|
@@ -3683,50 +3788,35 @@ function readRouterPrefix(pattern, classification, module2, options, range) {
|
|
|
3683
3788
|
options
|
|
3684
3789
|
);
|
|
3685
3790
|
if (resolution === null) {
|
|
3686
|
-
return
|
|
3791
|
+
return import_extractor5.absentReading;
|
|
3687
3792
|
}
|
|
3688
3793
|
if (resolution.kind === "abstain") {
|
|
3689
|
-
return (0,
|
|
3794
|
+
return (0, import_extractor5.unreadableReading)(
|
|
3690
3795
|
`The router this route is declared on ${resolution.reason}, so the binding names no path and nothing pairs with it`,
|
|
3691
3796
|
range
|
|
3692
3797
|
);
|
|
3693
3798
|
}
|
|
3694
3799
|
if (resolution.kind === "composed") {
|
|
3695
|
-
return (0,
|
|
3800
|
+
return (0, import_extractor5.writtenReading)(resolution.value, range);
|
|
3696
3801
|
}
|
|
3697
|
-
return
|
|
3802
|
+
return import_extractor5.absentReading;
|
|
3698
3803
|
}
|
|
3699
3804
|
function readStatusCode(pattern, classification) {
|
|
3700
3805
|
if (pattern.statusCodeKeyword === void 0) {
|
|
3701
|
-
return
|
|
3806
|
+
return import_extractor5.absentReading;
|
|
3702
3807
|
}
|
|
3703
3808
|
const arg = classification.keywordArgs[pattern.statusCodeKeyword];
|
|
3704
3809
|
if (arg === void 0) {
|
|
3705
|
-
return
|
|
3810
|
+
return import_extractor5.absentReading;
|
|
3706
3811
|
}
|
|
3707
3812
|
if (arg.kind === "number") {
|
|
3708
|
-
return (0,
|
|
3813
|
+
return (0, import_extractor5.writtenReading)(arg.value, classification.range);
|
|
3709
3814
|
}
|
|
3710
|
-
return (0,
|
|
3815
|
+
return (0, import_extractor5.unreadableReading)(
|
|
3711
3816
|
"The status this route's decorator states is not a literal number, so the response claims no status",
|
|
3712
3817
|
classification.range
|
|
3713
3818
|
);
|
|
3714
3819
|
}
|
|
3715
|
-
function returnStatements(node, found = []) {
|
|
3716
|
-
for (const child of node?.namedChildren ?? []) {
|
|
3717
|
-
if (child === null) {
|
|
3718
|
-
continue;
|
|
3719
|
-
}
|
|
3720
|
-
if (child.type === "function_definition" || child.type === "lambda") {
|
|
3721
|
-
continue;
|
|
3722
|
-
}
|
|
3723
|
-
if (child.type === "return_statement") {
|
|
3724
|
-
found.push(child);
|
|
3725
|
-
}
|
|
3726
|
-
returnStatements(child, found);
|
|
3727
|
-
}
|
|
3728
|
-
return found;
|
|
3729
|
-
}
|
|
3730
3820
|
function statusFromReturnedValue(node) {
|
|
3731
3821
|
if (node === void 0) {
|
|
3732
3822
|
return null;
|
|
@@ -3750,27 +3840,19 @@ function statusOfReturn(statement) {
|
|
|
3750
3840
|
const status = statusFromReturnedValue(returned.namedChildren[1]);
|
|
3751
3841
|
return status === null ? { kind: "unreadable" } : { kind: "status", value: status };
|
|
3752
3842
|
}
|
|
3753
|
-
function effectsReaching(effects, conditions) {
|
|
3754
|
-
return effects.filter(
|
|
3755
|
-
(effect) => (0, import_extractor4.guardsHoldOn)(effect.preconditions, conditions)
|
|
3756
|
-
);
|
|
3757
|
-
}
|
|
3758
3843
|
function returnStatusReading(statement, ctx) {
|
|
3759
|
-
|
|
3760
|
-
return ctx.declaredStatus.reading;
|
|
3761
|
-
}
|
|
3762
|
-
const read = statusOfReturn(statement);
|
|
3844
|
+
const read = statusOfReturnIn(statement, ctx.pattern, ctx);
|
|
3763
3845
|
const range = rangeOf(statement);
|
|
3764
3846
|
if (read.kind === "status") {
|
|
3765
|
-
return (0,
|
|
3847
|
+
return (0, import_extractor5.writtenReading)(read.value, range);
|
|
3766
3848
|
}
|
|
3767
|
-
if (read.kind === "
|
|
3768
|
-
return
|
|
3849
|
+
if (read.kind === "unreadable") {
|
|
3850
|
+
return (0, import_extractor5.unreadableReading)(
|
|
3851
|
+
"This return gives a status this reading cannot resolve to a number, so this outcome claims none",
|
|
3852
|
+
range
|
|
3853
|
+
);
|
|
3769
3854
|
}
|
|
3770
|
-
return
|
|
3771
|
-
"This return gives a status this reading cannot resolve to a number, so this outcome claims none",
|
|
3772
|
-
range
|
|
3773
|
-
);
|
|
3855
|
+
return ctx.pattern.statusFromReturnedTuple === true ? import_extractor5.absentReading : ctx.declaredStatus.reading;
|
|
3774
3856
|
}
|
|
3775
3857
|
function returnBranch(statement, ctx) {
|
|
3776
3858
|
const range = rangeOf(statement);
|
|
@@ -3795,7 +3877,7 @@ function returnBranch(statement, ctx) {
|
|
|
3795
3877
|
...ctx.declaredStatus.libraryDefault !== void 0 ? { libraryDefault: ctx.declaredStatus.libraryDefault } : {}
|
|
3796
3878
|
},
|
|
3797
3879
|
bodyShapeReading: {
|
|
3798
|
-
reading: writtenBody === null ? ctx.responseShape.reading : (0,
|
|
3880
|
+
reading: writtenBody === null ? ctx.responseShape.reading : (0, import_extractor5.writtenReading)(writtenBody, range)
|
|
3799
3881
|
},
|
|
3800
3882
|
location: range
|
|
3801
3883
|
};
|
|
@@ -3806,82 +3888,57 @@ function terminalBranchOf(found, ctx) {
|
|
|
3806
3888
|
raise: (variant) => ({
|
|
3807
3889
|
terminal: variant.terminal,
|
|
3808
3890
|
location: rangeOf(variant.statement)
|
|
3809
|
-
})
|
|
3891
|
+
}),
|
|
3892
|
+
// A route has no continuation, so none is ever collected for it.
|
|
3893
|
+
continuation: (variant) => returnBranch(variant.statement, ctx)
|
|
3810
3894
|
};
|
|
3811
3895
|
return (0, import_behavioral_ir2.dispatchByType)(table, found);
|
|
3812
3896
|
}
|
|
3813
|
-
function routeTerminals(body, raised) {
|
|
3814
|
-
const found = [
|
|
3815
|
-
...returnStatements(body).map(
|
|
3816
|
-
(statement) => ({ type: "return", statement })
|
|
3817
|
-
),
|
|
3818
|
-
...raised.map(
|
|
3819
|
-
(response) => ({
|
|
3820
|
-
type: "raise",
|
|
3821
|
-
statement: response.statement,
|
|
3822
|
-
terminal: response.terminal
|
|
3823
|
-
})
|
|
3824
|
-
)
|
|
3825
|
-
];
|
|
3826
|
-
return found.sort((a, b) => a.statement.startIndex - b.statement.startIndex);
|
|
3827
|
-
}
|
|
3828
3897
|
function branchesPerTerminal(options) {
|
|
3829
3898
|
const body = field(options.definitionNode, "body");
|
|
3830
3899
|
const raised = raisedResponses(body, {
|
|
3831
3900
|
calls: options.responseStatusCalls,
|
|
3901
|
+
module: options.ctx.module,
|
|
3902
|
+
facts: options.ctx.facts
|
|
3903
|
+
});
|
|
3904
|
+
const terminals = bodyTerminals(body, raised);
|
|
3905
|
+
const soleReturnWritesBody = terminals.length === 1 && terminals[0]?.type === "return" && returnedBodyShape(terminals[0].statement) !== null;
|
|
3906
|
+
if (terminals.length < 2 && !soleReturnWritesBody) {
|
|
3907
|
+
return null;
|
|
3908
|
+
}
|
|
3909
|
+
const branches = enumerateBodyBranches({
|
|
3910
|
+
body,
|
|
3911
|
+
terminals,
|
|
3912
|
+
raised,
|
|
3913
|
+
effects: options.effects,
|
|
3914
|
+
branchOf: (found) => terminalBranchOf(found, options.ctx)
|
|
3915
|
+
});
|
|
3916
|
+
return branches.length > 1 || soleReturnWritesBody ? branches : null;
|
|
3917
|
+
}
|
|
3918
|
+
function statusOfReturnIn(statement, pattern, options) {
|
|
3919
|
+
const constructed = returnedResponseStatus(statement, {
|
|
3920
|
+
calls: pattern.responseConstructors ?? [],
|
|
3832
3921
|
module: options.module,
|
|
3833
3922
|
facts: options.facts
|
|
3834
3923
|
});
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
return null;
|
|
3924
|
+
if (constructed !== null) {
|
|
3925
|
+
return constructed.type === "literal" ? { kind: "status", value: constructed.value } : { kind: "unreadable" };
|
|
3838
3926
|
}
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
raised.filter((response) => response.thrownByCall).map((response) => response.statement)
|
|
3842
|
-
);
|
|
3843
|
-
const lowered = lowerPythonBody(body, statements, thrownByCall);
|
|
3844
|
-
const enumerated = (0, import_extractor4.enumerateOrDegrade)(
|
|
3845
|
-
{
|
|
3846
|
-
statements: lowered.statements,
|
|
3847
|
-
terminalsByStmt: lowered.terminalsByStmt
|
|
3848
|
-
},
|
|
3849
|
-
statements
|
|
3850
|
-
);
|
|
3851
|
-
const branches = [];
|
|
3852
|
-
for (const found of terminals) {
|
|
3853
|
-
const paths = enumerated.byTerminal.get(found.statement);
|
|
3854
|
-
if (paths === void 0) {
|
|
3855
|
-
continue;
|
|
3856
|
-
}
|
|
3857
|
-
const branch = terminalBranchOf(found, options.ctx);
|
|
3858
|
-
for (const path6 of paths) {
|
|
3859
|
-
const conditions = path6.map((condition) => ({
|
|
3860
|
-
sourceText: condition.sourceText,
|
|
3861
|
-
structured: condition.expression === null ? null : predicateOf(condition.expression),
|
|
3862
|
-
polarity: condition.polarity,
|
|
3863
|
-
source: condition.source
|
|
3864
|
-
}));
|
|
3865
|
-
branches.push({
|
|
3866
|
-
...branch,
|
|
3867
|
-
conditions,
|
|
3868
|
-
effects: effectsReaching(options.effects, conditions),
|
|
3869
|
-
isDefault: path6.length === 0
|
|
3870
|
-
});
|
|
3871
|
-
}
|
|
3927
|
+
if (pattern.statusFromReturnedTuple !== true) {
|
|
3928
|
+
return { kind: "none" };
|
|
3872
3929
|
}
|
|
3873
|
-
return
|
|
3930
|
+
return statusOfReturn(statement);
|
|
3874
3931
|
}
|
|
3875
|
-
function readReturnedStatus(pattern, definitionNode) {
|
|
3876
|
-
if (pattern.statusFromReturnedTuple !== true) {
|
|
3877
|
-
return
|
|
3932
|
+
function readReturnedStatus(pattern, definitionNode, options) {
|
|
3933
|
+
if (pattern.statusFromReturnedTuple !== true && (pattern.responseConstructors ?? []).length === 0) {
|
|
3934
|
+
return import_extractor5.absentReading;
|
|
3878
3935
|
}
|
|
3879
3936
|
const range = rangeOf(definitionNode);
|
|
3880
3937
|
const statuses = /* @__PURE__ */ new Set();
|
|
3881
3938
|
let plainReturns = 0;
|
|
3882
3939
|
let unreadable = 0;
|
|
3883
3940
|
for (const statement of returnStatements(field(definitionNode, "body"))) {
|
|
3884
|
-
const read =
|
|
3941
|
+
const read = statusOfReturnIn(statement, pattern, options);
|
|
3885
3942
|
if (read.kind === "status") {
|
|
3886
3943
|
statuses.add(read.value);
|
|
3887
3944
|
} else if (read.kind === "none") {
|
|
@@ -3891,23 +3948,23 @@ function readReturnedStatus(pattern, definitionNode) {
|
|
|
3891
3948
|
}
|
|
3892
3949
|
}
|
|
3893
3950
|
if (unreadable > 0) {
|
|
3894
|
-
return (0,
|
|
3951
|
+
return (0, import_extractor5.unreadableReading)(
|
|
3895
3952
|
"This route returns a status this reading cannot resolve to a number, so no status is claimed for it",
|
|
3896
3953
|
range
|
|
3897
3954
|
);
|
|
3898
3955
|
}
|
|
3899
3956
|
if (statuses.size === 0) {
|
|
3900
|
-
return
|
|
3957
|
+
return import_extractor5.absentReading;
|
|
3901
3958
|
}
|
|
3902
3959
|
const candidates = [...statuses];
|
|
3903
3960
|
if (statuses.size > 1 || plainReturns > 0) {
|
|
3904
|
-
return (0,
|
|
3961
|
+
return (0, import_extractor5.ambiguousReading)(
|
|
3905
3962
|
candidates,
|
|
3906
3963
|
"This route returns more than one status depending on which branch runs, and nothing here reads which, so no status is claimed for it",
|
|
3907
3964
|
range
|
|
3908
3965
|
);
|
|
3909
3966
|
}
|
|
3910
|
-
return (0,
|
|
3967
|
+
return (0, import_extractor5.writtenReading)(candidates[0], range);
|
|
3911
3968
|
}
|
|
3912
3969
|
function declaredOrReturnedStatus(declared, returned) {
|
|
3913
3970
|
return declared.kind === "absent" ? returned : declared;
|
|
@@ -3920,19 +3977,19 @@ function defaultedStatus(reading, pattern) {
|
|
|
3920
3977
|
}
|
|
3921
3978
|
function readResponseModel(pattern, classification, module2, ctx) {
|
|
3922
3979
|
if (pattern.responseModelKeyword === void 0) {
|
|
3923
|
-
return
|
|
3980
|
+
return import_extractor5.absentReading;
|
|
3924
3981
|
}
|
|
3925
3982
|
const arg = classification.keywordArgs[pattern.responseModelKeyword];
|
|
3926
3983
|
if (arg === void 0) {
|
|
3927
|
-
return
|
|
3984
|
+
return import_extractor5.absentReading;
|
|
3928
3985
|
}
|
|
3929
3986
|
if (arg.kind === "identifier") {
|
|
3930
|
-
return (0,
|
|
3987
|
+
return (0, import_extractor5.writtenReading)(
|
|
3931
3988
|
shapeFromName(arg.name, module2.moduleScope, ctx),
|
|
3932
3989
|
classification.range
|
|
3933
3990
|
);
|
|
3934
3991
|
}
|
|
3935
|
-
return (0,
|
|
3992
|
+
return (0, import_extractor5.unreadableReading)(
|
|
3936
3993
|
"The response model this route's decorator states is not a name, so the response claims no body shape",
|
|
3937
3994
|
classification.range
|
|
3938
3995
|
);
|
|
@@ -3940,9 +3997,9 @@ function readResponseModel(pattern, classification, module2, ctx) {
|
|
|
3940
3997
|
function readReturnAnnotation(definitionNode, scope, ctx) {
|
|
3941
3998
|
const returnTypeNode = field(definitionNode, "return_type");
|
|
3942
3999
|
if (returnTypeNode === null) {
|
|
3943
|
-
return
|
|
4000
|
+
return import_extractor5.absentReading;
|
|
3944
4001
|
}
|
|
3945
|
-
return (0,
|
|
4002
|
+
return (0, import_extractor5.writtenReading)(
|
|
3946
4003
|
annotationToShape(returnTypeNode, scope, ctx),
|
|
3947
4004
|
rangeOf(returnTypeNode)
|
|
3948
4005
|
);
|
|
@@ -3969,7 +4026,7 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
3969
4026
|
routePath: entry.routePath,
|
|
3970
4027
|
...entry.mount !== void 0 ? { mount: entry.mount } : {},
|
|
3971
4028
|
requestBodyFromAnnotatedClass: pattern.annotatedClassIsRequestBody === true,
|
|
3972
|
-
|
|
4029
|
+
pattern,
|
|
3973
4030
|
responseStatusCalls: pattern.responseStatusCalls ?? [],
|
|
3974
4031
|
facts: options.facts,
|
|
3975
4032
|
injectedCallees: new Set(pattern.injectedParameterCallees ?? []),
|
|
@@ -3982,22 +4039,46 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
3982
4039
|
statusCode: defaultedStatus(
|
|
3983
4040
|
declaredOrReturnedStatus(
|
|
3984
4041
|
readStatusCode(pattern, classification),
|
|
3985
|
-
readReturnedStatus(pattern, functionNode
|
|
4042
|
+
readReturnedStatus(pattern, functionNode, {
|
|
4043
|
+
module: module2,
|
|
4044
|
+
facts: options.facts
|
|
4045
|
+
})
|
|
3986
4046
|
),
|
|
3987
4047
|
pattern
|
|
3988
4048
|
),
|
|
3989
4049
|
definitionsCtx: ctx,
|
|
3990
|
-
storage: options.storage
|
|
4050
|
+
storage: options.storage,
|
|
4051
|
+
wrappers: wrappersAround(
|
|
4052
|
+
pattern,
|
|
4053
|
+
pack,
|
|
4054
|
+
classification,
|
|
4055
|
+
functionNode,
|
|
4056
|
+
module2,
|
|
4057
|
+
options
|
|
4058
|
+
)
|
|
3991
4059
|
},
|
|
3992
4060
|
options
|
|
3993
4061
|
)
|
|
3994
4062
|
);
|
|
3995
4063
|
}
|
|
4064
|
+
function wrappersAround(pattern, pack, classification, definitionNode, module2, options) {
|
|
4065
|
+
if (options.wrappers === void 0) {
|
|
4066
|
+
return [];
|
|
4067
|
+
}
|
|
4068
|
+
return options.wrappers.wrappersFor({
|
|
4069
|
+
pack,
|
|
4070
|
+
pattern,
|
|
4071
|
+
file: options.absoluteFile ?? options.filePath,
|
|
4072
|
+
module: module2,
|
|
4073
|
+
classification,
|
|
4074
|
+
definitionNode
|
|
4075
|
+
});
|
|
4076
|
+
}
|
|
3996
4077
|
function readResponseShape(declared, readAnnotation) {
|
|
3997
4078
|
if (declared.kind === "written") {
|
|
3998
4079
|
return { reading: declared, passedOver: [] };
|
|
3999
4080
|
}
|
|
4000
|
-
return (0,
|
|
4081
|
+
return (0, import_extractor5.firstWrittenReading)([declared, readAnnotation()]);
|
|
4001
4082
|
}
|
|
4002
4083
|
function routeUnitOrAbstention(unitOptions, options) {
|
|
4003
4084
|
try {
|
|
@@ -4037,7 +4118,7 @@ function unbuiltRouteUnit(unitOptions, error) {
|
|
|
4037
4118
|
dependencyCalls: [],
|
|
4038
4119
|
declaredContract: null,
|
|
4039
4120
|
readings: [
|
|
4040
|
-
(0,
|
|
4121
|
+
(0, import_extractor5.unreadableReading)(
|
|
4041
4122
|
`This route could not be read into a unit (${message}), so the binding names no path and nothing pairs with it`,
|
|
4042
4123
|
range
|
|
4043
4124
|
)
|
|
@@ -4052,7 +4133,7 @@ function buildRouteUnit(options) {
|
|
|
4052
4133
|
method,
|
|
4053
4134
|
routePath,
|
|
4054
4135
|
requestBodyFromAnnotatedClass,
|
|
4055
|
-
|
|
4136
|
+
pattern,
|
|
4056
4137
|
injectedCallees,
|
|
4057
4138
|
definitionNode,
|
|
4058
4139
|
enclosingScope,
|
|
@@ -4063,7 +4144,7 @@ function buildRouteUnit(options) {
|
|
|
4063
4144
|
definitionsCtx,
|
|
4064
4145
|
storage: storageLookup
|
|
4065
4146
|
} = options;
|
|
4066
|
-
const template = (0,
|
|
4147
|
+
const template = (0, import_extractor5.valueToReadFurtherFrom)(routePath);
|
|
4067
4148
|
const ctx = definitionsCtx ?? createAnnotationContext(module2.scopeFor);
|
|
4068
4149
|
const parameters = readParameters(
|
|
4069
4150
|
definitionNode,
|
|
@@ -4083,10 +4164,14 @@ function buildRouteUnit(options) {
|
|
|
4083
4164
|
const perTerminal = branchesPerTerminal({
|
|
4084
4165
|
definitionNode,
|
|
4085
4166
|
effects,
|
|
4086
|
-
module: module2,
|
|
4087
|
-
facts: options.facts,
|
|
4088
4167
|
responseStatusCalls: options.responseStatusCalls,
|
|
4089
|
-
ctx: {
|
|
4168
|
+
ctx: {
|
|
4169
|
+
pattern,
|
|
4170
|
+
responseShape,
|
|
4171
|
+
declaredStatus: statusCode,
|
|
4172
|
+
module: module2,
|
|
4173
|
+
facts: options.facts
|
|
4174
|
+
}
|
|
4090
4175
|
});
|
|
4091
4176
|
const branches = (perTerminal ?? []).map(
|
|
4092
4177
|
(branch) => extra.length === 0 ? branch : { ...branch, extraEffects: extra }
|
|
@@ -4145,7 +4230,8 @@ function buildRouteUnit(options) {
|
|
|
4145
4230
|
...responseShape.passedOver
|
|
4146
4231
|
],
|
|
4147
4232
|
...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {},
|
|
4148
|
-
...options.mount !== void 0 ? { mount: options.mount } : {}
|
|
4233
|
+
...options.mount !== void 0 ? { mount: options.mount } : {},
|
|
4234
|
+
...options.wrappers !== void 0 && options.wrappers.length > 0 ? { wrappers: options.wrappers } : {}
|
|
4149
4235
|
};
|
|
4150
4236
|
}
|
|
4151
4237
|
function unreadRoleReadings(parameters, range) {
|
|
@@ -4153,7 +4239,7 @@ function unreadRoleReadings(parameters, range) {
|
|
|
4153
4239
|
return [];
|
|
4154
4240
|
}
|
|
4155
4241
|
return [
|
|
4156
|
-
(0,
|
|
4242
|
+
(0, import_extractor5.unreadableReading)(
|
|
4157
4243
|
"Nothing read this route's path, so its parameters name no role and a path parameter here does not read as one",
|
|
4158
4244
|
range
|
|
4159
4245
|
)
|
|
@@ -4494,12 +4580,12 @@ var import_node_fs3 = __toESM(require("fs"), 1);
|
|
|
4494
4580
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
4495
4581
|
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
4496
4582
|
var import_datalog3 = require("@suss/datalog");
|
|
4497
|
-
var
|
|
4583
|
+
var import_extractor10 = require("@suss/extractor");
|
|
4498
4584
|
|
|
4499
4585
|
// src/diagnostics.ts
|
|
4500
|
-
var
|
|
4586
|
+
var import_extractor6 = require("@suss/extractor");
|
|
4501
4587
|
function buildPythonExtractionReport(args) {
|
|
4502
|
-
return (0,
|
|
4588
|
+
return (0, import_extractor6.buildUngatedExtractionReport)({
|
|
4503
4589
|
packs: args.packs.map((pack) => ({
|
|
4504
4590
|
name: pack.name,
|
|
4505
4591
|
version: pack.version ?? null,
|
|
@@ -4514,7 +4600,7 @@ function buildPythonExtractionReport(args) {
|
|
|
4514
4600
|
// src/reach/closure.ts
|
|
4515
4601
|
var import_behavioral_ir3 = require("@suss/behavioral-ir");
|
|
4516
4602
|
var import_datalog2 = require("@suss/datalog");
|
|
4517
|
-
var
|
|
4603
|
+
var import_extractor7 = require("@suss/extractor");
|
|
4518
4604
|
|
|
4519
4605
|
// src/reach/resolveCallee.ts
|
|
4520
4606
|
var stop = (reason) => ({ kind: "stop", reason });
|
|
@@ -4839,7 +4925,7 @@ function reachedFunctions(seeds, options) {
|
|
|
4839
4925
|
if (seedKeys.has(key) || target === void 0) {
|
|
4840
4926
|
continue;
|
|
4841
4927
|
}
|
|
4842
|
-
const summary = (0,
|
|
4928
|
+
const summary = (0, import_extractor7.assembleSummary)(libraryUnit(target, options), {
|
|
4843
4929
|
gapHandling: options.gapHandling
|
|
4844
4930
|
});
|
|
4845
4931
|
summary.confidence = { source: "inferred_static", level: "low" };
|
|
@@ -4959,7 +5045,7 @@ function scanBody(source, ctx, recognized) {
|
|
|
4959
5045
|
followed.push(outcome.target);
|
|
4960
5046
|
}
|
|
4961
5047
|
};
|
|
4962
|
-
(0,
|
|
5048
|
+
(0, import_extractor7.walkDescendants)(
|
|
4963
5049
|
body,
|
|
4964
5050
|
{ scope: scopeAt2(file, node), rebound: reboundNames(body) },
|
|
4965
5051
|
{
|
|
@@ -4970,7 +5056,7 @@ function scanBody(source, ctx, recognized) {
|
|
|
4970
5056
|
},
|
|
4971
5057
|
into: (child, where) => {
|
|
4972
5058
|
if (child.type === "function_definition") {
|
|
4973
|
-
return
|
|
5059
|
+
return import_extractor7.SKIP_CHILDREN;
|
|
4974
5060
|
}
|
|
4975
5061
|
if (child.type === "lambda") {
|
|
4976
5062
|
return {
|
|
@@ -5015,7 +5101,7 @@ var REBINDING_FIELDS = {
|
|
|
5015
5101
|
};
|
|
5016
5102
|
function reboundNames(body) {
|
|
5017
5103
|
const names = /* @__PURE__ */ new Set();
|
|
5018
|
-
(0,
|
|
5104
|
+
(0, import_extractor7.walkDescendants)(body, null, {
|
|
5019
5105
|
at: (node) => {
|
|
5020
5106
|
const target = REBINDING_FIELDS[node.type];
|
|
5021
5107
|
if (target === void 0 || boundByBinder(node, body)) {
|
|
@@ -5028,7 +5114,7 @@ function reboundNames(body) {
|
|
|
5028
5114
|
}
|
|
5029
5115
|
}
|
|
5030
5116
|
},
|
|
5031
|
-
into: (node) => node.type === "function_definition" ?
|
|
5117
|
+
into: (node) => node.type === "function_definition" ? import_extractor7.SKIP_CHILDREN : null
|
|
5032
5118
|
});
|
|
5033
5119
|
return names;
|
|
5034
5120
|
}
|
|
@@ -5193,12 +5279,8 @@ function buildRouterIndex(files, packs, resolverOptions) {
|
|
|
5193
5279
|
}
|
|
5194
5280
|
return {
|
|
5195
5281
|
moduleDef(fromFile, spec, name) {
|
|
5196
|
-
const
|
|
5197
|
-
if (
|
|
5198
|
-
return null;
|
|
5199
|
-
}
|
|
5200
|
-
const bound = byFile.get(resolution.file);
|
|
5201
|
-
if (bound === void 0) {
|
|
5282
|
+
const bound = boundModuleAt(fromFile, spec, byFile, resolverOptions);
|
|
5283
|
+
if (bound === null) {
|
|
5202
5284
|
return null;
|
|
5203
5285
|
}
|
|
5204
5286
|
const binding = bound.module.moduleScope.bindings.get(name);
|
|
@@ -5224,12 +5306,12 @@ function buildRouterIndex(files, packs, resolverOptions) {
|
|
|
5224
5306
|
}
|
|
5225
5307
|
return composedPrefixOf(index, construction, displayPaths.get(module2));
|
|
5226
5308
|
},
|
|
5227
|
-
resolveConstruction(pattern, module2, constructorName,
|
|
5309
|
+
resolveConstruction(pattern, module2, constructorName, constructionKey2) {
|
|
5228
5310
|
const index = byPattern.get(pattern);
|
|
5229
5311
|
if (index === void 0) {
|
|
5230
5312
|
return NOT_ROUTER;
|
|
5231
5313
|
}
|
|
5232
|
-
const construction = index.byValueKey.get(
|
|
5314
|
+
const construction = index.byValueKey.get(constructionKey2);
|
|
5233
5315
|
if (construction !== void 0) {
|
|
5234
5316
|
return composedPrefixOf(index, construction, displayPaths.get(module2));
|
|
5235
5317
|
}
|
|
@@ -5465,6 +5547,13 @@ function buildPatternIndex(files, importModule, composition, resolverOptions) {
|
|
|
5465
5547
|
}
|
|
5466
5548
|
return index;
|
|
5467
5549
|
}
|
|
5550
|
+
function boundModuleAt(fromFile, spec, byFile, resolverOptions) {
|
|
5551
|
+
const resolution = resolveModule(fromFile, spec, resolverOptions);
|
|
5552
|
+
if (resolution.status !== "resolved") {
|
|
5553
|
+
return null;
|
|
5554
|
+
}
|
|
5555
|
+
return byFile.get(resolution.file) ?? null;
|
|
5556
|
+
}
|
|
5468
5557
|
function constructionOf(name, scope, importModule) {
|
|
5469
5558
|
const binding = resolveName(scope, name);
|
|
5470
5559
|
if (binding?.kind !== "assignment" || binding.value?.type !== "call") {
|
|
@@ -5673,16 +5762,13 @@ function constructionNamed(name, scope, scan, constructions = scan.index.constru
|
|
|
5673
5762
|
if (binding.kind !== "importFrom") {
|
|
5674
5763
|
return null;
|
|
5675
5764
|
}
|
|
5676
|
-
const
|
|
5765
|
+
const target = boundModuleAt(
|
|
5677
5766
|
scan.bound.file,
|
|
5678
5767
|
{ module: binding.module, relativeLevel: binding.relativeLevel },
|
|
5768
|
+
scan.byFile,
|
|
5679
5769
|
scan.resolverOptions
|
|
5680
5770
|
);
|
|
5681
|
-
if (
|
|
5682
|
-
return null;
|
|
5683
|
-
}
|
|
5684
|
-
const target = scan.byFile.get(resolution.file);
|
|
5685
|
-
if (target === void 0) {
|
|
5771
|
+
if (target === null) {
|
|
5686
5772
|
return null;
|
|
5687
5773
|
}
|
|
5688
5774
|
return constructions.get(target.module)?.get(binding.importedName) ?? null;
|
|
@@ -5700,10 +5786,10 @@ function constructionThroughFacts(name, scope, scan) {
|
|
|
5700
5786
|
return null;
|
|
5701
5787
|
}
|
|
5702
5788
|
const nameKey = `${scan.bound.file}#${name}`;
|
|
5703
|
-
const
|
|
5789
|
+
const constructionKey2 = subjectConstructions(facts, [nameKey]).get(
|
|
5704
5790
|
nameKey
|
|
5705
5791
|
)?.constructionKey;
|
|
5706
|
-
return
|
|
5792
|
+
return constructionKey2 === void 0 ? null : scan.index.byValueKey.get(constructionKey2) ?? null;
|
|
5707
5793
|
}
|
|
5708
5794
|
var MOUNT_STATE_BY_EFFECT = {
|
|
5709
5795
|
prefixes: (statedPrefix, site) => ({
|
|
@@ -5940,12 +6026,13 @@ function constructionThroughModule(arg, scope, scan) {
|
|
|
5940
6026
|
if (spec === null) {
|
|
5941
6027
|
return null;
|
|
5942
6028
|
}
|
|
5943
|
-
const
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
6029
|
+
const target = boundModuleAt(
|
|
6030
|
+
scan.bound.file,
|
|
6031
|
+
spec,
|
|
6032
|
+
scan.byFile,
|
|
6033
|
+
scan.resolverOptions
|
|
6034
|
+
);
|
|
6035
|
+
if (target === null) {
|
|
5949
6036
|
return null;
|
|
5950
6037
|
}
|
|
5951
6038
|
return scan.index.constructions.get(target.module)?.get(arg.attributeName) ?? null;
|
|
@@ -6289,13 +6376,479 @@ function carrierPrefix(carrier, constructorArg, objectName, scope, scan) {
|
|
|
6289
6376
|
}
|
|
6290
6377
|
|
|
6291
6378
|
// src/version.ts
|
|
6292
|
-
var
|
|
6379
|
+
var import_extractor8 = require("@suss/extractor");
|
|
6293
6380
|
var ADAPTER_VERSION = "0.1.0";
|
|
6294
|
-
var adapterStamp = (0,
|
|
6381
|
+
var adapterStamp = (0, import_extractor8.createAdapterStamp)({
|
|
6295
6382
|
moduleUrl: importMetaUrl,
|
|
6296
6383
|
version: ADAPTER_VERSION
|
|
6297
6384
|
});
|
|
6298
6385
|
|
|
6386
|
+
// src/wrappers.ts
|
|
6387
|
+
var import_extractor9 = require("@suss/extractor");
|
|
6388
|
+
function buildWrapperIndex(files, options) {
|
|
6389
|
+
const forms = declaredForms(options.packs);
|
|
6390
|
+
const filesByPath = new Map(files.map((file) => [file.file, file]));
|
|
6391
|
+
const index = new PythonWrapperIndex(options, filesByPath);
|
|
6392
|
+
if (forms.length > 0) {
|
|
6393
|
+
for (const file of files) {
|
|
6394
|
+
for (const declared of forms) {
|
|
6395
|
+
registerFrom(file, declared, index);
|
|
6396
|
+
}
|
|
6397
|
+
}
|
|
6398
|
+
}
|
|
6399
|
+
return index;
|
|
6400
|
+
}
|
|
6401
|
+
function declaredForms(packs) {
|
|
6402
|
+
return packs.flatMap(
|
|
6403
|
+
(pack) => pack.discovery.flatMap(
|
|
6404
|
+
(pattern) => (pattern.wrappers ?? []).map((form) => ({ pack, pattern, form }))
|
|
6405
|
+
)
|
|
6406
|
+
);
|
|
6407
|
+
}
|
|
6408
|
+
var PythonWrapperIndex = class {
|
|
6409
|
+
constructor(options, filesByPath) {
|
|
6410
|
+
this.options = options;
|
|
6411
|
+
this.filesByPath = filesByPath;
|
|
6412
|
+
}
|
|
6413
|
+
options;
|
|
6414
|
+
filesByPath;
|
|
6415
|
+
/** By pack name: what the app registered, in the order the forms are declared and then the order the files were read. */
|
|
6416
|
+
everyRoute = /* @__PURE__ */ new Map();
|
|
6417
|
+
/** By construction key: what a router or a blueprint registered. */
|
|
6418
|
+
ownRoutes = /* @__PURE__ */ new Map();
|
|
6419
|
+
unitsByKey = /* @__PURE__ */ new Map();
|
|
6420
|
+
unitsByFile = /* @__PURE__ */ new Map();
|
|
6421
|
+
register(covers, target, declared) {
|
|
6422
|
+
const registered = this.registered(target, declared);
|
|
6423
|
+
const table = covers.kind === "everyRoute" ? this.everyRoute : this.ownRoutes;
|
|
6424
|
+
const key = covers.kind === "everyRoute" ? covers.pack : covers.key;
|
|
6425
|
+
const list = table.get(key) ?? [];
|
|
6426
|
+
list.push(registered);
|
|
6427
|
+
table.set(key, list);
|
|
6428
|
+
}
|
|
6429
|
+
/** The unit for a function, built once however many registrations point at it. */
|
|
6430
|
+
registered(target, declared) {
|
|
6431
|
+
const span = spanOf(target.node);
|
|
6432
|
+
const key = `${target.file.file}:${span.start}-${span.end}`;
|
|
6433
|
+
if (!this.unitsByKey.has(key)) {
|
|
6434
|
+
const unit = wrapperUnit(target, declared, this.options);
|
|
6435
|
+
this.unitsByKey.set(key, unit);
|
|
6436
|
+
const inFile = this.unitsByFile.get(target.file.file) ?? [];
|
|
6437
|
+
inFile.push(unit);
|
|
6438
|
+
this.unitsByFile.set(target.file.file, inFile);
|
|
6439
|
+
}
|
|
6440
|
+
return {
|
|
6441
|
+
reference: {
|
|
6442
|
+
file: target.file.displayPath,
|
|
6443
|
+
name: target.name,
|
|
6444
|
+
...isThrowForm(declared.form) ? { onThrow: true } : {}
|
|
6445
|
+
},
|
|
6446
|
+
form: declared.form
|
|
6447
|
+
};
|
|
6448
|
+
}
|
|
6449
|
+
wrappersFor(query) {
|
|
6450
|
+
const file = this.filesByPath.get(query.file);
|
|
6451
|
+
const forms = (query.pattern.wrappers ?? []).map((form) => ({
|
|
6452
|
+
pack: query.pack,
|
|
6453
|
+
pattern: query.pattern,
|
|
6454
|
+
form
|
|
6455
|
+
}));
|
|
6456
|
+
if (file === void 0 || forms.length === 0) {
|
|
6457
|
+
return [];
|
|
6458
|
+
}
|
|
6459
|
+
const found = [
|
|
6460
|
+
...this.everyRoute.get(query.pack.name) ?? [],
|
|
6461
|
+
...this.ownRoutesOf(query)
|
|
6462
|
+
];
|
|
6463
|
+
for (const declared of forms) {
|
|
6464
|
+
if (declared.form.type !== "dependency") {
|
|
6465
|
+
continue;
|
|
6466
|
+
}
|
|
6467
|
+
const site = {
|
|
6468
|
+
file,
|
|
6469
|
+
scope: query.module.moduleScope,
|
|
6470
|
+
rebound: /* @__PURE__ */ new Set()
|
|
6471
|
+
};
|
|
6472
|
+
const targets = [
|
|
6473
|
+
...decoratorDependencies(query.classification, declared.form),
|
|
6474
|
+
...parameterDependencies(query.definitionNode, declared.form)
|
|
6475
|
+
];
|
|
6476
|
+
for (const name of targets) {
|
|
6477
|
+
const target = resolveNamedFunctionArgument(name, site, {
|
|
6478
|
+
filesByPath: this.filesByPath,
|
|
6479
|
+
roots: this.options.roots
|
|
6480
|
+
});
|
|
6481
|
+
if (target !== null) {
|
|
6482
|
+
found.push(this.registered(target, declared));
|
|
6483
|
+
}
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6487
|
+
const ordered = [];
|
|
6488
|
+
for (const wrapper of [...found].sort(
|
|
6489
|
+
(a, b) => runOrder(a.form) - runOrder(b.form)
|
|
6490
|
+
)) {
|
|
6491
|
+
const key = `${wrapper.reference.file}::${wrapper.reference.name}::${wrapper.reference.onThrow === true}`;
|
|
6492
|
+
if (seen.has(key)) {
|
|
6493
|
+
continue;
|
|
6494
|
+
}
|
|
6495
|
+
seen.add(key);
|
|
6496
|
+
ordered.push(wrapper.reference);
|
|
6497
|
+
}
|
|
6498
|
+
return ordered;
|
|
6499
|
+
}
|
|
6500
|
+
ownRoutesOf(query) {
|
|
6501
|
+
const site = this.objectSiteOf(query);
|
|
6502
|
+
if (site === null) {
|
|
6503
|
+
return [];
|
|
6504
|
+
}
|
|
6505
|
+
for (const form of query.pattern.wrappers ?? []) {
|
|
6506
|
+
const match = registrarOf(site.name, site.scope, {
|
|
6507
|
+
pack: query.pack,
|
|
6508
|
+
pattern: query.pattern,
|
|
6509
|
+
form
|
|
6510
|
+
});
|
|
6511
|
+
if (match !== null && match.registrar.covers === "ownRoutes") {
|
|
6512
|
+
return this.ownRoutes.get(constructionKey(site.file, match.call)) ?? [];
|
|
6513
|
+
}
|
|
6514
|
+
}
|
|
6515
|
+
return [];
|
|
6516
|
+
}
|
|
6517
|
+
/**
|
|
6518
|
+
* Where the decorator's object was built: the route's own file, the file
|
|
6519
|
+
* a project wrapper function is written in, or the file an imported
|
|
6520
|
+
* router comes from. The name is the one that file binds it under.
|
|
6521
|
+
*/
|
|
6522
|
+
objectSiteOf(query) {
|
|
6523
|
+
const name = query.classification.objectName;
|
|
6524
|
+
if (name === null) {
|
|
6525
|
+
return null;
|
|
6526
|
+
}
|
|
6527
|
+
const wrapperModule = query.classification.objectModule;
|
|
6528
|
+
if (wrapperModule !== void 0) {
|
|
6529
|
+
const file = this.fileOfModule(wrapperModule);
|
|
6530
|
+
return file === null ? null : { file, scope: wrapperModule.moduleScope, name };
|
|
6531
|
+
}
|
|
6532
|
+
const binding = resolveName(query.module.moduleScope, name);
|
|
6533
|
+
if (binding?.kind !== "importFrom") {
|
|
6534
|
+
return { file: query.file, scope: query.module.moduleScope, name };
|
|
6535
|
+
}
|
|
6536
|
+
const target = boundModuleAt(
|
|
6537
|
+
query.file,
|
|
6538
|
+
{ module: binding.module, relativeLevel: binding.relativeLevel },
|
|
6539
|
+
this.filesByPath,
|
|
6540
|
+
{ roots: this.options.roots }
|
|
6541
|
+
);
|
|
6542
|
+
return target === null ? null : {
|
|
6543
|
+
file: target.file,
|
|
6544
|
+
scope: target.module.moduleScope,
|
|
6545
|
+
name: binding.importedName
|
|
6546
|
+
};
|
|
6547
|
+
}
|
|
6548
|
+
fileOfModule(module2) {
|
|
6549
|
+
for (const file of this.filesByPath.values()) {
|
|
6550
|
+
if (file.module === module2) {
|
|
6551
|
+
return file.file;
|
|
6552
|
+
}
|
|
6553
|
+
}
|
|
6554
|
+
return null;
|
|
6555
|
+
}
|
|
6556
|
+
unitsIn(file) {
|
|
6557
|
+
return this.unitsByFile.get(file) ?? [];
|
|
6558
|
+
}
|
|
6559
|
+
};
|
|
6560
|
+
function isThrowForm(form) {
|
|
6561
|
+
return form.type === "decoratedWrapper" && form.throwParam !== void 0;
|
|
6562
|
+
}
|
|
6563
|
+
function runOrder(form) {
|
|
6564
|
+
if (isThrowForm(form)) {
|
|
6565
|
+
return 2;
|
|
6566
|
+
}
|
|
6567
|
+
return form.type === "decoratedWrapper" ? 0 : 1;
|
|
6568
|
+
}
|
|
6569
|
+
function registrarOf(name, scope, declared) {
|
|
6570
|
+
const modules = [
|
|
6571
|
+
...declared.pattern.importModule,
|
|
6572
|
+
...declared.form.registrars.flatMap(
|
|
6573
|
+
(registrar2) => registrar2.importModule ?? []
|
|
6574
|
+
)
|
|
6575
|
+
];
|
|
6576
|
+
const construction = constructionOf(name, scope, modules);
|
|
6577
|
+
if (construction === null) {
|
|
6578
|
+
return null;
|
|
6579
|
+
}
|
|
6580
|
+
const registrar = declared.form.registrars.find(
|
|
6581
|
+
(candidate) => candidate.constructorName === construction.constructorName
|
|
6582
|
+
);
|
|
6583
|
+
return registrar === void 0 ? null : { registrar, call: construction.call };
|
|
6584
|
+
}
|
|
6585
|
+
function constructionKey(file, call) {
|
|
6586
|
+
return `${file}#${call.startIndex}`;
|
|
6587
|
+
}
|
|
6588
|
+
function registerFrom(file, declared, index) {
|
|
6589
|
+
const table = {
|
|
6590
|
+
dependency: () => registerConstructorDependencies(
|
|
6591
|
+
file,
|
|
6592
|
+
declared,
|
|
6593
|
+
declared.form,
|
|
6594
|
+
index
|
|
6595
|
+
),
|
|
6596
|
+
decoratedWrapper: () => registerDecorated(
|
|
6597
|
+
file,
|
|
6598
|
+
declared,
|
|
6599
|
+
declared.form,
|
|
6600
|
+
index
|
|
6601
|
+
)
|
|
6602
|
+
};
|
|
6603
|
+
table[declared.form.type]();
|
|
6604
|
+
}
|
|
6605
|
+
function registerConstructorDependencies(file, declared, form, index) {
|
|
6606
|
+
const scope = file.module.moduleScope;
|
|
6607
|
+
for (const stmt of file.root.namedChildren) {
|
|
6608
|
+
const assignment2 = stmt?.type === "expression_statement" ? stmt.namedChildren.find((child) => child?.type === "assignment") : void 0;
|
|
6609
|
+
const left = assignment2 === void 0 || assignment2 === null ? null : field(assignment2, "left");
|
|
6610
|
+
if (left?.type !== "identifier") {
|
|
6611
|
+
continue;
|
|
6612
|
+
}
|
|
6613
|
+
const match = registrarOf(left.text, scope, declared);
|
|
6614
|
+
if (match === null) {
|
|
6615
|
+
continue;
|
|
6616
|
+
}
|
|
6617
|
+
const { keywordArgs } = readCallArguments(field(match.call, "arguments"));
|
|
6618
|
+
const listed = keywordArgs[form.keyword];
|
|
6619
|
+
if (listed === void 0) {
|
|
6620
|
+
continue;
|
|
6621
|
+
}
|
|
6622
|
+
const site = { file, scope, rebound: /* @__PURE__ */ new Set() };
|
|
6623
|
+
for (const name of dependencyNamesIn(listed.node, form)) {
|
|
6624
|
+
const target = resolveNamedFunctionArgument(name, site, {
|
|
6625
|
+
filesByPath: index.filesByPath,
|
|
6626
|
+
roots: index.options.roots
|
|
6627
|
+
});
|
|
6628
|
+
if (target !== null) {
|
|
6629
|
+
index.register(
|
|
6630
|
+
coverageOf(match, file, declared.pack),
|
|
6631
|
+
target,
|
|
6632
|
+
declared
|
|
6633
|
+
);
|
|
6634
|
+
}
|
|
6635
|
+
}
|
|
6636
|
+
}
|
|
6637
|
+
}
|
|
6638
|
+
function coverageOf(match, file, pack) {
|
|
6639
|
+
return match.registrar.covers === "everyRoute" ? { kind: "everyRoute", pack: pack.name } : { kind: "ownRoutes", key: constructionKey(file.file, match.call) };
|
|
6640
|
+
}
|
|
6641
|
+
function registerDecorated(file, declared, form, index) {
|
|
6642
|
+
(0, import_extractor9.walkDescendants)(file.root, file.module.moduleScope, {
|
|
6643
|
+
at: (node, scope) => {
|
|
6644
|
+
if (node.type !== "decorated_definition") {
|
|
6645
|
+
return;
|
|
6646
|
+
}
|
|
6647
|
+
const { definition, decorators } = stripDecorators(node);
|
|
6648
|
+
if (definition.type !== "function_definition") {
|
|
6649
|
+
return;
|
|
6650
|
+
}
|
|
6651
|
+
for (const decorator of decorators) {
|
|
6652
|
+
const receiver = decoratorReceiver(decorator);
|
|
6653
|
+
if (receiver === null || receiver.attributeName !== form.attribute || receiver.object.type !== "identifier") {
|
|
6654
|
+
continue;
|
|
6655
|
+
}
|
|
6656
|
+
const match = registrarOf(receiver.object.text, scope, declared);
|
|
6657
|
+
const name = field(definition, "name")?.text;
|
|
6658
|
+
if (match === null || name === void 0) {
|
|
6659
|
+
continue;
|
|
6660
|
+
}
|
|
6661
|
+
index.register(
|
|
6662
|
+
coverageOf(match, file, declared.pack),
|
|
6663
|
+
{ file, node: definition, name, exportPath: [name] },
|
|
6664
|
+
declared
|
|
6665
|
+
);
|
|
6666
|
+
}
|
|
6667
|
+
},
|
|
6668
|
+
into: (node, scope) => file.module.scopeFor.get(node.id) ?? scope
|
|
6669
|
+
});
|
|
6670
|
+
}
|
|
6671
|
+
function dependencyNamesIn(node, form) {
|
|
6672
|
+
const calls = node.type === "list" ? node.namedChildren : [node];
|
|
6673
|
+
const names = [];
|
|
6674
|
+
for (const call of calls) {
|
|
6675
|
+
const name = call === null ? null : dependencyNameOf(call, form);
|
|
6676
|
+
if (name !== null) {
|
|
6677
|
+
names.push(name);
|
|
6678
|
+
}
|
|
6679
|
+
}
|
|
6680
|
+
return names;
|
|
6681
|
+
}
|
|
6682
|
+
function dependencyNameOf(node, form) {
|
|
6683
|
+
if (node.type !== "call") {
|
|
6684
|
+
return null;
|
|
6685
|
+
}
|
|
6686
|
+
const callee = field(node, "function");
|
|
6687
|
+
const calleeName3 = callee?.type === "identifier" ? callee.text : callee?.type === "attribute" ? field(callee, "attribute")?.text ?? null : null;
|
|
6688
|
+
if (calleeName3 === null || !form.callees.includes(calleeName3)) {
|
|
6689
|
+
return null;
|
|
6690
|
+
}
|
|
6691
|
+
const first = field(node, "arguments")?.namedChildren[0];
|
|
6692
|
+
return first?.type === "identifier" ? first.text : null;
|
|
6693
|
+
}
|
|
6694
|
+
function decoratorDependencies(classification, form) {
|
|
6695
|
+
const listed = classification.keywordArgs[form.keyword];
|
|
6696
|
+
return listed === void 0 ? [] : dependencyNamesIn(listed.node, form);
|
|
6697
|
+
}
|
|
6698
|
+
var MAX_ANNOTATION_DEPTH2 = 6;
|
|
6699
|
+
function parameterDependencies(definitionNode, form) {
|
|
6700
|
+
const names = [];
|
|
6701
|
+
const findIn = (node, depth) => {
|
|
6702
|
+
if (node === null || depth > MAX_ANNOTATION_DEPTH2) {
|
|
6703
|
+
return null;
|
|
6704
|
+
}
|
|
6705
|
+
const direct = dependencyNameOf(node, form);
|
|
6706
|
+
if (direct !== null) {
|
|
6707
|
+
return direct;
|
|
6708
|
+
}
|
|
6709
|
+
for (const child of node.namedChildren) {
|
|
6710
|
+
const found = findIn(child, depth + 1);
|
|
6711
|
+
if (found !== null) {
|
|
6712
|
+
return found;
|
|
6713
|
+
}
|
|
6714
|
+
}
|
|
6715
|
+
return null;
|
|
6716
|
+
};
|
|
6717
|
+
for (const param of field(definitionNode, "parameters")?.namedChildren ?? []) {
|
|
6718
|
+
if (param === null) {
|
|
6719
|
+
continue;
|
|
6720
|
+
}
|
|
6721
|
+
const inDefault = field(param, "value");
|
|
6722
|
+
const found = inDefault === null ? findIn(field(param, "type"), 0) : dependencyNameOf(inDefault, form);
|
|
6723
|
+
if (found !== null) {
|
|
6724
|
+
names.push(found);
|
|
6725
|
+
}
|
|
6726
|
+
}
|
|
6727
|
+
return names;
|
|
6728
|
+
}
|
|
6729
|
+
function wrapperUnit(target, declared, options) {
|
|
6730
|
+
const { file, node, name, exportPath } = target;
|
|
6731
|
+
const body = field(node, "body");
|
|
6732
|
+
const range = rangeOf(node);
|
|
6733
|
+
const raised = raisedResponses(body, {
|
|
6734
|
+
calls: declared.pattern.responseStatusCalls ?? [],
|
|
6735
|
+
module: file.module,
|
|
6736
|
+
facts: options.facts
|
|
6737
|
+
});
|
|
6738
|
+
const continuations = continuationStatements(node, declared.form);
|
|
6739
|
+
const terminals = bodyTerminals(body, raised, continuations);
|
|
6740
|
+
const effects = invocationEffects(node);
|
|
6741
|
+
const extra = recognizedBodyEffects(
|
|
6742
|
+
node,
|
|
6743
|
+
file.module,
|
|
6744
|
+
options.storageFor(file)
|
|
6745
|
+
);
|
|
6746
|
+
const delegate = (at) => ({
|
|
6747
|
+
terminal: {
|
|
6748
|
+
kind: "delegate",
|
|
6749
|
+
statusCode: null,
|
|
6750
|
+
body: null,
|
|
6751
|
+
exceptionType: null,
|
|
6752
|
+
message: null,
|
|
6753
|
+
component: null,
|
|
6754
|
+
renderTree: null,
|
|
6755
|
+
delegateTarget: null,
|
|
6756
|
+
emitEvent: null,
|
|
6757
|
+
location: rangeOf(at)
|
|
6758
|
+
},
|
|
6759
|
+
location: rangeOf(at)
|
|
6760
|
+
});
|
|
6761
|
+
const respond = (statement) => returnBranch(statement, {
|
|
6762
|
+
pattern: declared.pattern,
|
|
6763
|
+
responseShape: { reading: import_extractor9.absentReading },
|
|
6764
|
+
declaredStatus: {
|
|
6765
|
+
reading: import_extractor9.absentReading,
|
|
6766
|
+
...declared.pattern.defaultStatusCode !== void 0 ? { libraryDefault: declared.pattern.defaultStatusCode } : {}
|
|
6767
|
+
},
|
|
6768
|
+
module: file.module,
|
|
6769
|
+
facts: options.facts
|
|
6770
|
+
});
|
|
6771
|
+
const branchOf = (terminal) => {
|
|
6772
|
+
if (terminal.type === "raise") {
|
|
6773
|
+
return {
|
|
6774
|
+
terminal: terminal.terminal,
|
|
6775
|
+
location: rangeOf(terminal.statement)
|
|
6776
|
+
};
|
|
6777
|
+
}
|
|
6778
|
+
if (terminal.type === "continuation" || returnHandsOn(terminal.statement, declared.form)) {
|
|
6779
|
+
return delegate(terminal.statement);
|
|
6780
|
+
}
|
|
6781
|
+
return respond(terminal.statement);
|
|
6782
|
+
};
|
|
6783
|
+
const branches = enumerateBodyBranches({
|
|
6784
|
+
body,
|
|
6785
|
+
terminals,
|
|
6786
|
+
raised,
|
|
6787
|
+
effects,
|
|
6788
|
+
branchOf,
|
|
6789
|
+
fallthrough: delegate(node)
|
|
6790
|
+
}).map(
|
|
6791
|
+
(branch) => extra.length === 0 ? branch : { ...branch, extraEffects: extra }
|
|
6792
|
+
);
|
|
6793
|
+
return {
|
|
6794
|
+
identity: {
|
|
6795
|
+
name,
|
|
6796
|
+
nameKind: "binding",
|
|
6797
|
+
kind: "middleware",
|
|
6798
|
+
file: file.displayPath,
|
|
6799
|
+
range,
|
|
6800
|
+
span: spanOf(node),
|
|
6801
|
+
exportName: exportPath[0] ?? name,
|
|
6802
|
+
exportPath
|
|
6803
|
+
},
|
|
6804
|
+
boundaryBinding: null,
|
|
6805
|
+
parameters: [],
|
|
6806
|
+
branches,
|
|
6807
|
+
bodyContent: body === null ? "absent" : bodyContentOf(body),
|
|
6808
|
+
dependencyCalls: [],
|
|
6809
|
+
declaredContract: null
|
|
6810
|
+
};
|
|
6811
|
+
}
|
|
6812
|
+
function returnHandsOn(statement, form) {
|
|
6813
|
+
if (form.type === "dependency") {
|
|
6814
|
+
return true;
|
|
6815
|
+
}
|
|
6816
|
+
if (form.continuationParam !== void 0 || form.throwParam !== void 0) {
|
|
6817
|
+
return false;
|
|
6818
|
+
}
|
|
6819
|
+
if (form.returnedValueResponds === true) {
|
|
6820
|
+
const returned = statement.namedChildren[0];
|
|
6821
|
+
return returned === void 0 || returned === null || returned.type === "none";
|
|
6822
|
+
}
|
|
6823
|
+
return true;
|
|
6824
|
+
}
|
|
6825
|
+
function continuationStatements(node, form) {
|
|
6826
|
+
if (form.type !== "decoratedWrapper" || form.continuationParam === void 0) {
|
|
6827
|
+
return [];
|
|
6828
|
+
}
|
|
6829
|
+
const params = (field(node, "parameters")?.namedChildren ?? []).filter(
|
|
6830
|
+
(param2) => param2 !== null
|
|
6831
|
+
);
|
|
6832
|
+
const param = params[form.continuationParam];
|
|
6833
|
+
const continuation = param === void 0 ? null : field(param, "name")?.text ?? (param.type === "identifier" ? param.text : null);
|
|
6834
|
+
if (continuation === null) {
|
|
6835
|
+
return [];
|
|
6836
|
+
}
|
|
6837
|
+
const body = field(node, "body");
|
|
6838
|
+
if (body === null) {
|
|
6839
|
+
return [];
|
|
6840
|
+
}
|
|
6841
|
+
const found = [];
|
|
6842
|
+
for (const call of bodyCalls(body)) {
|
|
6843
|
+
const callee = field(call, "function");
|
|
6844
|
+
const statement = callee?.type === "identifier" && callee.text === continuation ? enclosingStatement(call, body) : null;
|
|
6845
|
+
if (statement !== null) {
|
|
6846
|
+
found.push(statement);
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6849
|
+
return found;
|
|
6850
|
+
}
|
|
6851
|
+
|
|
6299
6852
|
// src/project.ts
|
|
6300
6853
|
function reportUnresolvedProjectModules(options, db) {
|
|
6301
6854
|
const imported = new Set(db.facts("pyImport").map((row) => String(row[1])));
|
|
@@ -6312,11 +6865,11 @@ function reportUnresolvedProjectModules(options, db) {
|
|
|
6312
6865
|
}
|
|
6313
6866
|
}
|
|
6314
6867
|
async function extractPythonProject(options) {
|
|
6315
|
-
const timer = options.onTiming !== void 0 ? (0,
|
|
6868
|
+
const timer = options.onTiming !== void 0 ? (0, import_extractor10.createTimer)() : (0, import_extractor10.noopTimer)();
|
|
6316
6869
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
6317
6870
|
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? import_node_path3.default.join(options.projectRoot, ".suss", "cache") : null)
|
|
6318
6871
|
);
|
|
6319
|
-
const cache = (0,
|
|
6872
|
+
const cache = (0, import_extractor10.createCacheLayer)(cacheDir);
|
|
6320
6873
|
const packsDigest = adapterStamp.packsDigest(
|
|
6321
6874
|
options.packs.map(
|
|
6322
6875
|
(pack) => pack.version !== void 0 ? { name: pack.name, version: pack.version } : { name: pack.name }
|
|
@@ -6324,7 +6877,7 @@ async function extractPythonProject(options) {
|
|
|
6324
6877
|
);
|
|
6325
6878
|
const cacheInput = {
|
|
6326
6879
|
files: cacheDir === null ? [] : options.files,
|
|
6327
|
-
adapterPacksDigest: cacheDir === null ? packsDigest : (0,
|
|
6880
|
+
adapterPacksDigest: cacheDir === null ? packsDigest : (0, import_extractor10.runDigest)(packsDigest, options.packs, options.files)
|
|
6328
6881
|
};
|
|
6329
6882
|
const lookup = await timer.timeAsync(
|
|
6330
6883
|
"cache.lookup",
|
|
@@ -6338,7 +6891,7 @@ async function extractPythonProject(options) {
|
|
|
6338
6891
|
const db = new import_datalog3.Database();
|
|
6339
6892
|
const summaries = [];
|
|
6340
6893
|
const gapHandling = options.gapHandling ?? "permissive";
|
|
6341
|
-
const tallies = (0,
|
|
6894
|
+
const tallies = (0, import_extractor6.createPackTallies)(options.packs);
|
|
6342
6895
|
const displayPathOf = (file) => options.workspaceRoot !== void 0 ? import_node_path3.default.relative(options.workspaceRoot, file) : file;
|
|
6343
6896
|
const bound = [];
|
|
6344
6897
|
for (const file of options.files) {
|
|
@@ -6393,33 +6946,52 @@ async function extractPythonProject(options) {
|
|
|
6393
6946
|
couldMatch,
|
|
6394
6947
|
rawSql: rawSqlPatterns
|
|
6395
6948
|
} : void 0;
|
|
6396
|
-
const
|
|
6397
|
-
|
|
6949
|
+
const wrapperIndex = timer.time(
|
|
6950
|
+
"discover",
|
|
6951
|
+
() => buildWrapperIndex(bound, {
|
|
6952
|
+
packs: options.packs,
|
|
6953
|
+
roots: options.roots,
|
|
6954
|
+
facts: needsValues ? db : void 0,
|
|
6955
|
+
storageFor
|
|
6956
|
+
})
|
|
6957
|
+
);
|
|
6958
|
+
const discovered = /* @__PURE__ */ new Map();
|
|
6398
6959
|
for (const boundFile of bound) {
|
|
6399
6960
|
const { file, root, module: moduleBinding } = boundFile;
|
|
6400
|
-
const displayPath = displayPathOf(file);
|
|
6401
6961
|
const storage = storageFor(boundFile);
|
|
6402
6962
|
const rawUnits = timer.time(
|
|
6403
6963
|
"discover",
|
|
6404
6964
|
() => discoverUnits(root, moduleBinding, {
|
|
6405
6965
|
packs: options.packs,
|
|
6406
|
-
filePath:
|
|
6966
|
+
filePath: displayPathOf(file),
|
|
6407
6967
|
absoluteFile: file,
|
|
6408
6968
|
routerIndex,
|
|
6409
6969
|
gapHandling,
|
|
6970
|
+
wrappers: wrapperIndex,
|
|
6410
6971
|
...needsValues ? { facts: db } : {},
|
|
6411
6972
|
...storage === void 0 ? {} : { storage }
|
|
6412
6973
|
})
|
|
6413
6974
|
);
|
|
6975
|
+
discovered.set(file, rawUnits);
|
|
6976
|
+
}
|
|
6977
|
+
const seeds = [];
|
|
6978
|
+
const summariesBySeed = /* @__PURE__ */ new Map();
|
|
6979
|
+
for (const boundFile of bound) {
|
|
6980
|
+
const { file, root, module: moduleBinding } = boundFile;
|
|
6981
|
+
const displayPath = displayPathOf(file);
|
|
6982
|
+
const rawUnits = [
|
|
6983
|
+
...discovered.get(file) ?? [],
|
|
6984
|
+
...wrapperIndex.unitsIn(file)
|
|
6985
|
+
];
|
|
6414
6986
|
for (const raw of rawUnits) {
|
|
6415
6987
|
const summary = timer.time(
|
|
6416
6988
|
"summarize",
|
|
6417
|
-
() => (0,
|
|
6989
|
+
() => (0, import_extractor10.assembleSummary)(raw, { gapHandling })
|
|
6418
6990
|
);
|
|
6419
6991
|
summary.confidence = { source: "inferred_static", level: "low" };
|
|
6420
6992
|
summaries.push(summary);
|
|
6421
6993
|
emitEntryFact(db, file, raw.identity.range, raw.identity.name);
|
|
6422
|
-
(0,
|
|
6994
|
+
(0, import_extractor6.tallyUnit)(tallies, raw.boundaryBinding?.recognition);
|
|
6423
6995
|
const span = raw.identity.span;
|
|
6424
6996
|
const key = span === void 0 ? null : `${file}:${span.start}-${span.end}`;
|
|
6425
6997
|
const node = key === null ? void 0 : definitions.get(key);
|
|
@@ -6441,8 +7013,8 @@ async function extractPythonProject(options) {
|
|
|
6441
7013
|
if (loadTimeReads.length > 0) {
|
|
6442
7014
|
const summary = timer.time(
|
|
6443
7015
|
"summarize",
|
|
6444
|
-
() => (0,
|
|
6445
|
-
(0,
|
|
7016
|
+
() => (0, import_extractor10.assembleSummary)(
|
|
7017
|
+
(0, import_extractor10.moduleInitStructure)({
|
|
6446
7018
|
name: import_node_path3.default.basename(displayPath),
|
|
6447
7019
|
file: displayPath,
|
|
6448
7020
|
range: rangeOf(root),
|
|
@@ -6485,7 +7057,7 @@ async function extractPythonProject(options) {
|
|
|
6485
7057
|
}
|
|
6486
7058
|
summaries.push(...reached.summaries);
|
|
6487
7059
|
const resolvedImports = resolvedImportsOf(db, displayPathOf);
|
|
6488
|
-
(0,
|
|
7060
|
+
(0, import_extractor10.stampModuleImports)(summaries, (file) => resolvedImports.get(file) ?? []);
|
|
6489
7061
|
const idRoot = options.projectRoot ?? options.workspaceRoot;
|
|
6490
7062
|
for (const summary of summaries) {
|
|
6491
7063
|
const absoluteFile = options.workspaceRoot === void 0 ? summary.location.file : import_node_path3.default.resolve(options.workspaceRoot, summary.location.file);
|
|
@@ -6498,12 +7070,16 @@ async function extractPythonProject(options) {
|
|
|
6498
7070
|
}
|
|
6499
7071
|
(0, import_behavioral_ir4.disambiguateSummaryIds)(summaries);
|
|
6500
7072
|
(0, import_behavioral_ir4.linkCallsToSummaries)(summaries);
|
|
7073
|
+
const composed = timer.time(
|
|
7074
|
+
"summarize",
|
|
7075
|
+
() => (0, import_extractor10.composeWrappers)(summaries, { gapHandling })
|
|
7076
|
+
);
|
|
6501
7077
|
await timer.timeAsync("cache.write", async () => {
|
|
6502
|
-
if (cacheDir === null ||
|
|
7078
|
+
if (cacheDir === null || composed.length === 0) {
|
|
6503
7079
|
return;
|
|
6504
7080
|
}
|
|
6505
7081
|
try {
|
|
6506
|
-
await cache.write(cacheInput,
|
|
7082
|
+
await cache.write(cacheInput, composed);
|
|
6507
7083
|
} catch {
|
|
6508
7084
|
}
|
|
6509
7085
|
});
|
|
@@ -6512,11 +7088,11 @@ async function extractPythonProject(options) {
|
|
|
6512
7088
|
packs: options.packs,
|
|
6513
7089
|
tallies,
|
|
6514
7090
|
filesWalked: options.files.length,
|
|
6515
|
-
summaries
|
|
7091
|
+
summaries: composed
|
|
6516
7092
|
})
|
|
6517
7093
|
);
|
|
6518
7094
|
options.onTiming?.(timer.report());
|
|
6519
|
-
return { summaries, facts: db };
|
|
7095
|
+
return { summaries: composed, facts: db };
|
|
6520
7096
|
}
|
|
6521
7097
|
function resolvedImportsOf(db, displayPathOf) {
|
|
6522
7098
|
const importsByFile = /* @__PURE__ */ new Map();
|