@suss/adapter-python 0.25.0 → 0.27.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/dist/index.cjs +339 -56
- package/dist/index.d.cts +226 -196
- package/dist/index.d.ts +226 -196
- package/dist/index.js +339 -56
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -159,6 +159,25 @@ function children(node) {
|
|
|
159
159
|
function bodyStatements(body) {
|
|
160
160
|
return children(body);
|
|
161
161
|
}
|
|
162
|
+
function nestedStatements(stmt) {
|
|
163
|
+
const found = [];
|
|
164
|
+
for (const child of children(stmt)) {
|
|
165
|
+
if (child.type === "block") {
|
|
166
|
+
for (const inner of children(child)) {
|
|
167
|
+
if (inner.type.endsWith("_clause")) {
|
|
168
|
+
found.push(...nestedStatements(inner));
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
found.push(inner);
|
|
172
|
+
}
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (child.type.endsWith("_clause")) {
|
|
176
|
+
found.push(...nestedStatements(child));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return found;
|
|
180
|
+
}
|
|
162
181
|
function stripDecorators(node) {
|
|
163
182
|
if (node.type !== "decorated_definition") {
|
|
164
183
|
return { definition: node, decorators: [] };
|
|
@@ -519,8 +538,36 @@ function resolveNonlocal(scope, name) {
|
|
|
519
538
|
}
|
|
520
539
|
|
|
521
540
|
// src/annotations.ts
|
|
522
|
-
function createAnnotationContext(scopeFor) {
|
|
523
|
-
return {
|
|
541
|
+
function createAnnotationContext(scopeFor, importedDefinition = null) {
|
|
542
|
+
return {
|
|
543
|
+
scopeMaps: [scopeFor],
|
|
544
|
+
definitions: /* @__PURE__ */ new Map(),
|
|
545
|
+
importedDefinition,
|
|
546
|
+
expanding: /* @__PURE__ */ new Set()
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function scopeOfNode(ctx, node) {
|
|
550
|
+
for (const scopeFor of ctx.scopeMaps) {
|
|
551
|
+
const scope = scopeFor.get(node.id);
|
|
552
|
+
if (scope !== void 0) {
|
|
553
|
+
return scope;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return void 0;
|
|
557
|
+
}
|
|
558
|
+
function aliasValueOf(name, scope, ctx) {
|
|
559
|
+
const binding = resolveName(scope, name);
|
|
560
|
+
if (binding?.kind === "assignment") {
|
|
561
|
+
return binding.value === null ? null : { node: binding.value, scope };
|
|
562
|
+
}
|
|
563
|
+
if (binding?.kind !== "import" && binding?.kind !== "importFrom") {
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
const imported = ctx.importedDefinition?.(scope, name) ?? null;
|
|
567
|
+
if (imported === null || imported.node.type === "class_definition") {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
return { node: imported.node, scope: imported.moduleScope };
|
|
524
571
|
}
|
|
525
572
|
function collectedDefinitions(ctx) {
|
|
526
573
|
const out = {};
|
|
@@ -563,6 +610,7 @@ var EXPRESSION_SHAPERS = {
|
|
|
563
610
|
identifier: (node, scope, ctx) => shapeFromName(node.text, scope, ctx),
|
|
564
611
|
none: () => ({ type: "null" }),
|
|
565
612
|
generic_type: shapeFromGenericType,
|
|
613
|
+
subscript: shapeFromSubscript,
|
|
566
614
|
binary_operator: shapeFromBinaryOperator
|
|
567
615
|
};
|
|
568
616
|
function shapeFromExpression(node, scope, ctx) {
|
|
@@ -584,8 +632,46 @@ function shapeFromName(name, scope, ctx) {
|
|
|
584
632
|
if (binding?.kind === "classDef") {
|
|
585
633
|
return recordShapeRef(name, binding.node, ctx);
|
|
586
634
|
}
|
|
635
|
+
if (binding?.kind === "import" || binding?.kind === "importFrom") {
|
|
636
|
+
const imported = ctx.importedDefinition?.(scope, name) ?? null;
|
|
637
|
+
if (imported?.node.type === "class_definition") {
|
|
638
|
+
if (!ctx.scopeMaps.includes(imported.scopeFor)) {
|
|
639
|
+
ctx.scopeMaps.push(imported.scopeFor);
|
|
640
|
+
}
|
|
641
|
+
return recordShapeRef(name, imported.node, ctx);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
const alias = aliasValueOf(name, scope, ctx);
|
|
645
|
+
if (alias !== null) {
|
|
646
|
+
return shapeFromAliasValue(name, alias, ctx);
|
|
647
|
+
}
|
|
587
648
|
return { type: "ref", name };
|
|
588
649
|
}
|
|
650
|
+
function shapeFromAliasValue(name, alias, ctx) {
|
|
651
|
+
if (ctx.expanding.has(alias.node.id)) {
|
|
652
|
+
return { type: "ref", name };
|
|
653
|
+
}
|
|
654
|
+
ctx.expanding.add(alias.node.id);
|
|
655
|
+
try {
|
|
656
|
+
return shapeFromExpression(alias.node, alias.scope, ctx);
|
|
657
|
+
} finally {
|
|
658
|
+
ctx.expanding.delete(alias.node.id);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function shapeFromSubscript(node, scope, ctx) {
|
|
662
|
+
const base = field(node, "value");
|
|
663
|
+
const args = fields(node, "subscript");
|
|
664
|
+
const baseName = base?.type === "identifier" ? base.text : null;
|
|
665
|
+
if (baseName === "Annotated") {
|
|
666
|
+
const first = args[0];
|
|
667
|
+
return first === void 0 ? { type: "unknown" } : shapeFromExpression(first, scope, ctx);
|
|
668
|
+
}
|
|
669
|
+
return shapeFromGeneric(
|
|
670
|
+
baseName,
|
|
671
|
+
node.text,
|
|
672
|
+
args.map((arg) => shapeFromExpression(arg, scope, ctx))
|
|
673
|
+
);
|
|
674
|
+
}
|
|
589
675
|
function genericTypeArgs(node) {
|
|
590
676
|
const typeParameter = node.namedChildren.find(
|
|
591
677
|
(child) => child !== null && child.type === "type_parameter"
|
|
@@ -596,14 +682,20 @@ function genericTypeArgs(node) {
|
|
|
596
682
|
}
|
|
597
683
|
function shapeFromGenericType(node, scope, ctx) {
|
|
598
684
|
const base = node.namedChild(0);
|
|
599
|
-
const args = genericTypeArgs(node);
|
|
600
|
-
const shapeOf = (arg) => arg !== void 0 ? annotationToShape(arg, scope, ctx) : { type: "unknown" };
|
|
601
685
|
const baseName = base?.type === "identifier" ? base.text : null;
|
|
686
|
+
return shapeFromGeneric(
|
|
687
|
+
baseName,
|
|
688
|
+
node.text,
|
|
689
|
+
genericTypeArgs(node).map((arg) => annotationToShape(arg, scope, ctx))
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
function shapeFromGeneric(baseName, text2, args) {
|
|
693
|
+
const shapeOf = (arg) => arg ?? { type: "unknown" };
|
|
602
694
|
if (baseName === "Optional") {
|
|
603
695
|
return { type: "union", variants: [shapeOf(args[0]), { type: "null" }] };
|
|
604
696
|
}
|
|
605
697
|
if (baseName === "Union") {
|
|
606
|
-
return { type: "union", variants: args
|
|
698
|
+
return { type: "union", variants: args };
|
|
607
699
|
}
|
|
608
700
|
if (baseName !== null && LIST_NAMES.has(baseName)) {
|
|
609
701
|
return { type: "array", items: shapeOf(args[0]) };
|
|
@@ -614,7 +706,7 @@ function shapeFromGenericType(node, scope, ctx) {
|
|
|
614
706
|
if (baseName !== null && TUPLE_SET_NAMES.has(baseName)) {
|
|
615
707
|
return { type: "array", items: shapeOf(args[0]) };
|
|
616
708
|
}
|
|
617
|
-
return { type: "ref", name: baseName ??
|
|
709
|
+
return { type: "ref", name: baseName ?? text2 };
|
|
618
710
|
}
|
|
619
711
|
function shapeFromBinaryOperator(node, scope, ctx) {
|
|
620
712
|
const operator = field(node, "operator");
|
|
@@ -639,7 +731,7 @@ function recordShapeRef(name, classNode, ctx) {
|
|
|
639
731
|
}
|
|
640
732
|
ctx.definitions.set(key, null);
|
|
641
733
|
const bodyNode = field(classNode, "body");
|
|
642
|
-
const classScope = ctx
|
|
734
|
+
const classScope = scopeOfNode(ctx, classNode);
|
|
643
735
|
ctx.definitions.set(
|
|
644
736
|
key,
|
|
645
737
|
bodyNode !== null && classScope !== void 0 ? recordShapeOf(bodyNode, classScope, ctx) : { type: "record", properties: {} }
|
|
@@ -1431,6 +1523,13 @@ function writtenValueOf(db, key) {
|
|
|
1431
1523
|
resolveCalls(db, [key]);
|
|
1432
1524
|
return (0, import_resolution.writtenValueOf)(db, key, (keys) => resolveCalls(db, keys));
|
|
1433
1525
|
}
|
|
1526
|
+
function originsOf(db, nameKey) {
|
|
1527
|
+
if (!db.facts("wantedOrigin").some((row) => String(row[0]) === nameKey)) {
|
|
1528
|
+
db.add("wantedOrigin", [nameKey]);
|
|
1529
|
+
(0, import_datalog.evaluate)(db, RESOLUTION_PROGRAM.rules);
|
|
1530
|
+
}
|
|
1531
|
+
return db.facts("wantedComesFrom").filter((row) => String(row[0]) === nameKey).map((row) => ({ module: String(row[1]), name: String(row[2]) }));
|
|
1532
|
+
}
|
|
1434
1533
|
function subjectConstructions(db, valueKeys) {
|
|
1435
1534
|
const found = /* @__PURE__ */ new Map();
|
|
1436
1535
|
if (valueKeys.length === 0) {
|
|
@@ -1766,7 +1865,7 @@ function emitBinding(emitter, assignment2, receiver) {
|
|
|
1766
1865
|
emitter,
|
|
1767
1866
|
"binds",
|
|
1768
1867
|
nameId(emitter.filePath, left.text),
|
|
1769
|
-
valueKey(emitter, right)
|
|
1868
|
+
valueKey(emitter, assignedValue(right))
|
|
1770
1869
|
);
|
|
1771
1870
|
return;
|
|
1772
1871
|
}
|
|
@@ -1798,9 +1897,17 @@ function emitAssignment(emitter, assignment2) {
|
|
|
1798
1897
|
"exportsAs",
|
|
1799
1898
|
emitter.filePath,
|
|
1800
1899
|
left.text,
|
|
1801
|
-
valueKey(emitter, right)
|
|
1900
|
+
valueKey(emitter, assignedValue(right))
|
|
1802
1901
|
);
|
|
1803
1902
|
}
|
|
1903
|
+
function assignedValue(right) {
|
|
1904
|
+
if (right.type !== "subscript") {
|
|
1905
|
+
return right;
|
|
1906
|
+
}
|
|
1907
|
+
const outer = field(right, "value");
|
|
1908
|
+
const first = fields(right, "subscript")[0];
|
|
1909
|
+
return outer?.text === "Annotated" && first !== void 0 ? first : right;
|
|
1910
|
+
}
|
|
1804
1911
|
function declaredBy(statement) {
|
|
1805
1912
|
if (statement.type === "decorated_definition") {
|
|
1806
1913
|
return field(statement, "definition") ?? statement;
|
|
@@ -3375,11 +3482,15 @@ var WALK_DESCENTS = {
|
|
|
3375
3482
|
scan,
|
|
3376
3483
|
visit
|
|
3377
3484
|
);
|
|
3378
|
-
}
|
|
3485
|
+
},
|
|
3486
|
+
if_statement: descendInPlace,
|
|
3487
|
+
try_statement: descendInPlace,
|
|
3488
|
+
while_statement: descendInPlace,
|
|
3489
|
+
with_statement: descendInPlace,
|
|
3490
|
+
match_statement: descendInPlace
|
|
3379
3491
|
};
|
|
3380
|
-
function
|
|
3381
|
-
|
|
3382
|
-
return body === null ? [] : bodyStatements(body);
|
|
3492
|
+
function descendInPlace(stmt, position, scan, visit) {
|
|
3493
|
+
walkStatements(nestedStatements(stmt), position, scan, visit);
|
|
3383
3494
|
}
|
|
3384
3495
|
function walkStatements(statements, position, scan, visit) {
|
|
3385
3496
|
for (const stmt of statements) {
|
|
@@ -4460,7 +4571,7 @@ function rawSqlEffects(calls, options) {
|
|
|
4460
4571
|
binding: (0, import_ir_core.storageBinding)({
|
|
4461
4572
|
recognition: `python-${pattern.module}`,
|
|
4462
4573
|
storageSystem: pattern.storageSystem,
|
|
4463
|
-
scope:
|
|
4574
|
+
scope: "default",
|
|
4464
4575
|
container: access.table
|
|
4465
4576
|
}),
|
|
4466
4577
|
callee: field(call, "function")?.text ?? "",
|
|
@@ -4604,16 +4715,23 @@ function typeNameOf(annotation) {
|
|
|
4604
4715
|
if (quoted !== null) {
|
|
4605
4716
|
return quoted;
|
|
4606
4717
|
}
|
|
4718
|
+
if (annotation.type === "binary_operator") {
|
|
4719
|
+
const named = [field(annotation, "left"), field(annotation, "right")].find(
|
|
4720
|
+
(side) => side !== null && side.type !== "none"
|
|
4721
|
+
);
|
|
4722
|
+
return named === void 0 || named === null ? null : typeNameOf(named);
|
|
4723
|
+
}
|
|
4607
4724
|
if (annotation.type === "generic_type") {
|
|
4608
4725
|
const outer = annotation.namedChildren[0];
|
|
4609
4726
|
const first = genericTypeArgs(annotation)[0];
|
|
4610
4727
|
if ((outer?.text === "Annotated" || outer?.text === "Optional") && first !== void 0) {
|
|
4611
4728
|
return typeNameOf(first);
|
|
4612
4729
|
}
|
|
4730
|
+
return outer?.type === "identifier" ? outer.text : null;
|
|
4613
4731
|
}
|
|
4614
4732
|
return null;
|
|
4615
4733
|
}
|
|
4616
|
-
function typeGivenBy(statement, name) {
|
|
4734
|
+
function typeGivenBy(statement, name, options) {
|
|
4617
4735
|
if (statement.type === "assignment") {
|
|
4618
4736
|
if (field(statement, "left")?.text !== name) {
|
|
4619
4737
|
return null;
|
|
@@ -4623,8 +4741,7 @@ function typeGivenBy(statement, name) {
|
|
|
4623
4741
|
return typeNameOf(annotation);
|
|
4624
4742
|
}
|
|
4625
4743
|
const right = field(statement, "right");
|
|
4626
|
-
|
|
4627
|
-
return callee?.type === "identifier" ? callee.text : null;
|
|
4744
|
+
return right?.type === "call" ? builtType(right, options) : null;
|
|
4628
4745
|
}
|
|
4629
4746
|
if (statement.type === "as_pattern") {
|
|
4630
4747
|
const alias = field(statement, "alias");
|
|
@@ -4634,7 +4751,34 @@ function typeGivenBy(statement, name) {
|
|
|
4634
4751
|
}
|
|
4635
4752
|
return null;
|
|
4636
4753
|
}
|
|
4637
|
-
function
|
|
4754
|
+
function builtType(call, options) {
|
|
4755
|
+
const root = rootOf(call);
|
|
4756
|
+
const callee = field(root, "function");
|
|
4757
|
+
if (callee?.type === "identifier") {
|
|
4758
|
+
return isClassName(callee.text) ? callee.text : resolvedReturnType(options, callee);
|
|
4759
|
+
}
|
|
4760
|
+
const object = callee?.type === "attribute" ? field(callee, "object") : null;
|
|
4761
|
+
if (object?.type === "identifier" && isClassName(object.text)) {
|
|
4762
|
+
return object.text;
|
|
4763
|
+
}
|
|
4764
|
+
const args = field(root, "arguments");
|
|
4765
|
+
const first = (args === null ? [] : children(args))[0];
|
|
4766
|
+
if (first?.type === "identifier" && isClassName(first.text)) {
|
|
4767
|
+
return first.text;
|
|
4768
|
+
}
|
|
4769
|
+
return callee === null ? null : resolvedReturnType(options, callee);
|
|
4770
|
+
}
|
|
4771
|
+
function resolvedReturnType(options, callee) {
|
|
4772
|
+
const settled = settledCallee(options, callee);
|
|
4773
|
+
return settled === void 0 ? null : returnTypeName(options.definitionAt(settled));
|
|
4774
|
+
}
|
|
4775
|
+
function settledCallee(options, callee) {
|
|
4776
|
+
const key = readKey(options.filePath, callee, enclosingFunction(callee));
|
|
4777
|
+
resolveCalls(options.facts, [key]);
|
|
4778
|
+
const resolved = options.facts.facts("wantedResolves").filter((row) => String(row[0]) === key).map((row) => String(row[1]));
|
|
4779
|
+
return resolved.length === 1 ? resolved[0] : void 0;
|
|
4780
|
+
}
|
|
4781
|
+
function declaredTypeName(name, from, options) {
|
|
4638
4782
|
const fn = enclosingFunction(from);
|
|
4639
4783
|
if (fn === null) {
|
|
4640
4784
|
return null;
|
|
@@ -4647,7 +4791,7 @@ function declaredTypeName(name, from) {
|
|
|
4647
4791
|
}
|
|
4648
4792
|
}
|
|
4649
4793
|
const visit = (node) => {
|
|
4650
|
-
const given = typeGivenBy(node, name);
|
|
4794
|
+
const given = typeGivenBy(node, name, options);
|
|
4651
4795
|
if (given !== null) {
|
|
4652
4796
|
return given;
|
|
4653
4797
|
}
|
|
@@ -4676,16 +4820,27 @@ function typedReceiverPattern(options, chain) {
|
|
|
4676
4820
|
if (receiver === null) {
|
|
4677
4821
|
return void 0;
|
|
4678
4822
|
}
|
|
4679
|
-
const typeName = declaredTypeName(receiver, chain.root);
|
|
4823
|
+
const typeName = declaredTypeName(receiver, chain.root, options);
|
|
4680
4824
|
if (typeName === null) {
|
|
4681
4825
|
return void 0;
|
|
4682
4826
|
}
|
|
4683
|
-
const
|
|
4684
|
-
|
|
4685
|
-
|
|
4827
|
+
const typeKey = `${options.filePath}#${typeName}`;
|
|
4828
|
+
const imported = options.facts.facts("pyImportedName").find((row) => String(row[0]) === typeKey);
|
|
4829
|
+
const direct = imported === void 0 ? void 0 : queryTypePattern(options, String(imported[1]), String(imported[2]));
|
|
4830
|
+
if (direct !== void 0) {
|
|
4831
|
+
return direct;
|
|
4832
|
+
}
|
|
4833
|
+
for (const origin of originsOf(options.facts, typeKey)) {
|
|
4834
|
+
const pattern = queryTypePattern(options, origin.module, origin.name);
|
|
4835
|
+
if (pattern !== void 0) {
|
|
4836
|
+
return pattern;
|
|
4837
|
+
}
|
|
4686
4838
|
}
|
|
4839
|
+
return void 0;
|
|
4840
|
+
}
|
|
4841
|
+
function queryTypePattern(options, module2, name) {
|
|
4687
4842
|
return options.patterns.find(
|
|
4688
|
-
(pattern) =>
|
|
4843
|
+
(pattern) => module2 === pattern.module && pattern.queryTypes.includes(name)
|
|
4689
4844
|
);
|
|
4690
4845
|
}
|
|
4691
4846
|
function fieldsOf(chain, valueMethods) {
|
|
@@ -4740,7 +4895,71 @@ function selectorOf(chain, valueMethods) {
|
|
|
4740
4895
|
)
|
|
4741
4896
|
];
|
|
4742
4897
|
}
|
|
4743
|
-
|
|
4898
|
+
var TABLE_METHODS = ["select_from", "join"];
|
|
4899
|
+
function modelOf(chain, options) {
|
|
4900
|
+
const fromRoot = modelArgument(chain.root, chain.root, options);
|
|
4901
|
+
if (fromRoot !== null) {
|
|
4902
|
+
return fromRoot;
|
|
4903
|
+
}
|
|
4904
|
+
for (const call of laterCalls(chain)) {
|
|
4905
|
+
if (TABLE_METHODS.includes(methodNameOf(call))) {
|
|
4906
|
+
const named = modelArgument(call, chain.root, options);
|
|
4907
|
+
if (named !== null) {
|
|
4908
|
+
return named;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4912
|
+
return isClassName(chain.subject) ? chain.subject : null;
|
|
4913
|
+
}
|
|
4914
|
+
function modelArgument(call, from, options) {
|
|
4915
|
+
const args = field(call, "arguments");
|
|
4916
|
+
const first = (args === null ? [] : children(args)).find(
|
|
4917
|
+
(argument) => argument.type !== "keyword_argument"
|
|
4918
|
+
);
|
|
4919
|
+
return first === void 0 ? null : modelNamed(first, from, options);
|
|
4920
|
+
}
|
|
4921
|
+
function modelNamed(node, from, options) {
|
|
4922
|
+
if (node.type === "identifier") {
|
|
4923
|
+
if (isClassName(node.text)) {
|
|
4924
|
+
return node.text;
|
|
4925
|
+
}
|
|
4926
|
+
const declared = declaredTypeName(node.text, from, options);
|
|
4927
|
+
return declared === null ? null : classBehind(declared, options);
|
|
4928
|
+
}
|
|
4929
|
+
if (node.type === "attribute") {
|
|
4930
|
+
const property = field(node, "attribute");
|
|
4931
|
+
if (property !== null && isClassName(property.text)) {
|
|
4932
|
+
return property.text;
|
|
4933
|
+
}
|
|
4934
|
+
const object = field(node, "object");
|
|
4935
|
+
return object === null ? null : modelNamed(object, from, options);
|
|
4936
|
+
}
|
|
4937
|
+
if (node.type === "call") {
|
|
4938
|
+
const callee = field(node, "function");
|
|
4939
|
+
const built = callee === null ? null : modelNamed(callee, from, options);
|
|
4940
|
+
return built ?? modelArgument(node, from, options);
|
|
4941
|
+
}
|
|
4942
|
+
return null;
|
|
4943
|
+
}
|
|
4944
|
+
function classBehind(typeName, options) {
|
|
4945
|
+
const key = `${options.filePath}#${typeName}`;
|
|
4946
|
+
originsOf(options.facts, key);
|
|
4947
|
+
const reached = new Set(
|
|
4948
|
+
options.facts.facts("wantedComesTo").filter((row) => String(row[0]) === key).map((row) => String(row[1]))
|
|
4949
|
+
);
|
|
4950
|
+
const classes = new Set(
|
|
4951
|
+
options.facts.facts("objectValue").map((row) => String(row[0])).filter((value) => reached.has(value))
|
|
4952
|
+
);
|
|
4953
|
+
const exported = options.facts.facts("exportsAs").find((row) => classes.has(String(row[2])));
|
|
4954
|
+
if (exported !== void 0) {
|
|
4955
|
+
return String(exported[1]);
|
|
4956
|
+
}
|
|
4957
|
+
return isClassName(typeName) ? typeName : null;
|
|
4958
|
+
}
|
|
4959
|
+
function isClassName(name) {
|
|
4960
|
+
return /^[A-Z][A-Za-z0-9_]*$/.test(name) && name !== name.toUpperCase();
|
|
4961
|
+
}
|
|
4962
|
+
function effectFor(pattern, chain, operation, options) {
|
|
4744
4963
|
const valueMethods = pattern.valueMethods ?? [];
|
|
4745
4964
|
const picked = selectorOf(chain, valueMethods);
|
|
4746
4965
|
return {
|
|
@@ -4748,8 +4967,8 @@ function effectFor(pattern, chain, operation) {
|
|
|
4748
4967
|
binding: (0, import_ir_core2.storageBinding)({
|
|
4749
4968
|
recognition: "python-storage",
|
|
4750
4969
|
storageSystem: pattern.storageSystem,
|
|
4751
|
-
scope:
|
|
4752
|
-
container: chain
|
|
4970
|
+
scope: "default",
|
|
4971
|
+
container: modelOf(chain, options)
|
|
4753
4972
|
}),
|
|
4754
4973
|
callee: chain.last.text,
|
|
4755
4974
|
interaction: {
|
|
@@ -4766,23 +4985,14 @@ function fileOf(key) {
|
|
|
4766
4985
|
return at === -1 ? key : key.slice(0, at);
|
|
4767
4986
|
}
|
|
4768
4987
|
function returnTypeName(node) {
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
}
|
|
4772
|
-
const annotation = field(node, "return_type");
|
|
4773
|
-
if (annotation === null) {
|
|
4774
|
-
return null;
|
|
4775
|
-
}
|
|
4776
|
-
return annotation.type === "subscript" ? field(annotation, "value")?.text ?? null : annotation.text;
|
|
4988
|
+
const annotation = node === void 0 ? null : field(node, "return_type");
|
|
4989
|
+
return annotation === null ? null : typeNameOf(annotation);
|
|
4777
4990
|
}
|
|
4778
4991
|
function storageCallees(calls, filePath, couldMatch) {
|
|
4779
4992
|
return chainsIn(calls).filter((chain) => couldMatch.has(methodName(chain.root))).map((chain) => field(chain.root, "function")).filter((callee) => callee !== null).map((callee) => readKey(filePath, callee, enclosingFunction(callee)));
|
|
4780
4993
|
}
|
|
4781
4994
|
function resolvedMethodPattern(options, callee) {
|
|
4782
|
-
const
|
|
4783
|
-
(row) => String(row[0]) === readKey(options.filePath, callee, enclosingFunction(callee))
|
|
4784
|
-
).map((row) => String(row[1]));
|
|
4785
|
-
const settled = resolved.length === 1 ? resolved[0] : void 0;
|
|
4995
|
+
const settled = settledCallee(options, callee);
|
|
4786
4996
|
if (settled === void 0) {
|
|
4787
4997
|
return void 0;
|
|
4788
4998
|
}
|
|
@@ -4859,7 +5069,7 @@ function storageCallIds(calls, options) {
|
|
|
4859
5069
|
}
|
|
4860
5070
|
function storageEffects(calls, options) {
|
|
4861
5071
|
return matchedChains(calls, options).flatMap(
|
|
4862
|
-
({ chain, pattern, operation }) => operation === null ? [] : [effectFor(pattern, chain, operation)]
|
|
5072
|
+
({ chain, pattern, operation }) => operation === null ? [] : [effectFor(pattern, chain, operation, options)]
|
|
4863
5073
|
);
|
|
4864
5074
|
}
|
|
4865
5075
|
|
|
@@ -5155,6 +5365,7 @@ function classRouteUnits(pattern, pack, classification, classNode, module2, opti
|
|
|
5155
5365
|
pattern
|
|
5156
5366
|
),
|
|
5157
5367
|
storage: options.storage,
|
|
5368
|
+
importedDefinition: options.importedDefinition,
|
|
5158
5369
|
wrappers: wrappersAround(
|
|
5159
5370
|
pattern,
|
|
5160
5371
|
pack,
|
|
@@ -5484,7 +5695,10 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
5484
5695
|
if (functionName === void 0) {
|
|
5485
5696
|
return [];
|
|
5486
5697
|
}
|
|
5487
|
-
const ctx = createAnnotationContext(
|
|
5698
|
+
const ctx = createAnnotationContext(
|
|
5699
|
+
module2.scopeFor,
|
|
5700
|
+
options.importedDefinition ?? null
|
|
5701
|
+
);
|
|
5488
5702
|
return readRoutePaths(
|
|
5489
5703
|
pattern,
|
|
5490
5704
|
readPathArgument(classification, options),
|
|
@@ -5523,6 +5737,7 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
5523
5737
|
),
|
|
5524
5738
|
definitionsCtx: ctx,
|
|
5525
5739
|
storage: options.storage,
|
|
5740
|
+
importedDefinition: options.importedDefinition,
|
|
5526
5741
|
wrappers: wrappersAround(
|
|
5527
5742
|
pattern,
|
|
5528
5743
|
pack,
|
|
@@ -5620,7 +5835,10 @@ function buildRouteUnit(options) {
|
|
|
5620
5835
|
storage: storageLookup
|
|
5621
5836
|
} = options;
|
|
5622
5837
|
const template = (0, import_extractor5.valueToReadFurtherFrom)(routePath);
|
|
5623
|
-
const ctx = definitionsCtx ?? createAnnotationContext(
|
|
5838
|
+
const ctx = definitionsCtx ?? createAnnotationContext(
|
|
5839
|
+
module2.scopeFor,
|
|
5840
|
+
options.importedDefinition ?? null
|
|
5841
|
+
);
|
|
5624
5842
|
const parameters = readParameters(
|
|
5625
5843
|
definitionNode,
|
|
5626
5844
|
enclosingScope,
|
|
@@ -5701,7 +5919,7 @@ function buildRouteUnit(options) {
|
|
|
5701
5919
|
declaredContract: null,
|
|
5702
5920
|
readings: [
|
|
5703
5921
|
routePath,
|
|
5704
|
-
...unreadRoleReadings(parameters, rangeOf(definitionNode)),
|
|
5922
|
+
...template === null ? unreadRoleReadings(parameters, rangeOf(definitionNode)) : [],
|
|
5705
5923
|
...responseShape.passedOver
|
|
5706
5924
|
],
|
|
5707
5925
|
...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {},
|
|
@@ -5796,7 +6014,7 @@ function readParameter(param, scope, ctx, pathParamNames, requestBodyFromAnnotat
|
|
|
5796
6014
|
}
|
|
5797
6015
|
const { name, typeNode } = info;
|
|
5798
6016
|
const shape = typeNode !== null ? annotationToShape(typeNode, scope, ctx) : null;
|
|
5799
|
-
const role = isInjectedParameter(param, injectedCallees) ? null : roleOf(name, shape, pathParamNames, requestBodyFromAnnotatedClass);
|
|
6017
|
+
const role = isInjectedParameter(param, injectedCallees, scope, ctx) ? null : roleOf(name, shape, pathParamNames, requestBodyFromAnnotatedClass);
|
|
5800
6018
|
return {
|
|
5801
6019
|
name,
|
|
5802
6020
|
position,
|
|
@@ -5830,7 +6048,7 @@ function calleeName2(call) {
|
|
|
5830
6048
|
}
|
|
5831
6049
|
return null;
|
|
5832
6050
|
}
|
|
5833
|
-
function isInjectedParameter(param, injectedCallees) {
|
|
6051
|
+
function isInjectedParameter(param, injectedCallees, scope, ctx) {
|
|
5834
6052
|
if (injectedCallees.size === 0) {
|
|
5835
6053
|
return false;
|
|
5836
6054
|
}
|
|
@@ -5844,18 +6062,26 @@ function isInjectedParameter(param, injectedCallees) {
|
|
|
5844
6062
|
if (callsAnInjector(field(param, "value"))) {
|
|
5845
6063
|
return true;
|
|
5846
6064
|
}
|
|
5847
|
-
const
|
|
6065
|
+
const followed = /* @__PURE__ */ new Set();
|
|
6066
|
+
const containsInjectorCall = (node, nodeScope, depth) => {
|
|
5848
6067
|
if (node === null || depth > MAX_ANNOTATION_DEPTH) {
|
|
5849
6068
|
return false;
|
|
5850
6069
|
}
|
|
5851
6070
|
if (callsAnInjector(node)) {
|
|
5852
6071
|
return true;
|
|
5853
6072
|
}
|
|
6073
|
+
if (node.type === "identifier" && !followed.has(node.id)) {
|
|
6074
|
+
followed.add(node.id);
|
|
6075
|
+
const alias = aliasValueOf(node.text, nodeScope, ctx);
|
|
6076
|
+
if (alias !== null && containsInjectorCall(alias.node, alias.scope, 0)) {
|
|
6077
|
+
return true;
|
|
6078
|
+
}
|
|
6079
|
+
}
|
|
5854
6080
|
return node.namedChildren.some(
|
|
5855
|
-
(child) => containsInjectorCall(child, depth + 1)
|
|
6081
|
+
(child) => containsInjectorCall(child, nodeScope, depth + 1)
|
|
5856
6082
|
);
|
|
5857
6083
|
};
|
|
5858
|
-
return containsInjectorCall(field(param, "type"), 0);
|
|
6084
|
+
return containsInjectorCall(field(param, "type"), scope, 0);
|
|
5859
6085
|
}
|
|
5860
6086
|
|
|
5861
6087
|
// src/facts/why.ts
|
|
@@ -5991,6 +6217,58 @@ function buildPythonExtractionReport(args) {
|
|
|
5991
6217
|
});
|
|
5992
6218
|
}
|
|
5993
6219
|
|
|
6220
|
+
// src/importedDefinitions.ts
|
|
6221
|
+
function importedDefinitionLookup(db, files) {
|
|
6222
|
+
const fileOfModuleScope = /* @__PURE__ */ new Map();
|
|
6223
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
6224
|
+
for (const file of files) {
|
|
6225
|
+
fileOfModuleScope.set(file.module.moduleScope.node.id, file.file);
|
|
6226
|
+
byFile.set(file.file, file);
|
|
6227
|
+
}
|
|
6228
|
+
const found = /* @__PURE__ */ new Map();
|
|
6229
|
+
return (scope, name) => {
|
|
6230
|
+
const fromFile = fileOfModuleScope.get(moduleScopeOf(scope).node.id);
|
|
6231
|
+
if (fromFile === void 0) {
|
|
6232
|
+
return null;
|
|
6233
|
+
}
|
|
6234
|
+
const key = `${fromFile}#${name}`;
|
|
6235
|
+
const known = found.get(key);
|
|
6236
|
+
if (known !== void 0) {
|
|
6237
|
+
return known;
|
|
6238
|
+
}
|
|
6239
|
+
const definition = definitionAmong(originsOf(db, key), byFile);
|
|
6240
|
+
found.set(key, definition);
|
|
6241
|
+
return definition;
|
|
6242
|
+
};
|
|
6243
|
+
}
|
|
6244
|
+
function definitionAmong(origins, byFile) {
|
|
6245
|
+
for (const origin of origins) {
|
|
6246
|
+
const file = byFile.get(origin.module);
|
|
6247
|
+
const binding = file?.module.moduleScope.bindings.get(origin.name);
|
|
6248
|
+
if (file === void 0 || binding === void 0) {
|
|
6249
|
+
continue;
|
|
6250
|
+
}
|
|
6251
|
+
const node = definedNodeOf(binding);
|
|
6252
|
+
if (node !== null) {
|
|
6253
|
+
return {
|
|
6254
|
+
node,
|
|
6255
|
+
moduleScope: file.module.moduleScope,
|
|
6256
|
+
scopeFor: file.module.scopeFor
|
|
6257
|
+
};
|
|
6258
|
+
}
|
|
6259
|
+
}
|
|
6260
|
+
return null;
|
|
6261
|
+
}
|
|
6262
|
+
function definedNodeOf(binding) {
|
|
6263
|
+
if (binding.kind === "classDef") {
|
|
6264
|
+
return binding.node;
|
|
6265
|
+
}
|
|
6266
|
+
if (binding.kind === "assignment") {
|
|
6267
|
+
return binding.value;
|
|
6268
|
+
}
|
|
6269
|
+
return null;
|
|
6270
|
+
}
|
|
6271
|
+
|
|
5994
6272
|
// src/reach/closure.ts
|
|
5995
6273
|
var import_behavioral_ir4 = require("@suss/behavioral-ir");
|
|
5996
6274
|
var import_datalog2 = require("@suss/datalog");
|
|
@@ -6048,14 +6326,9 @@ var EXPRESSION_RESOLVERS = {
|
|
|
6048
6326
|
}
|
|
6049
6327
|
return memberOf(resolveExpression(object, site, ctx), attribute.text, ctx);
|
|
6050
6328
|
},
|
|
6051
|
-
// `Service().run()` runs a method on whatever the constructor built.
|
|
6052
6329
|
call: (node, site, ctx) => {
|
|
6053
6330
|
const callee = field(node, "function");
|
|
6054
|
-
|
|
6055
|
-
return stop("noDeclaration");
|
|
6056
|
-
}
|
|
6057
|
-
const built = resolveExpression(callee, site, ctx);
|
|
6058
|
-
return built.kind === "class" ? built : stop("noDeclaration");
|
|
6331
|
+
return callee === null ? stop("noDeclaration") : instanceBuiltBy(resolveExpression(callee, site, ctx), "noDeclaration");
|
|
6059
6332
|
},
|
|
6060
6333
|
parenthesized_expression: (node, site, ctx) => {
|
|
6061
6334
|
const inner = node.namedChildren[0];
|
|
@@ -6066,6 +6339,12 @@ function resolveExpression(node, site, ctx) {
|
|
|
6066
6339
|
const resolver = EXPRESSION_RESOLVERS[node.type];
|
|
6067
6340
|
return resolver === void 0 ? stop("noDeclaration") : resolver(node, site, ctx);
|
|
6068
6341
|
}
|
|
6342
|
+
function instanceBuiltBy(built, otherwise) {
|
|
6343
|
+
if (built.kind === "class" || built.kind === "stop") {
|
|
6344
|
+
return built;
|
|
6345
|
+
}
|
|
6346
|
+
return built.kind === "package" ? stop("outsideRun") : stop(otherwise);
|
|
6347
|
+
}
|
|
6069
6348
|
function resolveIdentifier(name, site, ctx) {
|
|
6070
6349
|
if (site.rebound.has(name)) {
|
|
6071
6350
|
return stop("unsettledValue");
|
|
@@ -6131,8 +6410,10 @@ function aliasedValue(value, file, scope, ctx, visited) {
|
|
|
6131
6410
|
}
|
|
6132
6411
|
if (value.type === "call") {
|
|
6133
6412
|
const callee = field(value, "function");
|
|
6134
|
-
|
|
6135
|
-
|
|
6413
|
+
return callee === null ? stop("unsettledValue") : instanceBuiltBy(
|
|
6414
|
+
aliasedValue(callee, file, scope, ctx, visited),
|
|
6415
|
+
"unsettledValue"
|
|
6416
|
+
);
|
|
6136
6417
|
}
|
|
6137
6418
|
if (value.type === "attribute") {
|
|
6138
6419
|
const object = field(value, "object");
|
|
@@ -7222,6 +7503,7 @@ async function extractPythonProject(options) {
|
|
|
7222
7503
|
storageFor
|
|
7223
7504
|
})
|
|
7224
7505
|
);
|
|
7506
|
+
const importedDefinition = importedDefinitionLookup(db, bound);
|
|
7225
7507
|
const discovered = /* @__PURE__ */ new Map();
|
|
7226
7508
|
for (const boundFile of bound) {
|
|
7227
7509
|
const { file, root, module: moduleBinding } = boundFile;
|
|
@@ -7235,6 +7517,7 @@ async function extractPythonProject(options) {
|
|
|
7235
7517
|
routerIndex,
|
|
7236
7518
|
gapHandling,
|
|
7237
7519
|
wrappers: wrapperIndex,
|
|
7520
|
+
importedDefinition,
|
|
7238
7521
|
...needsValues ? { facts: db } : {},
|
|
7239
7522
|
...storage === void 0 ? {} : { storage }
|
|
7240
7523
|
})
|