@suss/adapter-python 0.34.0 → 0.35.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 +1681 -600
- package/dist/index.d.cts +126 -6
- package/dist/index.d.ts +126 -6
- package/dist/index.js +1576 -478
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -82,10 +82,7 @@ function stringLiteralValue(node) {
|
|
|
82
82
|
return null;
|
|
83
83
|
}
|
|
84
84
|
let content = "";
|
|
85
|
-
for (const child of node
|
|
86
|
-
if (child === null) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
85
|
+
for (const child of children(node)) {
|
|
89
86
|
if (child.type === "string_content") {
|
|
90
87
|
content += stringContentValue(child);
|
|
91
88
|
continue;
|
|
@@ -97,7 +94,29 @@ function stringLiteralValue(node) {
|
|
|
97
94
|
return content;
|
|
98
95
|
}
|
|
99
96
|
function children(node) {
|
|
100
|
-
|
|
97
|
+
if (node === null || node === void 0) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const found = [];
|
|
101
|
+
const count = node.namedChildCount;
|
|
102
|
+
for (let index = 0; index < count; index++) {
|
|
103
|
+
const child = node.namedChild(index);
|
|
104
|
+
if (child !== null) {
|
|
105
|
+
found.push(child);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return found;
|
|
109
|
+
}
|
|
110
|
+
function allChildren(node) {
|
|
111
|
+
const found = [];
|
|
112
|
+
const count = node.childCount;
|
|
113
|
+
for (let index = 0; index < count; index++) {
|
|
114
|
+
const child = node.child(index);
|
|
115
|
+
if (child !== null) {
|
|
116
|
+
found.push(child);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return found;
|
|
101
120
|
}
|
|
102
121
|
function bodyStatements(body) {
|
|
103
122
|
return children(body);
|
|
@@ -129,11 +148,59 @@ function stripDecorators(node) {
|
|
|
129
148
|
if (definition === null) {
|
|
130
149
|
throw new Error("decorated_definition with no definition field");
|
|
131
150
|
}
|
|
132
|
-
const decorators = node.
|
|
133
|
-
(child) => child
|
|
151
|
+
const decorators = children(node).filter(
|
|
152
|
+
(child) => child.type === "decorator"
|
|
134
153
|
);
|
|
135
154
|
return { definition, decorators };
|
|
136
155
|
}
|
|
156
|
+
var isChild = (fieldName) => (parent, child) => field(parent, fieldName)?.id === child.id;
|
|
157
|
+
var always = () => true;
|
|
158
|
+
var asCondition = isChild("condition");
|
|
159
|
+
var isConditionalTest = (parent, child) => parent.namedChild(1)?.id === child.id;
|
|
160
|
+
var VALUE_USED_UNDER = {
|
|
161
|
+
assignment: isChild("right"),
|
|
162
|
+
augmented_assignment: isChild("right"),
|
|
163
|
+
named_expression: isChild("value"),
|
|
164
|
+
attribute: isChild("object"),
|
|
165
|
+
subscript: always,
|
|
166
|
+
argument_list: always,
|
|
167
|
+
keyword_argument: isChild("value"),
|
|
168
|
+
pair: always,
|
|
169
|
+
list: always,
|
|
170
|
+
tuple: always,
|
|
171
|
+
set: always,
|
|
172
|
+
dictionary: always,
|
|
173
|
+
interpolation: always,
|
|
174
|
+
comparison_operator: always,
|
|
175
|
+
binary_operator: always,
|
|
176
|
+
unary_operator: always,
|
|
177
|
+
not_operator: always,
|
|
178
|
+
if_statement: asCondition,
|
|
179
|
+
elif_clause: asCondition,
|
|
180
|
+
while_statement: asCondition,
|
|
181
|
+
conditional_expression: isConditionalTest,
|
|
182
|
+
assert_statement: always,
|
|
183
|
+
for_statement: isChild("right"),
|
|
184
|
+
for_in_clause: isChild("right"),
|
|
185
|
+
with_item: always,
|
|
186
|
+
as_pattern: always
|
|
187
|
+
};
|
|
188
|
+
var PASSES_VALUE_ON = {
|
|
189
|
+
parenthesized_expression: always,
|
|
190
|
+
await: always,
|
|
191
|
+
boolean_operator: always,
|
|
192
|
+
conditional_expression: (parent, child) => !isConditionalTest(parent, child)
|
|
193
|
+
};
|
|
194
|
+
function resultUsedAsValue(node) {
|
|
195
|
+
let child = node;
|
|
196
|
+
let parent = node.parent;
|
|
197
|
+
while (parent !== null && PASSES_VALUE_ON[parent.type]?.(parent, child) === true) {
|
|
198
|
+
child = parent;
|
|
199
|
+
parent = parent.parent;
|
|
200
|
+
}
|
|
201
|
+
const used = parent === null ? void 0 : VALUE_USED_UNDER[parent.type];
|
|
202
|
+
return parent !== null && used !== void 0 && used(parent, child);
|
|
203
|
+
}
|
|
137
204
|
var NodeSet = class extends IdSet {
|
|
138
205
|
};
|
|
139
206
|
var NodeMap = class extends IdMap {
|
|
@@ -195,7 +262,7 @@ function bindWithStatement(stmt, scope, ctx) {
|
|
|
195
262
|
}
|
|
196
263
|
}
|
|
197
264
|
function asPatternsIn(stmt, found = []) {
|
|
198
|
-
for (const child of stmt
|
|
265
|
+
for (const child of children(stmt)) {
|
|
199
266
|
if (child === null || child.type === "block") {
|
|
200
267
|
continue;
|
|
201
268
|
}
|
|
@@ -224,12 +291,12 @@ function bindDeleteStatement(stmt, scope) {
|
|
|
224
291
|
return;
|
|
225
292
|
}
|
|
226
293
|
if (node.type === "expression_list") {
|
|
227
|
-
for (const child of node
|
|
294
|
+
for (const child of children(node)) {
|
|
228
295
|
unbind(child);
|
|
229
296
|
}
|
|
230
297
|
}
|
|
231
298
|
};
|
|
232
|
-
for (const child of stmt
|
|
299
|
+
for (const child of children(stmt)) {
|
|
233
300
|
unbind(child);
|
|
234
301
|
}
|
|
235
302
|
}
|
|
@@ -270,10 +337,7 @@ function bindImportStatement(stmt, scope) {
|
|
|
270
337
|
function relativeImportParts(node) {
|
|
271
338
|
let relativeLevel = 0;
|
|
272
339
|
let module = "";
|
|
273
|
-
for (const child of node
|
|
274
|
-
if (child === null) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
340
|
+
for (const child of children(node)) {
|
|
277
341
|
if (child.type === "import_prefix") {
|
|
278
342
|
relativeLevel += child.text.length;
|
|
279
343
|
continue;
|
|
@@ -290,8 +354,8 @@ function bindImportFromStatement(stmt, scope, ctx) {
|
|
|
290
354
|
return;
|
|
291
355
|
}
|
|
292
356
|
const { module, relativeLevel } = moduleNode.type === "relative_import" ? relativeImportParts(moduleNode) : { module: moduleNode.text, relativeLevel: 0 };
|
|
293
|
-
const hasWildcard = stmt.
|
|
294
|
-
(child) => child
|
|
357
|
+
const hasWildcard = children(stmt).some(
|
|
358
|
+
(child) => child.type === "wildcard_import"
|
|
295
359
|
);
|
|
296
360
|
if (hasWildcard) {
|
|
297
361
|
ctx.openImports.push(
|
|
@@ -349,10 +413,7 @@ function bindFunctionDefinition(stmt, scope, ctx) {
|
|
|
349
413
|
}
|
|
350
414
|
}
|
|
351
415
|
function bindParameters(parametersNode, functionScope) {
|
|
352
|
-
for (const param of parametersNode
|
|
353
|
-
if (param === null) {
|
|
354
|
-
continue;
|
|
355
|
-
}
|
|
416
|
+
for (const param of children(parametersNode)) {
|
|
356
417
|
const name = parameterName(param);
|
|
357
418
|
if (name !== null) {
|
|
358
419
|
bindName(functionScope, name, { kind: "parameter" });
|
|
@@ -369,9 +430,7 @@ function parameterName(param) {
|
|
|
369
430
|
"list_splat_pattern",
|
|
370
431
|
"dictionary_splat_pattern"
|
|
371
432
|
)) {
|
|
372
|
-
const inner = param.
|
|
373
|
-
(child) => child !== null && child.type === "identifier"
|
|
374
|
-
);
|
|
433
|
+
const inner = children(param).find((child) => child.type === "identifier");
|
|
375
434
|
return inner?.text ?? null;
|
|
376
435
|
}
|
|
377
436
|
if (isType(param, "default_parameter", "typed_default_parameter")) {
|
|
@@ -398,8 +457,8 @@ function bindClassDefinition(stmt, scope, ctx) {
|
|
|
398
457
|
}
|
|
399
458
|
}
|
|
400
459
|
function bindExpressionStatement(stmt, scope) {
|
|
401
|
-
const assignment2 = stmt.
|
|
402
|
-
(child) => child
|
|
460
|
+
const assignment2 = children(stmt).find(
|
|
461
|
+
(child) => child.type === "assignment"
|
|
403
462
|
);
|
|
404
463
|
if (assignment2 === void 0 || assignment2 === null) {
|
|
405
464
|
return;
|
|
@@ -416,15 +475,15 @@ function bindExpressionStatement(stmt, scope) {
|
|
|
416
475
|
}
|
|
417
476
|
}
|
|
418
477
|
function bindGlobalStatement(stmt, scope) {
|
|
419
|
-
for (const child of stmt
|
|
420
|
-
if (child
|
|
478
|
+
for (const child of children(stmt)) {
|
|
479
|
+
if (child.type === "identifier") {
|
|
421
480
|
scope.bindings.set(child.text, { kind: "global" });
|
|
422
481
|
}
|
|
423
482
|
}
|
|
424
483
|
}
|
|
425
484
|
function bindNonlocalStatement(stmt, scope) {
|
|
426
|
-
for (const child of stmt
|
|
427
|
-
if (child
|
|
485
|
+
for (const child of children(stmt)) {
|
|
486
|
+
if (child.type === "identifier") {
|
|
428
487
|
scope.bindings.set(child.text, { kind: "nonlocal" });
|
|
429
488
|
}
|
|
430
489
|
}
|
|
@@ -573,18 +632,9 @@ function shapeFromName(name, scope, ctx) {
|
|
|
573
632
|
if (DICT_NAMES.has(name)) {
|
|
574
633
|
return { type: "dictionary", values: { type: "unknown" } };
|
|
575
634
|
}
|
|
576
|
-
const
|
|
577
|
-
if (
|
|
578
|
-
return recordShapeRef(name,
|
|
579
|
-
}
|
|
580
|
-
if (binding?.kind === "import" || binding?.kind === "importFrom") {
|
|
581
|
-
const imported = ctx.importedDefinition?.(scope, name) ?? null;
|
|
582
|
-
if (imported?.node.type === "class_definition") {
|
|
583
|
-
if (!ctx.scopeMaps.includes(imported.scopeFor)) {
|
|
584
|
-
ctx.scopeMaps.push(imported.scopeFor);
|
|
585
|
-
}
|
|
586
|
-
return recordShapeRef(name, imported.node, ctx);
|
|
587
|
-
}
|
|
635
|
+
const classNode = projectClassNamed(name, scope, ctx);
|
|
636
|
+
if (classNode !== null) {
|
|
637
|
+
return recordShapeRef(name, classNode, ctx);
|
|
588
638
|
}
|
|
589
639
|
const alias = aliasValueOf(name, scope, ctx);
|
|
590
640
|
if (alias !== null) {
|
|
@@ -592,6 +642,23 @@ function shapeFromName(name, scope, ctx) {
|
|
|
592
642
|
}
|
|
593
643
|
return { type: "ref", name };
|
|
594
644
|
}
|
|
645
|
+
function projectClassNamed(name, scope, ctx) {
|
|
646
|
+
const binding = resolveName(scope, name);
|
|
647
|
+
if (binding?.kind === "classDef") {
|
|
648
|
+
return binding.node;
|
|
649
|
+
}
|
|
650
|
+
if (binding?.kind !== "import" && binding?.kind !== "importFrom") {
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
const imported = ctx.importedDefinition?.(scope, name) ?? null;
|
|
654
|
+
if (imported?.node.type !== "class_definition") {
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
if (!ctx.scopeMaps.includes(imported.scopeFor)) {
|
|
658
|
+
ctx.scopeMaps.push(imported.scopeFor);
|
|
659
|
+
}
|
|
660
|
+
return imported.node;
|
|
661
|
+
}
|
|
595
662
|
function shapeFromAliasValue(name, alias, ctx) {
|
|
596
663
|
if (ctx.expanding.has(alias.node.id)) {
|
|
597
664
|
return { type: "ref", name };
|
|
@@ -618,8 +685,9 @@ function shapeFromSubscript(node, scope, ctx) {
|
|
|
618
685
|
);
|
|
619
686
|
}
|
|
620
687
|
function annotationTarget(annotation) {
|
|
621
|
-
|
|
622
|
-
|
|
688
|
+
const inner = annotation.type === "type" ? annotation.namedChild(0) : null;
|
|
689
|
+
if (inner !== null) {
|
|
690
|
+
return annotationTarget(inner);
|
|
623
691
|
}
|
|
624
692
|
if (annotation.type === "binary_operator") {
|
|
625
693
|
const named = [field(annotation, "left"), field(annotation, "right")].find(
|
|
@@ -628,7 +696,7 @@ function annotationTarget(annotation) {
|
|
|
628
696
|
return named === void 0 || named === null ? null : annotationTarget(named);
|
|
629
697
|
}
|
|
630
698
|
if (annotation.type === "generic_type") {
|
|
631
|
-
const outer = annotation.
|
|
699
|
+
const outer = annotation.namedChild(0);
|
|
632
700
|
const first = genericTypeArgs(annotation)[0];
|
|
633
701
|
if ((outer?.text === "Annotated" || outer?.text === "Optional") && first !== void 0) {
|
|
634
702
|
return annotationTarget(first);
|
|
@@ -645,12 +713,10 @@ function typeNameOf(annotation) {
|
|
|
645
713
|
return target.type === "identifier" ? target.text : stringLiteralValue(target);
|
|
646
714
|
}
|
|
647
715
|
function genericTypeArgs(node) {
|
|
648
|
-
const typeParameter = node.
|
|
649
|
-
(child) => child
|
|
716
|
+
const typeParameter = children(node).find(
|
|
717
|
+
(child) => child.type === "type_parameter"
|
|
650
718
|
);
|
|
651
|
-
return typeParameter
|
|
652
|
-
(child) => child !== null && child.type === "type"
|
|
653
|
-
) ?? [];
|
|
719
|
+
return children(typeParameter).filter((child) => child.type === "type");
|
|
654
720
|
}
|
|
655
721
|
function shapeFromGenericType(node, scope, ctx) {
|
|
656
722
|
const base = node.namedChild(0);
|
|
@@ -702,22 +768,44 @@ function recordShapeRef(name, classNode, ctx) {
|
|
|
702
768
|
return ref;
|
|
703
769
|
}
|
|
704
770
|
ctx.definitions.set(key, null);
|
|
771
|
+
ctx.definitions.set(key, {
|
|
772
|
+
type: "record",
|
|
773
|
+
properties: classFields(classNode, ctx, /* @__PURE__ */ new Set())
|
|
774
|
+
});
|
|
775
|
+
return ref;
|
|
776
|
+
}
|
|
777
|
+
function classFields(classNode, ctx, visiting) {
|
|
705
778
|
const bodyNode = field(classNode, "body");
|
|
706
779
|
const classScope = scopeOfNode(ctx, classNode);
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
780
|
+
if (bodyNode === null || classScope === void 0 || visiting.has(classNode.id)) {
|
|
781
|
+
return {};
|
|
782
|
+
}
|
|
783
|
+
visiting.add(classNode.id);
|
|
784
|
+
const inherited = baseClassNames(classNode).flatMap((name) => {
|
|
785
|
+
const base = projectClassNamed(name, classScope, ctx);
|
|
786
|
+
return base === null ? [] : [classFields(base, ctx, visiting)];
|
|
787
|
+
});
|
|
788
|
+
const own = recordShapeOf(bodyNode, classScope, ctx);
|
|
789
|
+
return Object.assign(
|
|
790
|
+
{},
|
|
791
|
+
...inherited.reverse(),
|
|
792
|
+
own.type === "record" ? own.properties : {}
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
function baseClassNames(classNode) {
|
|
796
|
+
const superclasses = field(classNode, "superclasses");
|
|
797
|
+
return children(superclasses).flatMap(
|
|
798
|
+
(child) => child.type === "identifier" ? [child.text] : []
|
|
710
799
|
);
|
|
711
|
-
return ref;
|
|
712
800
|
}
|
|
713
801
|
function recordShapeOf(bodyNode, classScope, ctx) {
|
|
714
802
|
const properties = {};
|
|
715
|
-
for (const stmt of bodyNode
|
|
803
|
+
for (const stmt of children(bodyNode)) {
|
|
716
804
|
if (stmt === null || stmt.type !== "expression_statement") {
|
|
717
805
|
continue;
|
|
718
806
|
}
|
|
719
|
-
const assignment2 = stmt.
|
|
720
|
-
(child) => child
|
|
807
|
+
const assignment2 = children(stmt).find(
|
|
808
|
+
(child) => child.type === "assignment"
|
|
721
809
|
);
|
|
722
810
|
if (assignment2 === void 0 || assignment2 === null) {
|
|
723
811
|
continue;
|
|
@@ -727,6 +815,9 @@ function recordShapeOf(bodyNode, classScope, ctx) {
|
|
|
727
815
|
if (left === null || left.type !== "identifier" || typeNode === null) {
|
|
728
816
|
continue;
|
|
729
817
|
}
|
|
818
|
+
if (typeNameOf(typeNode) === "ClassVar") {
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
730
821
|
properties[left.text] = annotationToShape(typeNode, classScope, ctx);
|
|
731
822
|
}
|
|
732
823
|
return { type: "record", properties };
|
|
@@ -743,8 +834,10 @@ import { nodeOfKey, noteKeyRead } from "@suss/resolution";
|
|
|
743
834
|
import { Evaluator, force, literalOf as literalOf2 } from "@suss/values";
|
|
744
835
|
|
|
745
836
|
// src/facts/resolve.ts
|
|
837
|
+
import { isTestFile } from "@suss/behavioral-ir";
|
|
746
838
|
import {
|
|
747
839
|
allocationSitesOf,
|
|
840
|
+
answersFromTestsLeftOut,
|
|
748
841
|
askResolution,
|
|
749
842
|
askResolutionUnder,
|
|
750
843
|
askSources,
|
|
@@ -802,7 +895,13 @@ function constructionSites(db, classKey) {
|
|
|
802
895
|
}
|
|
803
896
|
function writtenValueOf(db, key) {
|
|
804
897
|
resolveWritten(db, [key]);
|
|
805
|
-
return sharedWrittenValueOf(
|
|
898
|
+
return sharedWrittenValueOf(
|
|
899
|
+
db,
|
|
900
|
+
key,
|
|
901
|
+
(keys) => resolveWritten(db, keys),
|
|
902
|
+
void 0,
|
|
903
|
+
answersFromTestsLeftOut(key, isTestFile)
|
|
904
|
+
);
|
|
806
905
|
}
|
|
807
906
|
function writtenValuesOf(db, key) {
|
|
808
907
|
resolveWritten(db, [key]);
|
|
@@ -886,10 +985,14 @@ function objectReturnedBy(db, callKey) {
|
|
|
886
985
|
|
|
887
986
|
// src/facts/values.ts
|
|
888
987
|
import {
|
|
988
|
+
addEntryRows,
|
|
989
|
+
addTemplateRows,
|
|
889
990
|
NAMED_STORE_NAME,
|
|
890
991
|
RECEIVER_STORE_NAME,
|
|
992
|
+
SPREAD_ENTRY,
|
|
891
993
|
startsAtName,
|
|
892
994
|
UNPLACED_STORE_NAME,
|
|
995
|
+
VALUE_ENTRY,
|
|
893
996
|
valueLeftByWrites,
|
|
894
997
|
writesRunInOrder
|
|
895
998
|
} from "@suss/resolution";
|
|
@@ -900,6 +1003,8 @@ var CONVERTING_BUILTINS = /* @__PURE__ */ new Set([
|
|
|
900
1003
|
"str",
|
|
901
1004
|
"float"
|
|
902
1005
|
]);
|
|
1006
|
+
var ATTRIBUTE_GETTER = "getattr";
|
|
1007
|
+
var POSITION_COUNTER = "enumerate";
|
|
903
1008
|
|
|
904
1009
|
// src/facts/values.ts
|
|
905
1010
|
function nodeId(filePath, node) {
|
|
@@ -1071,8 +1176,7 @@ function emitConversion(emitter, call, callKey) {
|
|
|
1071
1176
|
return;
|
|
1072
1177
|
}
|
|
1073
1178
|
const name = callee.text;
|
|
1074
|
-
|
|
1075
|
-
if (builtin) {
|
|
1179
|
+
if (isBuiltin(emitter, name)) {
|
|
1076
1180
|
add(emitter, "converts", callKey, valueKey(emitter, first.node), name);
|
|
1077
1181
|
}
|
|
1078
1182
|
}
|
|
@@ -1121,6 +1225,7 @@ function emitSequence(emitter, sequence) {
|
|
|
1121
1225
|
const objectKey = nodeId(emitter.filePath, sequence);
|
|
1122
1226
|
add(emitter, "objectValue", objectKey);
|
|
1123
1227
|
let position = 0;
|
|
1228
|
+
const entries = [];
|
|
1124
1229
|
for (const element of children(sequence)) {
|
|
1125
1230
|
add(
|
|
1126
1231
|
emitter,
|
|
@@ -1130,12 +1235,21 @@ function emitSequence(emitter, sequence) {
|
|
|
1130
1235
|
valueKey(emitter, element)
|
|
1131
1236
|
);
|
|
1132
1237
|
position += 1;
|
|
1238
|
+
if (element.type !== "comment") {
|
|
1239
|
+
entries.push(writtenEntry(emitter, element));
|
|
1240
|
+
}
|
|
1133
1241
|
}
|
|
1242
|
+
addEntryRows(rowsOf(emitter), objectKey, entries);
|
|
1134
1243
|
}
|
|
1135
1244
|
function emitDictionary(emitter, dictionary) {
|
|
1136
1245
|
const objectKey = nodeId(emitter.filePath, dictionary);
|
|
1137
1246
|
add(emitter, "objectValue", objectKey);
|
|
1247
|
+
const entries = [];
|
|
1138
1248
|
for (const pair of children(dictionary)) {
|
|
1249
|
+
if (SPREAD_TYPES.has(pair.type)) {
|
|
1250
|
+
entries.push(writtenEntry(emitter, pair));
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1139
1253
|
if (pair.type !== "pair") {
|
|
1140
1254
|
continue;
|
|
1141
1255
|
}
|
|
@@ -1144,6 +1258,7 @@ function emitDictionary(emitter, dictionary) {
|
|
|
1144
1258
|
if (key === null || value === null) {
|
|
1145
1259
|
continue;
|
|
1146
1260
|
}
|
|
1261
|
+
entries.push(writtenEntry(emitter, value));
|
|
1147
1262
|
if (key.type !== "string") {
|
|
1148
1263
|
add(emitter, "holdsUnderKey", objectKey, valueKey(emitter, value));
|
|
1149
1264
|
continue;
|
|
@@ -1156,6 +1271,15 @@ function emitDictionary(emitter, dictionary) {
|
|
|
1156
1271
|
valueKey(emitter, value)
|
|
1157
1272
|
);
|
|
1158
1273
|
}
|
|
1274
|
+
addEntryRows(rowsOf(emitter), objectKey, entries);
|
|
1275
|
+
}
|
|
1276
|
+
var SPREAD_TYPES = /* @__PURE__ */ new Set(["list_splat", "dictionary_splat"]);
|
|
1277
|
+
function writtenEntry(emitter, entry) {
|
|
1278
|
+
const unpacked = SPREAD_TYPES.has(entry.type) ? children(entry)[0] : void 0;
|
|
1279
|
+
return unpacked === void 0 ? { key: valueKey(emitter, entry), form: VALUE_ENTRY } : { key: valueKey(emitter, unpacked), form: SPREAD_ENTRY };
|
|
1280
|
+
}
|
|
1281
|
+
function rowsOf(emitter) {
|
|
1282
|
+
return (relation, row) => add(emitter, relation, ...row);
|
|
1159
1283
|
}
|
|
1160
1284
|
function emitAttribute(emitter, attribute) {
|
|
1161
1285
|
const object = field(attribute, "object");
|
|
@@ -1220,13 +1344,50 @@ function emitKeyedRead(emitter, site, container, key) {
|
|
|
1220
1344
|
if (WRITTEN_KEY_TYPES.has(key.type)) {
|
|
1221
1345
|
return;
|
|
1222
1346
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1347
|
+
const siteKey = nodeId(emitter.filePath, site);
|
|
1348
|
+
const containerKey = valueKey(emitter, container);
|
|
1349
|
+
add(emitter, "readsKeyed", siteKey, containerKey, valueKey(emitter, key));
|
|
1350
|
+
add(emitter, "choosesEntry", siteKey, containerKey);
|
|
1351
|
+
}
|
|
1352
|
+
function emitAttributeChoice(emitter, call) {
|
|
1353
|
+
const callee = field(call, "function");
|
|
1354
|
+
const [target, name] = callArguments(call);
|
|
1355
|
+
if (callee?.type !== "identifier" || callee.text !== ATTRIBUTE_GETTER || !isBuiltin(emitter, callee.text) || target?.kind !== "positional" || name?.kind !== "positional") {
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
const siteKey = nodeId(emitter.filePath, call);
|
|
1359
|
+
const targetKey = valueKey(emitter, target.node);
|
|
1360
|
+
const written = plainStringOf(name.node);
|
|
1361
|
+
if (written !== null) {
|
|
1362
|
+
add(emitter, "choosesNamedEntry", siteKey, targetKey, written);
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
const ends = writtenEnds(name.node);
|
|
1366
|
+
if (ends === null) {
|
|
1367
|
+
add(emitter, "choosesEntry", siteKey, targetKey);
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
add(emitter, "choosesEntryLike", siteKey, targetKey, ends.start, ends.end);
|
|
1371
|
+
}
|
|
1372
|
+
function writtenEnds(node) {
|
|
1373
|
+
if (node.type !== "string") {
|
|
1374
|
+
return null;
|
|
1375
|
+
}
|
|
1376
|
+
const parts = children(node).filter(
|
|
1377
|
+
(part) => part.type !== "string_start" && part.type !== "string_end"
|
|
1229
1378
|
);
|
|
1379
|
+
const written = (part) => part.type === "string_content";
|
|
1380
|
+
const firstComputed = parts.findIndex((part) => !written(part));
|
|
1381
|
+
if (firstComputed === -1) {
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
const lastComputed = parts.length - 1 - [...parts].reverse().findIndex((part) => !written(part));
|
|
1385
|
+
const start = parts.slice(0, firstComputed).map((part) => part.text).join("");
|
|
1386
|
+
const end = parts.slice(lastComputed + 1).map((part) => part.text).join("");
|
|
1387
|
+
return start === "" && end === "" ? null : { start, end };
|
|
1388
|
+
}
|
|
1389
|
+
function isBuiltin(emitter, name) {
|
|
1390
|
+
return nameKey(emitter.filePath, emitter.enclosing, name) === nameId(emitter.filePath, name) && !emitter.moduleNames().has(name);
|
|
1230
1391
|
}
|
|
1231
1392
|
function emitWrittenKeyRead(emitter, site, container, key) {
|
|
1232
1393
|
const name = plainStringOf(key);
|
|
@@ -1362,6 +1523,86 @@ function emitComprehensionElement(emitter, comprehension) {
|
|
|
1362
1523
|
);
|
|
1363
1524
|
}
|
|
1364
1525
|
}
|
|
1526
|
+
var PAIR_TARGET_TYPES = /* @__PURE__ */ new Set(["pattern_list", "tuple_pattern"]);
|
|
1527
|
+
function emitElementVariables(emitter, clause) {
|
|
1528
|
+
const target = field(clause, "left");
|
|
1529
|
+
const over = field(clause, "right");
|
|
1530
|
+
if (target === null || over === null) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
const names = PAIR_TARGET_TYPES.has(target.type) ? children(target) : [];
|
|
1534
|
+
const [position, element] = names;
|
|
1535
|
+
const counted = countedCollection(emitter, over);
|
|
1536
|
+
if (counted !== null && names.length === 2 && position?.type === "identifier" && element !== void 0) {
|
|
1537
|
+
emitElementTaken(emitter, element, valueKey(emitter, counted), position);
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
emitElementTaken(emitter, target, valueKey(emitter, over), null);
|
|
1541
|
+
}
|
|
1542
|
+
function emitElementTaken(emitter, target, overKey, position) {
|
|
1543
|
+
const variables = target.type === "identifier" ? [{ node: target, part: null }] : partsTakenApart(target);
|
|
1544
|
+
for (const variable of variables) {
|
|
1545
|
+
const key = valueKey(emitter, variable.node);
|
|
1546
|
+
if (variable.part === null) {
|
|
1547
|
+
add(emitter, "elementOf", key, overKey);
|
|
1548
|
+
continue;
|
|
1549
|
+
}
|
|
1550
|
+
add(emitter, "elementPartOf", key, overKey, variable.part);
|
|
1551
|
+
}
|
|
1552
|
+
const [first] = variables;
|
|
1553
|
+
if (position !== null && first !== void 0) {
|
|
1554
|
+
add(
|
|
1555
|
+
emitter,
|
|
1556
|
+
"positionOf",
|
|
1557
|
+
valueKey(emitter, position),
|
|
1558
|
+
valueKey(emitter, first.node)
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
function partsTakenApart(target) {
|
|
1563
|
+
const parts = [];
|
|
1564
|
+
if (!PAIR_TARGET_TYPES.has(target.type)) {
|
|
1565
|
+
return parts;
|
|
1566
|
+
}
|
|
1567
|
+
for (const [position, part] of children(target).entries()) {
|
|
1568
|
+
if (part.type === "list_splat_pattern") {
|
|
1569
|
+
break;
|
|
1570
|
+
}
|
|
1571
|
+
if (part.type === "identifier") {
|
|
1572
|
+
parts.push({ node: part, part: String(position) });
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
return parts;
|
|
1576
|
+
}
|
|
1577
|
+
function countedCollection(emitter, over) {
|
|
1578
|
+
const callee = over.type === "call" ? field(over, "function") : null;
|
|
1579
|
+
const args = field(over, "arguments");
|
|
1580
|
+
const [first] = callArguments(over);
|
|
1581
|
+
if (callee?.type !== "identifier" || callee.text !== POSITION_COUNTER || !isBuiltin(emitter, POSITION_COUNTER) || args === null || writtenArgumentCount(args) !== 1 || first?.kind !== "positional") {
|
|
1582
|
+
return null;
|
|
1583
|
+
}
|
|
1584
|
+
return first.node;
|
|
1585
|
+
}
|
|
1586
|
+
function interpolatedPieces(emitter, string2) {
|
|
1587
|
+
const parts = children(string2);
|
|
1588
|
+
if (!parts.some((part) => part.type === "interpolation")) {
|
|
1589
|
+
return [];
|
|
1590
|
+
}
|
|
1591
|
+
return parts.flatMap((part) => {
|
|
1592
|
+
if (part.type === "string_content") {
|
|
1593
|
+
return [{ text: stringContentValue(part) }];
|
|
1594
|
+
}
|
|
1595
|
+
const expression = part.type === "interpolation" ? field(part, "expression") ?? children(part)[0] : void 0;
|
|
1596
|
+
return expression === void 0 ? [] : [{ hole: valueKey(emitter, expression) }];
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
function adjacentPieces(emitter, joined2) {
|
|
1600
|
+
return children(joined2).filter((part) => part.type !== "comment").map((part) => ({ hole: valueKey(emitter, part) }));
|
|
1601
|
+
}
|
|
1602
|
+
var TEMPLATE_PIECES = {
|
|
1603
|
+
string: interpolatedPieces,
|
|
1604
|
+
concatenated_string: adjacentPieces
|
|
1605
|
+
};
|
|
1365
1606
|
function emitExpressionFact(emitter, child, type) {
|
|
1366
1607
|
if (type === "call") {
|
|
1367
1608
|
emitCall(emitter, child);
|
|
@@ -1369,6 +1610,7 @@ function emitExpressionFact(emitter, child, type) {
|
|
|
1369
1610
|
if (mapping !== null) {
|
|
1370
1611
|
emitKeyedRead(emitter, child, mapping.container, mapping.key);
|
|
1371
1612
|
}
|
|
1613
|
+
emitAttributeChoice(emitter, child);
|
|
1372
1614
|
}
|
|
1373
1615
|
if (type === "subscript") {
|
|
1374
1616
|
const index = singleSubscript(child);
|
|
@@ -1398,6 +1640,13 @@ function emitExpressionFact(emitter, child, type) {
|
|
|
1398
1640
|
if (COMPREHENSION_TYPES.has(type)) {
|
|
1399
1641
|
emitComprehensionElement(emitter, child);
|
|
1400
1642
|
}
|
|
1643
|
+
if (type === "for_in_clause") {
|
|
1644
|
+
emitElementVariables(emitter, child);
|
|
1645
|
+
}
|
|
1646
|
+
const pieces = TEMPLATE_PIECES[type]?.(emitter, child) ?? [];
|
|
1647
|
+
if (pieces.length > 0) {
|
|
1648
|
+
addTemplateRows(rowsOf(emitter), nodeId(emitter.filePath, child), pieces);
|
|
1649
|
+
}
|
|
1401
1650
|
const branches = fallbackBranchesOf(child, type);
|
|
1402
1651
|
if (branches !== null) {
|
|
1403
1652
|
for (const branch of branches) {
|
|
@@ -1430,10 +1679,10 @@ function emitExpressionFacts(emitter, node) {
|
|
|
1430
1679
|
});
|
|
1431
1680
|
}
|
|
1432
1681
|
function yieldedValue(node) {
|
|
1433
|
-
if (node.
|
|
1682
|
+
if (allChildren(node).some((child) => child.type === "from")) {
|
|
1434
1683
|
return null;
|
|
1435
1684
|
}
|
|
1436
|
-
return node.
|
|
1685
|
+
return children(node).find((child) => child?.type !== "comment") ?? null;
|
|
1437
1686
|
}
|
|
1438
1687
|
function emitFunctionFacts(emitter, fn, classKey) {
|
|
1439
1688
|
const funcKey = nodeId(emitter.filePath, fn);
|
|
@@ -1505,7 +1754,7 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1505
1754
|
const stores = /* @__PURE__ */ new Map();
|
|
1506
1755
|
const visit = (child, type) => {
|
|
1507
1756
|
if (type === "return_statement") {
|
|
1508
|
-
const returned = child.
|
|
1757
|
+
const returned = child.namedChild(0);
|
|
1509
1758
|
if (returned != null) {
|
|
1510
1759
|
add(inside, "returnsValue", funcKey, valueKey(inside, returned));
|
|
1511
1760
|
statesReturn = true;
|
|
@@ -1916,6 +2165,9 @@ function readUnderName(emitter, statement, funcKey, accessed) {
|
|
|
1916
2165
|
function emitNestedDefinitions(emitter, node) {
|
|
1917
2166
|
for (const child of children(node)) {
|
|
1918
2167
|
const type = child.type;
|
|
2168
|
+
if (type === "decorated_definition") {
|
|
2169
|
+
emitDecoratorCalls(emitter, child);
|
|
2170
|
+
}
|
|
1919
2171
|
if (FUNCTION_TYPES.has(type)) {
|
|
1920
2172
|
emitFunctionFacts(emitter, child);
|
|
1921
2173
|
if (emitter.enclosing !== null) {
|
|
@@ -1935,6 +2187,20 @@ function emitNestedDefinitions(emitter, node) {
|
|
|
1935
2187
|
emitNestedDefinitions(emitter, child);
|
|
1936
2188
|
}
|
|
1937
2189
|
}
|
|
2190
|
+
function emitDecoratorCalls(emitter, decorated) {
|
|
2191
|
+
const { definition, decorators } = stripDecorators(decorated);
|
|
2192
|
+
let applied = nodeId(emitter.filePath, definition);
|
|
2193
|
+
for (const decorator of [...decorators].reverse()) {
|
|
2194
|
+
const [expression] = children(decorator);
|
|
2195
|
+
if (expression === void 0) {
|
|
2196
|
+
continue;
|
|
2197
|
+
}
|
|
2198
|
+
const callKey = nodeId(emitter.filePath, decorator);
|
|
2199
|
+
add(emitter, "call", callKey, valueKey(emitter, expression));
|
|
2200
|
+
add(emitter, "callArg", callKey, "0", applied);
|
|
2201
|
+
applied = callKey;
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
1938
2204
|
var readingsByTree = /* @__PURE__ */ new WeakMap();
|
|
1939
2205
|
function scopeReadingOf(fn, given) {
|
|
1940
2206
|
const tree = fn.tree;
|
|
@@ -2543,9 +2809,7 @@ function stringExpression(node) {
|
|
|
2543
2809
|
}
|
|
2544
2810
|
function comparisonExpression(node) {
|
|
2545
2811
|
const operands = children(node);
|
|
2546
|
-
const operators = node.
|
|
2547
|
-
(child) => child !== null && !child.isNamed
|
|
2548
|
-
);
|
|
2812
|
+
const operators = allChildren(node).filter((child) => !child.isNamed);
|
|
2549
2813
|
const operator = operators[0];
|
|
2550
2814
|
if (operands.length !== 2 || operators.length !== 1 || operator === void 0) {
|
|
2551
2815
|
return { kind: "opaque" };
|
|
@@ -2639,6 +2903,7 @@ var STATEMENT_TYPES = {
|
|
|
2639
2903
|
kind: "return",
|
|
2640
2904
|
value: children(node)[0] ?? null
|
|
2641
2905
|
}),
|
|
2906
|
+
raise_statement: (node) => caughtInSameFunction(node) ? OPAQUE : { kind: "throw" },
|
|
2642
2907
|
try_statement: (node) => ({
|
|
2643
2908
|
kind: "block",
|
|
2644
2909
|
body: [
|
|
@@ -2727,6 +2992,19 @@ function blockStatements(block) {
|
|
|
2727
2992
|
function isRoot(node) {
|
|
2728
2993
|
return ROOT_TYPES.has(node.type);
|
|
2729
2994
|
}
|
|
2995
|
+
var EXCEPT_CLAUSE_TYPES = /* @__PURE__ */ new Set(["except_clause", "except_group_clause"]);
|
|
2996
|
+
function caughtInSameFunction(node) {
|
|
2997
|
+
let child = node;
|
|
2998
|
+
let parent = node.parent;
|
|
2999
|
+
while (parent !== null && !isRoot(parent)) {
|
|
3000
|
+
if (parent.type === "try_statement" && field(parent, "body")?.id === child.id && children(parent).some((clause) => EXCEPT_CLAUSE_TYPES.has(clause.type))) {
|
|
3001
|
+
return true;
|
|
3002
|
+
}
|
|
3003
|
+
child = parent;
|
|
3004
|
+
parent = parent.parent;
|
|
3005
|
+
}
|
|
3006
|
+
return false;
|
|
3007
|
+
}
|
|
2730
3008
|
function isPathStatement(node, parent) {
|
|
2731
3009
|
return parent.type === "module" || parent.type === "block" || node.type === "elif_clause";
|
|
2732
3010
|
}
|
|
@@ -3139,6 +3417,10 @@ function writtenNodeOf(node, db) {
|
|
|
3139
3417
|
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
3140
3418
|
return bound?.context.writtenTo(node) ?? null;
|
|
3141
3419
|
}
|
|
3420
|
+
function calledDefinition(call, db) {
|
|
3421
|
+
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
3422
|
+
return bound?.context.callable(call) ?? null;
|
|
3423
|
+
}
|
|
3142
3424
|
function resolutionKeyOf(node, db) {
|
|
3143
3425
|
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
3144
3426
|
return bound?.keyOf(node) ?? null;
|
|
@@ -3361,7 +3643,7 @@ function argShapeOf(node) {
|
|
|
3361
3643
|
if (node.type === "list") {
|
|
3362
3644
|
return {
|
|
3363
3645
|
kind: "list",
|
|
3364
|
-
items: node
|
|
3646
|
+
items: children(node).map(readArg)
|
|
3365
3647
|
};
|
|
3366
3648
|
}
|
|
3367
3649
|
return { kind: "other" };
|
|
@@ -3372,10 +3654,7 @@ function readCallArguments(argumentList) {
|
|
|
3372
3654
|
if (argumentList === null) {
|
|
3373
3655
|
return { args, keywordArgs };
|
|
3374
3656
|
}
|
|
3375
|
-
for (const child of argumentList
|
|
3376
|
-
if (child === null) {
|
|
3377
|
-
continue;
|
|
3378
|
-
}
|
|
3657
|
+
for (const child of children(argumentList)) {
|
|
3379
3658
|
if (child.type === "keyword_argument") {
|
|
3380
3659
|
const nameNode = field(child, "name");
|
|
3381
3660
|
const valueNode = field(child, "value");
|
|
@@ -3501,10 +3780,10 @@ function unwrapDecorator(decoratorNode, facts) {
|
|
|
3501
3780
|
}
|
|
3502
3781
|
function passesParametersThrough(def, inner) {
|
|
3503
3782
|
const params = field(def, "parameters");
|
|
3504
|
-
const names = (params
|
|
3783
|
+
const names = children(params).filter((child) => child.type === "identifier").map((child) => child.text);
|
|
3505
3784
|
const argumentList = field(inner, "arguments");
|
|
3506
|
-
const positional = (argumentList
|
|
3507
|
-
(child) => child
|
|
3785
|
+
const positional = children(argumentList).filter(
|
|
3786
|
+
(child) => child.type !== "keyword_argument"
|
|
3508
3787
|
);
|
|
3509
3788
|
return positional.length === names.length && positional.every(
|
|
3510
3789
|
(argument, at) => argument.type === "identifier" && argument.text === names[at]
|
|
@@ -3527,8 +3806,14 @@ import {
|
|
|
3527
3806
|
import { constantOf as constantOf5, literalOf as literalOf6, pathOf as pathOf2 } from "@suss/values";
|
|
3528
3807
|
|
|
3529
3808
|
// src/clientCalls.ts
|
|
3530
|
-
import {
|
|
3531
|
-
|
|
3809
|
+
import {
|
|
3810
|
+
hasNameHole,
|
|
3811
|
+
restBinding,
|
|
3812
|
+
statusMembersOf,
|
|
3813
|
+
testsStatus
|
|
3814
|
+
} from "@suss/behavioral-ir";
|
|
3815
|
+
import { redirectDeliveryWhenSet } from "@suss/extractor";
|
|
3816
|
+
import { hostOf, pathOf, scalarOf } from "@suss/values";
|
|
3532
3817
|
|
|
3533
3818
|
// src/paths/bodyBranches.ts
|
|
3534
3819
|
import { enumerateOrDegrade as enumerateOrDegrade2, guardsHoldOn } from "@suss/extractor";
|
|
@@ -3549,7 +3834,7 @@ var COMPARISONS = {
|
|
|
3549
3834
|
"<=": "lte"
|
|
3550
3835
|
};
|
|
3551
3836
|
function operatorText(node) {
|
|
3552
|
-
return node.
|
|
3837
|
+
return allChildren(node).filter((child) => !child.isNamed).map((child) => child.text).join(" ");
|
|
3553
3838
|
}
|
|
3554
3839
|
function valueRefOf(node, facts, inputs) {
|
|
3555
3840
|
const value = evaluatedValue(node, facts);
|
|
@@ -3601,7 +3886,7 @@ function nullCheckOf(subject, negated2, facts, inputs) {
|
|
|
3601
3886
|
};
|
|
3602
3887
|
}
|
|
3603
3888
|
function comparisonOf(node, facts, inputs) {
|
|
3604
|
-
const [left, right] = node.
|
|
3889
|
+
const [left, right] = children(node).filter(
|
|
3605
3890
|
(child) => child !== null
|
|
3606
3891
|
);
|
|
3607
3892
|
if (left === void 0 || right === void 0) {
|
|
@@ -3630,14 +3915,14 @@ function comparisonOf(node, facts, inputs) {
|
|
|
3630
3915
|
}
|
|
3631
3916
|
function predicateOf(node, facts, inputs) {
|
|
3632
3917
|
if (node.type === "parenthesized_expression") {
|
|
3633
|
-
const inner = node.
|
|
3918
|
+
const inner = node.namedChild(0);
|
|
3634
3919
|
return inner == null ? opaqueOf(node) : predicateOf(inner, facts, inputs);
|
|
3635
3920
|
}
|
|
3636
3921
|
if (node.type === "comparison_operator") {
|
|
3637
3922
|
return comparisonOf(node, facts, inputs);
|
|
3638
3923
|
}
|
|
3639
3924
|
if (node.type === "not_operator") {
|
|
3640
|
-
const operand2 = field(node, "argument") ?? node.
|
|
3925
|
+
const operand2 = field(node, "argument") ?? node.namedChild(0);
|
|
3641
3926
|
return operand2 == null ? opaqueOf(node) : { type: "negation", operand: predicateOf(operand2, facts, inputs) };
|
|
3642
3927
|
}
|
|
3643
3928
|
if (node.type === "identifier" || node.type === "attribute" || inputs?.has(node.id) === true) {
|
|
@@ -3652,11 +3937,11 @@ function predicateOf(node, facts, inputs) {
|
|
|
3652
3937
|
var SUBJECT_TYPES = /* @__PURE__ */ new Set(["identifier", "attribute", "subscript"]);
|
|
3653
3938
|
function operandsOf(node) {
|
|
3654
3939
|
if (node.type === "parenthesized_expression" || node.type === "not_operator") {
|
|
3655
|
-
const inner = field(node, "argument") ?? node.
|
|
3940
|
+
const inner = field(node, "argument") ?? node.namedChild(0);
|
|
3656
3941
|
return inner == null ? [] : operandsOf(inner);
|
|
3657
3942
|
}
|
|
3658
3943
|
if (node.type === "comparison_operator") {
|
|
3659
|
-
return node.
|
|
3944
|
+
return children(node).filter(
|
|
3660
3945
|
(child) => child !== null && SUBJECT_TYPES.has(child.type)
|
|
3661
3946
|
);
|
|
3662
3947
|
}
|
|
@@ -3682,7 +3967,7 @@ var NESTED_FUNCTION_TYPES = /* @__PURE__ */ new Set(["function_definition", "lam
|
|
|
3682
3967
|
function exitKindOf(node, thrown) {
|
|
3683
3968
|
let sawReturn = false;
|
|
3684
3969
|
const raises = (current) => {
|
|
3685
|
-
for (const child of current
|
|
3970
|
+
for (const child of children(current)) {
|
|
3686
3971
|
if (child === null || NESTED_FUNCTION_TYPES.has(child.type)) {
|
|
3687
3972
|
continue;
|
|
3688
3973
|
}
|
|
@@ -3710,12 +3995,10 @@ function blockStatements2(block) {
|
|
|
3710
3995
|
if (block === null) {
|
|
3711
3996
|
return [];
|
|
3712
3997
|
}
|
|
3713
|
-
return block
|
|
3998
|
+
return children(block);
|
|
3714
3999
|
}
|
|
3715
4000
|
function childBlock(node) {
|
|
3716
|
-
return node.
|
|
3717
|
-
(child) => child !== null && child.type === "block"
|
|
3718
|
-
) ?? null;
|
|
4001
|
+
return children(node).find((child) => child.type === "block") ?? null;
|
|
3719
4002
|
}
|
|
3720
4003
|
var Lowerer = class {
|
|
3721
4004
|
// tree-sitter hands back a fresh wrapper object each time a child is
|
|
@@ -3764,7 +4047,7 @@ var Lowerer = class {
|
|
|
3764
4047
|
return [nested];
|
|
3765
4048
|
}
|
|
3766
4049
|
lowerIf(node) {
|
|
3767
|
-
const clauses = node.
|
|
4050
|
+
const clauses = children(node).filter(
|
|
3768
4051
|
(child) => child !== null && (child.type === "elif_clause" || child.type === "else_clause")
|
|
3769
4052
|
);
|
|
3770
4053
|
return {
|
|
@@ -3776,10 +4059,10 @@ var Lowerer = class {
|
|
|
3776
4059
|
};
|
|
3777
4060
|
}
|
|
3778
4061
|
lowerTry(node) {
|
|
3779
|
-
const excepts = node.
|
|
4062
|
+
const excepts = children(node).filter(
|
|
3780
4063
|
(child) => child !== null && (child.type === "except_clause" || child.type === "except_group_clause")
|
|
3781
4064
|
);
|
|
3782
|
-
const finallyClause = node.
|
|
4065
|
+
const finallyClause = children(node).find(
|
|
3783
4066
|
(child) => child !== null && child.type === "finally_clause"
|
|
3784
4067
|
) ?? null;
|
|
3785
4068
|
return {
|
|
@@ -3795,7 +4078,7 @@ var Lowerer = class {
|
|
|
3795
4078
|
(child) => child.type === "case_clause"
|
|
3796
4079
|
);
|
|
3797
4080
|
const groups = cases.map((clause) => {
|
|
3798
|
-
const pattern = clause.
|
|
4081
|
+
const pattern = children(clause).find(
|
|
3799
4082
|
(child) => child !== null && child.type === "case_pattern"
|
|
3800
4083
|
) ?? null;
|
|
3801
4084
|
return {
|
|
@@ -3876,7 +4159,7 @@ function literalArgOf(node, facts) {
|
|
|
3876
4159
|
return null;
|
|
3877
4160
|
}
|
|
3878
4161
|
function bodyCalls(node, found = []) {
|
|
3879
|
-
for (const child of node
|
|
4162
|
+
for (const child of children(node)) {
|
|
3880
4163
|
if (child === null || NESTED_DEFINITION_TYPES.has(child.type)) {
|
|
3881
4164
|
continue;
|
|
3882
4165
|
}
|
|
@@ -3888,7 +4171,7 @@ function bodyCalls(node, found = []) {
|
|
|
3888
4171
|
return found;
|
|
3889
4172
|
}
|
|
3890
4173
|
function moduleLoadCalls(node, found = []) {
|
|
3891
|
-
for (const child of node
|
|
4174
|
+
for (const child of children(node)) {
|
|
3892
4175
|
if (child === null || !runsAtModuleLoad(child)) {
|
|
3893
4176
|
continue;
|
|
3894
4177
|
}
|
|
@@ -3928,7 +4211,7 @@ function argumentNodes(call) {
|
|
|
3928
4211
|
if (args === null) {
|
|
3929
4212
|
return [];
|
|
3930
4213
|
}
|
|
3931
|
-
return args
|
|
4214
|
+
return children(args).map(
|
|
3932
4215
|
(child) => child.type === "keyword_argument" ? field(child, "value") ?? child : child
|
|
3933
4216
|
);
|
|
3934
4217
|
}
|
|
@@ -3939,6 +4222,9 @@ function calleeText(call) {
|
|
|
3939
4222
|
return field(call, "function")?.text ?? call.text;
|
|
3940
4223
|
}
|
|
3941
4224
|
function invocationEffects(definitionNode, facts) {
|
|
4225
|
+
return invocationSites(definitionNode, facts).map((site) => site.effect);
|
|
4226
|
+
}
|
|
4227
|
+
function invocationSites(definitionNode, facts) {
|
|
3942
4228
|
const body = field(definitionNode, "body");
|
|
3943
4229
|
if (body === null) {
|
|
3944
4230
|
return [];
|
|
@@ -3946,14 +4232,18 @@ function invocationEffects(definitionNode, facts) {
|
|
|
3946
4232
|
return invocationEffectsIn(body, bodyCalls(body), facts);
|
|
3947
4233
|
}
|
|
3948
4234
|
function moduleLoadInvocationEffects(moduleNode, facts) {
|
|
3949
|
-
return invocationEffectsIn(
|
|
4235
|
+
return invocationEffectsIn(
|
|
4236
|
+
moduleNode,
|
|
4237
|
+
moduleLoadCalls(moduleNode),
|
|
4238
|
+
facts
|
|
4239
|
+
).map((site) => site.effect);
|
|
3950
4240
|
}
|
|
3951
4241
|
var ASKED_ABOUT_TYPES = /* @__PURE__ */ new Set(["identifier", "attribute", "call"]);
|
|
3952
4242
|
function askedNodesUnder(node, found = []) {
|
|
3953
4243
|
if (ASKED_ABOUT_TYPES.has(node.type)) {
|
|
3954
4244
|
found.push(node);
|
|
3955
4245
|
}
|
|
3956
|
-
for (const child of node
|
|
4246
|
+
for (const child of children(node)) {
|
|
3957
4247
|
if (child !== null && !NESTED_DEFINITION_TYPES.has(child.type)) {
|
|
3958
4248
|
askedNodesUnder(child, found);
|
|
3959
4249
|
}
|
|
@@ -4027,11 +4317,14 @@ function invocationEffectsIn(body, written, facts) {
|
|
|
4027
4317
|
(condition) => predicateOf(condition, facts, inputs)
|
|
4028
4318
|
);
|
|
4029
4319
|
return {
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4320
|
+
call,
|
|
4321
|
+
effect: {
|
|
4322
|
+
type: "invocation",
|
|
4323
|
+
callee: calleeText(call),
|
|
4324
|
+
args: argsOf(call, facts),
|
|
4325
|
+
async: false,
|
|
4326
|
+
...conditions.length > 0 ? { preconditions: conditions } : {}
|
|
4327
|
+
}
|
|
4035
4328
|
};
|
|
4036
4329
|
});
|
|
4037
4330
|
}
|
|
@@ -4066,7 +4359,7 @@ function statedBy(statement, name) {
|
|
|
4066
4359
|
}
|
|
4067
4360
|
if (statement.type === "as_pattern") {
|
|
4068
4361
|
const alias = field(statement, "alias");
|
|
4069
|
-
const value = statement.
|
|
4362
|
+
const value = statement.namedChild(0) ?? null;
|
|
4070
4363
|
const callee = value?.type === "call" ? field(value, "function") : null;
|
|
4071
4364
|
return alias?.text === name ? callee : null;
|
|
4072
4365
|
}
|
|
@@ -4262,7 +4555,7 @@ function importedFunctionMatch(call, options) {
|
|
|
4262
4555
|
return null;
|
|
4263
4556
|
}
|
|
4264
4557
|
const args = field(call, "arguments");
|
|
4265
|
-
const first = args
|
|
4558
|
+
const first = children(args)[0] ?? null;
|
|
4266
4559
|
const statement = first === null ? null : writtenStatement(first, void 0, options.facts);
|
|
4267
4560
|
if (statement === null) {
|
|
4268
4561
|
return null;
|
|
@@ -4626,7 +4919,7 @@ function columnComparisons(node) {
|
|
|
4626
4919
|
const args = field(node, "arguments");
|
|
4627
4920
|
return (args === null ? [] : children(args)).flatMap(columnComparisons);
|
|
4628
4921
|
}
|
|
4629
|
-
const operator = node.
|
|
4922
|
+
const operator = allChildren(node).find((child) => !child.isNamed);
|
|
4630
4923
|
const [left, right, ...rest] = children(node);
|
|
4631
4924
|
if (node.type !== "comparison_operator" || operator?.type !== "==" || left === void 0 || right === void 0 || rest.length > 0) {
|
|
4632
4925
|
return [];
|
|
@@ -4645,13 +4938,37 @@ function modelColumn(node) {
|
|
|
4645
4938
|
}
|
|
4646
4939
|
return field(node, "attribute")?.text ?? null;
|
|
4647
4940
|
}
|
|
4648
|
-
function selectorOf(chain, valueMethods) {
|
|
4941
|
+
function selectorOf(chain, valueMethods, model) {
|
|
4942
|
+
const picking = laterCalls(chain).filter(
|
|
4943
|
+
(call) => !valueMethods.includes(methodNameOf(call))
|
|
4944
|
+
);
|
|
4649
4945
|
return [
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4946
|
+
.../* @__PURE__ */ new Set([
|
|
4947
|
+
...picking.flatMap((call) => pickedBy(call).map((one) => one.name)),
|
|
4948
|
+
...model === null ? [] : picking.flatMap((call) => columnsComparedBy(call, model))
|
|
4949
|
+
])
|
|
4653
4950
|
];
|
|
4654
4951
|
}
|
|
4952
|
+
var COMBINED_TESTS = ["and_", "or_", "not_"];
|
|
4953
|
+
function columnsComparedBy(call, model) {
|
|
4954
|
+
const args = field(call, "arguments");
|
|
4955
|
+
return (args === null ? [] : children(args)).flatMap(
|
|
4956
|
+
(argument) => columnsCompared(argument, model)
|
|
4957
|
+
);
|
|
4958
|
+
}
|
|
4959
|
+
function columnsCompared(node, model) {
|
|
4960
|
+
if (node.type === "call" && COMBINED_TESTS.includes(methodNameOf(node))) {
|
|
4961
|
+
return columnsComparedBy(node, model);
|
|
4962
|
+
}
|
|
4963
|
+
if (node.type !== "comparison_operator") {
|
|
4964
|
+
return [];
|
|
4965
|
+
}
|
|
4966
|
+
return children(node).flatMap((side) => {
|
|
4967
|
+
const object = side.type === "attribute" ? field(side, "object") : null;
|
|
4968
|
+
const column = object?.text === model ? field(side, "attribute") : null;
|
|
4969
|
+
return column === null ? [] : [column.text];
|
|
4970
|
+
});
|
|
4971
|
+
}
|
|
4655
4972
|
var TABLE_METHODS = ["select_from", "join"];
|
|
4656
4973
|
function modelOf(chain, options) {
|
|
4657
4974
|
const fromRoot = modelArgument(chain.root, chain.root, options);
|
|
@@ -4716,14 +5033,15 @@ function isClassName(name) {
|
|
|
4716
5033
|
}
|
|
4717
5034
|
function effectFor2(pattern, chain, operation, options) {
|
|
4718
5035
|
const valueMethods = pattern.valueMethods ?? [];
|
|
4719
|
-
const
|
|
5036
|
+
const model = modelOf(chain, options);
|
|
5037
|
+
const picked = selectorOf(chain, valueMethods, model);
|
|
4720
5038
|
const effect = {
|
|
4721
5039
|
type: "interaction",
|
|
4722
5040
|
binding: storageBinding2({
|
|
4723
5041
|
recognition: "python-storage",
|
|
4724
5042
|
storageSystem: pattern.storageSystem,
|
|
4725
5043
|
scope: "default",
|
|
4726
|
-
container:
|
|
5044
|
+
container: model
|
|
4727
5045
|
}),
|
|
4728
5046
|
callee: chain.last.text,
|
|
4729
5047
|
interaction: {
|
|
@@ -4999,10 +5317,7 @@ function literalAt(key, facts) {
|
|
|
4999
5317
|
|
|
5000
5318
|
// src/paths/bodyBranches.ts
|
|
5001
5319
|
function returnStatements(node, found = []) {
|
|
5002
|
-
for (const child of node
|
|
5003
|
-
if (child === null) {
|
|
5004
|
-
continue;
|
|
5005
|
-
}
|
|
5320
|
+
for (const child of children(node)) {
|
|
5006
5321
|
if (child.type === "function_definition" || child.type === "lambda") {
|
|
5007
5322
|
continue;
|
|
5008
5323
|
}
|
|
@@ -5059,7 +5374,8 @@ function enumerateBodyBranches(options) {
|
|
|
5059
5374
|
const enumerated = enumerateOrDegrade2(
|
|
5060
5375
|
{
|
|
5061
5376
|
statements: lowered.statements,
|
|
5062
|
-
terminalsByStmt: lowered.terminalsByStmt
|
|
5377
|
+
terminalsByStmt: lowered.terminalsByStmt,
|
|
5378
|
+
...options.keepsArms === void 0 ? {} : { keepsArms: options.keepsArms }
|
|
5063
5379
|
},
|
|
5064
5380
|
statements
|
|
5065
5381
|
);
|
|
@@ -5096,66 +5412,296 @@ function enumerateBodyBranches(options) {
|
|
|
5096
5412
|
return branches;
|
|
5097
5413
|
}
|
|
5098
5414
|
|
|
5099
|
-
// src/
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
continue;
|
|
5106
|
-
}
|
|
5107
|
-
for (const call of bodyCalls(definition)) {
|
|
5108
|
-
for (const request of requestCalls(call, pattern, module, options)) {
|
|
5109
|
-
units.push(
|
|
5110
|
-
clientUnit(definition, name, request, pattern, pack, options)
|
|
5111
|
-
);
|
|
5112
|
-
}
|
|
5113
|
-
}
|
|
5415
|
+
// src/paths/raisedResponses.ts
|
|
5416
|
+
import { constantOf as constantOf4 } from "@suss/values";
|
|
5417
|
+
function statusNumberOf(node, options) {
|
|
5418
|
+
const value = constantOf4(evaluatedValue(node, options.facts));
|
|
5419
|
+
if (typeof value === "number") {
|
|
5420
|
+
return value;
|
|
5114
5421
|
}
|
|
5115
|
-
|
|
5422
|
+
const origin = originOf(node, options.module);
|
|
5423
|
+
return origin === null ? null : options.constants?.[`${origin.module}.${origin.name}`] ?? null;
|
|
5116
5424
|
}
|
|
5117
|
-
|
|
5425
|
+
var NESTED_DEFINITION_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
|
|
5426
|
+
function raisedResponses(body, options) {
|
|
5427
|
+
if (options.calls.length === 0) {
|
|
5428
|
+
return [];
|
|
5429
|
+
}
|
|
5430
|
+
return raisesIn(body, options);
|
|
5431
|
+
}
|
|
5432
|
+
function raisesIn(body, options) {
|
|
5433
|
+
if (body === null) {
|
|
5434
|
+
return [];
|
|
5435
|
+
}
|
|
5118
5436
|
const found = [];
|
|
5119
|
-
|
|
5120
|
-
for (const
|
|
5121
|
-
|
|
5122
|
-
if (callee === null || originOf(callee, module) !== null) {
|
|
5437
|
+
const walk = (node) => {
|
|
5438
|
+
for (const child of children(node)) {
|
|
5439
|
+
if (child === null || NESTED_DEFINITION_TYPES2.has(child.type)) {
|
|
5123
5440
|
continue;
|
|
5124
5441
|
}
|
|
5125
|
-
const
|
|
5126
|
-
if (
|
|
5127
|
-
found.push(
|
|
5442
|
+
const response = raisedResponseOf(child, options);
|
|
5443
|
+
if (response !== null) {
|
|
5444
|
+
found.push(response);
|
|
5128
5445
|
}
|
|
5446
|
+
walk(child);
|
|
5129
5447
|
}
|
|
5130
|
-
}
|
|
5448
|
+
};
|
|
5449
|
+
walk(body);
|
|
5131
5450
|
return found;
|
|
5132
5451
|
}
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
functionDefinitions(child, found);
|
|
5452
|
+
var ENDING_EXPRESSION = {
|
|
5453
|
+
raise_statement: (statement) => statement.namedChild(0) ?? null,
|
|
5454
|
+
expression_statement: (statement) => {
|
|
5455
|
+
const only = statement.namedChild(0);
|
|
5456
|
+
return only?.type === "call" ? only : null;
|
|
5139
5457
|
}
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
if (attribute === null) {
|
|
5146
|
-
return [];
|
|
5458
|
+
};
|
|
5459
|
+
function raisedResponseOf(statement, options) {
|
|
5460
|
+
const expression = ENDING_EXPRESSION[statement.type]?.(statement) ?? null;
|
|
5461
|
+
if (expression === null) {
|
|
5462
|
+
return null;
|
|
5147
5463
|
}
|
|
5148
|
-
const
|
|
5149
|
-
|
|
5150
|
-
|
|
5464
|
+
const thrownByCall = statement.type !== "raise_statement";
|
|
5465
|
+
const prebuilt = thrownByCall ? null : prebuiltCallOf(expression, options);
|
|
5466
|
+
if (prebuilt !== null) {
|
|
5467
|
+
return {
|
|
5468
|
+
statement,
|
|
5469
|
+
thrownByCall,
|
|
5470
|
+
terminal: terminalOf(
|
|
5471
|
+
statement,
|
|
5472
|
+
calleeOf(prebuilt.call, prebuilt.call),
|
|
5473
|
+
prebuilt.call,
|
|
5474
|
+
prebuilt.declared,
|
|
5475
|
+
prebuilt.options
|
|
5476
|
+
)
|
|
5477
|
+
};
|
|
5151
5478
|
}
|
|
5152
|
-
const
|
|
5153
|
-
|
|
5154
|
-
|
|
5479
|
+
const call = expression.type === "call" ? expression : null;
|
|
5480
|
+
const callee = calleeOf(expression, call);
|
|
5481
|
+
const declared = declaredCallFor(callee, options);
|
|
5482
|
+
if (declared === void 0 && thrownByCall) {
|
|
5483
|
+
return null;
|
|
5484
|
+
}
|
|
5485
|
+
return {
|
|
5486
|
+
statement,
|
|
5487
|
+
thrownByCall,
|
|
5488
|
+
terminal: terminalOf(statement, callee, call, declared, options)
|
|
5489
|
+
};
|
|
5490
|
+
}
|
|
5491
|
+
function prebuiltCallOf(expression, options) {
|
|
5492
|
+
if (expression.type !== "identifier" && expression.type !== "attribute") {
|
|
5493
|
+
return null;
|
|
5494
|
+
}
|
|
5495
|
+
const written = writtenNodeOf(expression, options.facts);
|
|
5496
|
+
if (written === null || written.type !== "call") {
|
|
5497
|
+
return null;
|
|
5498
|
+
}
|
|
5499
|
+
const inItsFile = { ...options, module: moduleOf(written) };
|
|
5500
|
+
const declared = declaredCallFor(calleeOf(written, written), inItsFile);
|
|
5501
|
+
return declared === void 0 ? null : { call: written, declared, options: inItsFile };
|
|
5502
|
+
}
|
|
5503
|
+
function returnedResponseStatus(statement, options) {
|
|
5504
|
+
const returned = statement.namedChild(0);
|
|
5505
|
+
if (options.calls.length === 0 || returned === void 0 || returned === null || returned.type !== "call") {
|
|
5506
|
+
return null;
|
|
5507
|
+
}
|
|
5508
|
+
const callee = field(returned, "function");
|
|
5509
|
+
if (callee === null) {
|
|
5510
|
+
return null;
|
|
5511
|
+
}
|
|
5512
|
+
const declared = declaredCallFor(callee, options);
|
|
5513
|
+
return declared === void 0 ? null : statusOf(declared, returned, options);
|
|
5514
|
+
}
|
|
5515
|
+
function calleeOf(expression, call) {
|
|
5516
|
+
return call === null ? expression : field(call, "function") ?? expression;
|
|
5517
|
+
}
|
|
5518
|
+
function declaredCallFor(callee, options) {
|
|
5519
|
+
const origin = originOf(callee, options.module);
|
|
5520
|
+
if (origin === null) {
|
|
5521
|
+
return void 0;
|
|
5522
|
+
}
|
|
5523
|
+
const qualified = `${origin.module}.${origin.name}`;
|
|
5524
|
+
return options.calls.find((call) => call.callee === qualified);
|
|
5525
|
+
}
|
|
5526
|
+
function terminalOf(statement, callee, call, declared, options) {
|
|
5527
|
+
return {
|
|
5528
|
+
kind: "throw",
|
|
5529
|
+
statusCode: declared === void 0 ? null : statusOf(declared, call, options),
|
|
5530
|
+
body: null,
|
|
5531
|
+
exceptionType: lastSegmentOf(declared?.callee ?? callee.text),
|
|
5532
|
+
message: call === null ? null : writtenMessageOf(call),
|
|
5533
|
+
...declared === void 0 ? {} : { producesResponse: true },
|
|
5534
|
+
component: null,
|
|
5535
|
+
renderTree: null,
|
|
5536
|
+
delegateTarget: null,
|
|
5537
|
+
emitEvent: null,
|
|
5538
|
+
location: rangeOf(statement)
|
|
5539
|
+
};
|
|
5540
|
+
}
|
|
5541
|
+
function lastSegmentOf(dotted) {
|
|
5542
|
+
const segment = dotted.split(".").pop();
|
|
5543
|
+
return segment === void 0 || segment === "" ? null : segment;
|
|
5544
|
+
}
|
|
5545
|
+
function statusOf(declared, call, options) {
|
|
5546
|
+
const written = call === null ? null : statusArgumentOf(declared, call);
|
|
5547
|
+
if (written === null) {
|
|
5548
|
+
return declared.defaultStatusCode === void 0 ? null : { type: "literal", value: declared.defaultStatusCode };
|
|
5549
|
+
}
|
|
5550
|
+
const value = statusNumberOf(written, options);
|
|
5551
|
+
return value === null ? { type: "dynamic", sourceText: written.text } : { type: "literal", value };
|
|
5552
|
+
}
|
|
5553
|
+
function argumentsOf2(call) {
|
|
5554
|
+
return children(field(call, "arguments"));
|
|
5555
|
+
}
|
|
5556
|
+
function statusArgumentOf(declared, call) {
|
|
5557
|
+
const args = argumentsOf2(call);
|
|
5558
|
+
const keyed = args.find(
|
|
5559
|
+
(arg) => arg.type === "keyword_argument" && field(arg, "name")?.text === declared.statusKeyword
|
|
5560
|
+
);
|
|
5561
|
+
if (keyed !== void 0) {
|
|
5562
|
+
return field(keyed, "value");
|
|
5563
|
+
}
|
|
5564
|
+
if (declared.statusArgument === void 0) {
|
|
5565
|
+
return null;
|
|
5566
|
+
}
|
|
5567
|
+
const positional = args.filter((arg) => arg.type !== "keyword_argument");
|
|
5568
|
+
return positional[declared.statusArgument] ?? null;
|
|
5569
|
+
}
|
|
5570
|
+
function writtenMessageOf(call) {
|
|
5571
|
+
for (const arg of argumentsOf2(call)) {
|
|
5572
|
+
const value = arg.type === "keyword_argument" ? field(arg, "value") : arg;
|
|
5573
|
+
const literal = value === null ? null : stringLiteralValue(value);
|
|
5574
|
+
if (literal !== null) {
|
|
5575
|
+
return literal;
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5578
|
+
return null;
|
|
5579
|
+
}
|
|
5580
|
+
|
|
5581
|
+
// src/responseHandOff.ts
|
|
5582
|
+
import { helperPathsOnVariables, splitAtHandOffs } from "@suss/extractor";
|
|
5583
|
+
function throughResponseHelpers(branches, sites, options) {
|
|
5584
|
+
const handOffs = [];
|
|
5585
|
+
for (const { call, effect } of sites) {
|
|
5586
|
+
const helper = helperBranchesAt(call, options);
|
|
5587
|
+
if (helper !== null) {
|
|
5588
|
+
handOffs.push({
|
|
5589
|
+
helper,
|
|
5590
|
+
preconditions: effect.preconditions,
|
|
5591
|
+
line: rangeOf(call).start,
|
|
5592
|
+
at: rangeOf(call)
|
|
5593
|
+
});
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
return handOffs.length === 0 ? [...branches] : branches.flatMap((branch) => splitAtHandOffs(branch, handOffs));
|
|
5597
|
+
}
|
|
5598
|
+
function helperBranchesAt(call, options) {
|
|
5599
|
+
const handed = callArguments(call).filter(
|
|
5600
|
+
(argument) => argument.node.type === "identifier" && refersToResponse(argument.node, options)
|
|
5601
|
+
);
|
|
5602
|
+
if (handed.length === 0) {
|
|
5603
|
+
return null;
|
|
5604
|
+
}
|
|
5605
|
+
const helper = calledDefinition(call, options.facts);
|
|
5606
|
+
if (helper === null || helper.type !== "function_definition") {
|
|
5607
|
+
return null;
|
|
5608
|
+
}
|
|
5609
|
+
const passed = /* @__PURE__ */ new Map();
|
|
5610
|
+
const parameters = parameterShapes(helper, isMethod(helper) ? 1 : 0);
|
|
5611
|
+
for (const argument of handed) {
|
|
5612
|
+
const parameter = parameters.find(
|
|
5613
|
+
(one) => argument.kind === "positional" ? one.position === argument.position : one.name === argument.name
|
|
5614
|
+
);
|
|
5615
|
+
if (parameter !== void 0) {
|
|
5616
|
+
passed.set(parameter.name, argument.node.text);
|
|
5617
|
+
}
|
|
5618
|
+
}
|
|
5619
|
+
return passed.size === 0 ? null : helperPathsOnVariables(options.readHelper(helper), passed);
|
|
5620
|
+
}
|
|
5621
|
+
function refersToResponse(name, options) {
|
|
5622
|
+
const written = awaited(writtenNodeOf(name, options.facts));
|
|
5623
|
+
if (written === null) {
|
|
5624
|
+
return false;
|
|
5625
|
+
}
|
|
5626
|
+
if (sameNode(written, options.request)) {
|
|
5627
|
+
return true;
|
|
5628
|
+
}
|
|
5629
|
+
const callee = written.type === "call" ? field(written, "function") : null;
|
|
5630
|
+
const method = callee === null ? null : field(callee, "attribute");
|
|
5631
|
+
const receiver = callee === null ? null : field(callee, "object");
|
|
5632
|
+
if (method === null || receiver?.type !== "identifier" || !options.bodyMethods.includes(method.text)) {
|
|
5633
|
+
return false;
|
|
5634
|
+
}
|
|
5635
|
+
const parsedFrom = awaited(writtenNodeOf(receiver, options.facts));
|
|
5636
|
+
return parsedFrom !== null && sameNode(parsedFrom, options.request);
|
|
5637
|
+
}
|
|
5638
|
+
function awaited(node) {
|
|
5639
|
+
return node?.type === "await" ? node.namedChild(0) ?? null : node;
|
|
5640
|
+
}
|
|
5641
|
+
function sameNode(a, b) {
|
|
5642
|
+
return a.startIndex === b.startIndex && a.endIndex === b.endIndex && a.tree === b.tree;
|
|
5643
|
+
}
|
|
5644
|
+
|
|
5645
|
+
// src/clientCalls.ts
|
|
5646
|
+
function clientCallUnits(root, module, pack, pattern, options) {
|
|
5647
|
+
const units = [];
|
|
5648
|
+
for (const definition of functionDefinitions(root)) {
|
|
5649
|
+
const name = field(definition, "name")?.text;
|
|
5650
|
+
if (name === void 0) {
|
|
5651
|
+
continue;
|
|
5652
|
+
}
|
|
5653
|
+
for (const call of bodyCalls(definition)) {
|
|
5654
|
+
for (const request of requestCalls(call, pattern, module, options)) {
|
|
5655
|
+
units.push(
|
|
5656
|
+
clientUnit(definition, name, request, pattern, pack, options)
|
|
5657
|
+
);
|
|
5658
|
+
}
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
return units;
|
|
5662
|
+
}
|
|
5663
|
+
function clientCallReceivers(root, module) {
|
|
5664
|
+
const found = [];
|
|
5665
|
+
for (const definition of functionDefinitions(root)) {
|
|
5666
|
+
for (const call of bodyCalls(definition)) {
|
|
5667
|
+
const callee = field(call, "function");
|
|
5668
|
+
if (callee === null || originOf(callee, module) !== null) {
|
|
5669
|
+
continue;
|
|
5670
|
+
}
|
|
5671
|
+
const object = field(callee, "object");
|
|
5672
|
+
if (object !== null && field(callee, "attribute") !== null) {
|
|
5673
|
+
found.push(object);
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
}
|
|
5677
|
+
return found;
|
|
5678
|
+
}
|
|
5679
|
+
function functionDefinitions(node, found = []) {
|
|
5680
|
+
for (const child of children(node)) {
|
|
5681
|
+
if (isFunction(child)) {
|
|
5682
|
+
found.push(child);
|
|
5683
|
+
}
|
|
5684
|
+
functionDefinitions(child, found);
|
|
5685
|
+
}
|
|
5686
|
+
return found;
|
|
5687
|
+
}
|
|
5688
|
+
function requestCalls(call, pattern, module, options) {
|
|
5689
|
+
const callee = field(call, "function");
|
|
5690
|
+
const attribute = callee === null ? null : calledAttribute(callee, pattern, module, options.facts);
|
|
5691
|
+
if (attribute === null) {
|
|
5692
|
+
return [];
|
|
5693
|
+
}
|
|
5694
|
+
const plain = requestCall(call, attribute, pattern, options);
|
|
5695
|
+
if (plain !== null && !hasNameHole(plain.path)) {
|
|
5696
|
+
return [plain];
|
|
5697
|
+
}
|
|
5698
|
+
const byBoundary = /* @__PURE__ */ new Map();
|
|
5699
|
+
for (const site of constructionSitesOf(call, options.facts)) {
|
|
5700
|
+
const stated = requestCall(call, attribute, pattern, options, site);
|
|
5155
5701
|
if (stated === null) {
|
|
5156
5702
|
continue;
|
|
5157
5703
|
}
|
|
5158
|
-
const key = `${stated.method} ${stated.path}`;
|
|
5704
|
+
const key = `${stated.method} ${stated.host ?? ""} ${stated.path}`;
|
|
5159
5705
|
if (!byBoundary.has(key)) {
|
|
5160
5706
|
byBoundary.set(key, stated);
|
|
5161
5707
|
}
|
|
@@ -5166,16 +5712,33 @@ function requestCalls(call, pattern, module, options) {
|
|
|
5166
5712
|
return plain === null ? [] : [plain];
|
|
5167
5713
|
}
|
|
5168
5714
|
function requestCall(call, attribute, pattern, options, site) {
|
|
5715
|
+
const stated = methodAndPath(call, attribute, pattern, options, site);
|
|
5716
|
+
if (stated === null) {
|
|
5717
|
+
return null;
|
|
5718
|
+
}
|
|
5719
|
+
const redirectDelivery = redirectDeliveryAt(call, pattern, options, site);
|
|
5720
|
+
return redirectDelivery === void 0 ? stated : { ...stated, redirectDelivery };
|
|
5721
|
+
}
|
|
5722
|
+
function redirectDeliveryAt(call, pattern, options, site) {
|
|
5723
|
+
const option = pattern.response?.redirectOption;
|
|
5724
|
+
const argument = option === void 0 ? null : argumentAt(call, null, option.name);
|
|
5725
|
+
if (option === void 0 || argument === null) {
|
|
5726
|
+
return void 0;
|
|
5727
|
+
}
|
|
5728
|
+
const value = scalarOf(evaluatedValue(argument, options.facts, site));
|
|
5729
|
+
return value === null ? void 0 : redirectDeliveryWhenSet(option, value);
|
|
5730
|
+
}
|
|
5731
|
+
function methodAndPath(call, attribute, pattern, options, site) {
|
|
5169
5732
|
const verb = pattern.verbAttributeNames[attribute];
|
|
5170
5733
|
if (verb !== void 0) {
|
|
5171
|
-
const
|
|
5734
|
+
const target2 = urlAt(
|
|
5172
5735
|
call,
|
|
5173
5736
|
pattern.url.position,
|
|
5174
5737
|
pattern.url.keyword,
|
|
5175
5738
|
options,
|
|
5176
5739
|
site
|
|
5177
5740
|
);
|
|
5178
|
-
return
|
|
5741
|
+
return target2 === null ? null : { method: verb, ...target2, range: rangeOf(call), node: call };
|
|
5179
5742
|
}
|
|
5180
5743
|
const methodCall = pattern.methodCall;
|
|
5181
5744
|
if (methodCall === void 0 || methodCall.attribute !== attribute) {
|
|
@@ -5190,14 +5753,19 @@ function requestCall(call, attribute, pattern, options, site) {
|
|
|
5190
5753
|
if (method === null) {
|
|
5191
5754
|
return null;
|
|
5192
5755
|
}
|
|
5193
|
-
const
|
|
5756
|
+
const target = urlAt(
|
|
5194
5757
|
call,
|
|
5195
5758
|
methodCall.urlPosition,
|
|
5196
5759
|
pattern.url.keyword,
|
|
5197
5760
|
options,
|
|
5198
5761
|
site
|
|
5199
5762
|
);
|
|
5200
|
-
return
|
|
5763
|
+
return target === null ? null : {
|
|
5764
|
+
method: method.toUpperCase(),
|
|
5765
|
+
...target,
|
|
5766
|
+
range: rangeOf(call),
|
|
5767
|
+
node: call
|
|
5768
|
+
};
|
|
5201
5769
|
}
|
|
5202
5770
|
function calledAttribute(callee, pattern, module, facts) {
|
|
5203
5771
|
const origin = originOf(callee, module);
|
|
@@ -5230,7 +5798,9 @@ function urlAt(call, position, keyword, options, site) {
|
|
|
5230
5798
|
if (argument === null) {
|
|
5231
5799
|
return null;
|
|
5232
5800
|
}
|
|
5233
|
-
|
|
5801
|
+
const value = evaluatedValue(argument, options.facts, site);
|
|
5802
|
+
const path8 = pathOf(value);
|
|
5803
|
+
return path8 === void 0 ? null : { path: path8, host: hostOf(value) };
|
|
5234
5804
|
}
|
|
5235
5805
|
function argumentAt(call, position, keyword) {
|
|
5236
5806
|
const args = field(call, "arguments");
|
|
@@ -5248,25 +5818,33 @@ function argumentAt(call, position, keyword) {
|
|
|
5248
5818
|
}
|
|
5249
5819
|
positional.push(child);
|
|
5250
5820
|
}
|
|
5251
|
-
return positional[position] ?? null;
|
|
5821
|
+
return position === null ? null : positional[position] ?? null;
|
|
5252
5822
|
}
|
|
5253
|
-
function callerBranches(definition,
|
|
5823
|
+
function callerBranches(definition, reading) {
|
|
5824
|
+
const range = rangeOf(definition);
|
|
5254
5825
|
const body = field(definition, "body");
|
|
5255
|
-
const
|
|
5256
|
-
const
|
|
5257
|
-
if (body === null
|
|
5826
|
+
const sites = invocationSites(definition, reading.facts);
|
|
5827
|
+
const effects = sites.map((site) => site.effect);
|
|
5828
|
+
if (body === null) {
|
|
5258
5829
|
return [handsBack(range, effects)];
|
|
5259
5830
|
}
|
|
5831
|
+
const raised = raisesIn(body, {
|
|
5832
|
+
calls: [],
|
|
5833
|
+
module: moduleOf(definition),
|
|
5834
|
+
facts: reading.facts
|
|
5835
|
+
});
|
|
5260
5836
|
const branches = enumerateBodyBranches({
|
|
5261
5837
|
body,
|
|
5262
|
-
terminals,
|
|
5263
|
-
raised
|
|
5838
|
+
terminals: bodyTerminals(body, raised),
|
|
5839
|
+
raised,
|
|
5264
5840
|
effects,
|
|
5265
|
-
branchOf: (
|
|
5841
|
+
branchOf: (found2) => found2.type === "raise" ? { terminal: found2.terminal, location: rangeOf(found2.statement) } : handsBackAt(rangeOf(found2.statement)),
|
|
5266
5842
|
fallthrough: handsBackAt(range),
|
|
5267
|
-
facts
|
|
5843
|
+
facts: reading.facts,
|
|
5844
|
+
keepsArms: (condition) => testsStatus(predicateOf(condition, reading.facts), reading.statusMembers)
|
|
5268
5845
|
});
|
|
5269
|
-
|
|
5846
|
+
const found = branches.length === 0 ? [handsBack(range, effects)] : branches;
|
|
5847
|
+
return reading.handOff === void 0 ? found : throughResponseHelpers(found, sites, reading.handOff);
|
|
5270
5848
|
}
|
|
5271
5849
|
function handsBackAt(range) {
|
|
5272
5850
|
return {
|
|
@@ -5302,11 +5880,24 @@ function responseAccessors(pattern) {
|
|
|
5302
5880
|
...response.body === void 0 ? {} : { bodyAccessors: response.body },
|
|
5303
5881
|
...response.statusCode === void 0 ? {} : { statusAccessors: response.statusCode },
|
|
5304
5882
|
...response.success === void 0 ? {} : { successAccessors: response.success },
|
|
5305
|
-
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery }
|
|
5883
|
+
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery },
|
|
5884
|
+
...response.redirectDelivery === void 0 ? {} : { redirectDelivery: response.redirectDelivery }
|
|
5306
5885
|
};
|
|
5307
5886
|
}
|
|
5308
5887
|
function clientUnit(definition, name, request, pattern, pack, options) {
|
|
5309
5888
|
const range = rangeOf(definition);
|
|
5889
|
+
const accessors = responseAccessors(pattern);
|
|
5890
|
+
const statusMembers = statusMembersOf(accessors);
|
|
5891
|
+
const reading = {
|
|
5892
|
+
facts: options.facts,
|
|
5893
|
+
statusMembers,
|
|
5894
|
+
handOff: {
|
|
5895
|
+
request: request.node,
|
|
5896
|
+
bodyMethods: accessors.bodyAccessors ?? [],
|
|
5897
|
+
facts: options.facts,
|
|
5898
|
+
readHelper: (helper) => callerBranches(helper, { facts: options.facts, statusMembers })
|
|
5899
|
+
}
|
|
5900
|
+
};
|
|
5310
5901
|
return {
|
|
5311
5902
|
identity: {
|
|
5312
5903
|
name,
|
|
@@ -5322,11 +5913,13 @@ function clientUnit(definition, name, request, pattern, pack, options) {
|
|
|
5322
5913
|
transport: pack.protocol,
|
|
5323
5914
|
method: request.method,
|
|
5324
5915
|
path: request.path,
|
|
5916
|
+
host: request.host,
|
|
5325
5917
|
recognition: pack.name
|
|
5326
5918
|
}),
|
|
5327
5919
|
parameters: [],
|
|
5328
|
-
branches: callerBranches(definition,
|
|
5329
|
-
...
|
|
5920
|
+
branches: callerBranches(definition, reading),
|
|
5921
|
+
...accessors,
|
|
5922
|
+
...request.redirectDelivery === void 0 ? {} : { redirectDelivery: request.redirectDelivery },
|
|
5330
5923
|
bodyContent: "statements",
|
|
5331
5924
|
dependencyCalls: [],
|
|
5332
5925
|
declaredContract: null
|
|
@@ -5549,7 +6142,7 @@ function isTestedAt(parent, child, subject, seen) {
|
|
|
5549
6142
|
}
|
|
5550
6143
|
function conditionOf(node) {
|
|
5551
6144
|
if (node.type === "conditional_expression") {
|
|
5552
|
-
return node.
|
|
6145
|
+
return node.namedChild(1) ?? null;
|
|
5553
6146
|
}
|
|
5554
6147
|
return CONDITIONED_TYPES.has(node.type) ? field(node, "condition") : null;
|
|
5555
6148
|
}
|
|
@@ -5572,7 +6165,7 @@ function isPresentAt(node, subject) {
|
|
|
5572
6165
|
}
|
|
5573
6166
|
function isBranchWherePresent(parent, child, subject) {
|
|
5574
6167
|
if (parent.type === "conditional_expression") {
|
|
5575
|
-
const [whenTrue, test2, whenFalse] = parent
|
|
6168
|
+
const [whenTrue, test2, whenFalse] = children(parent);
|
|
5576
6169
|
return test2 !== void 0 && test2 !== null && (whenTrue?.id === child.id && isPresentWhen(test2, true, subject) || whenFalse?.id === child.id && isPresentWhen(test2, false, subject));
|
|
5577
6170
|
}
|
|
5578
6171
|
if (parent.type === "boolean_operator") {
|
|
@@ -5610,7 +6203,7 @@ function followsExitWhenAbsent(parent, child, subject) {
|
|
|
5610
6203
|
if (parent.type !== "block" && parent.type !== "module") {
|
|
5611
6204
|
return false;
|
|
5612
6205
|
}
|
|
5613
|
-
const statements = parent
|
|
6206
|
+
const statements = children(parent);
|
|
5614
6207
|
const at = statements.findIndex((statement) => statement?.id === child.id);
|
|
5615
6208
|
return statements.slice(0, at).some(
|
|
5616
6209
|
(statement) => statement !== null && leavesWhenAbsent(statement, subject)
|
|
@@ -5654,7 +6247,7 @@ function continuationRaises(from) {
|
|
|
5654
6247
|
let parent = current.parent;
|
|
5655
6248
|
while (parent !== null) {
|
|
5656
6249
|
if (parent.type === "block" || parent.type === "module") {
|
|
5657
|
-
const statements = parent
|
|
6250
|
+
const statements = children(parent);
|
|
5658
6251
|
const at = statements.findIndex((one) => one?.id === current.id);
|
|
5659
6252
|
const exit = firstExit(statements.slice(at + 1));
|
|
5660
6253
|
if (exit !== null) {
|
|
@@ -5698,7 +6291,7 @@ function exitOf(statement) {
|
|
|
5698
6291
|
if (LEAVING_TYPES.has(statement.type)) {
|
|
5699
6292
|
return "leave";
|
|
5700
6293
|
}
|
|
5701
|
-
return statement.type === "block" ? firstExit(statement
|
|
6294
|
+
return statement.type === "block" ? firstExit(children(statement)) : null;
|
|
5702
6295
|
}
|
|
5703
6296
|
function isPresentWhen(test, outcome, subject) {
|
|
5704
6297
|
const expression = peelParens(test);
|
|
@@ -5738,7 +6331,7 @@ function isPresentAfterComparison(comparison, outcome, subject) {
|
|
|
5738
6331
|
}
|
|
5739
6332
|
function comparisonParts(comparison) {
|
|
5740
6333
|
const operators = fields(comparison, "operators");
|
|
5741
|
-
const operands = comparison.
|
|
6334
|
+
const operands = children(comparison).filter(
|
|
5742
6335
|
(child) => child !== null && !operators.some((one) => one.id === child.id)
|
|
5743
6336
|
);
|
|
5744
6337
|
const [left, right] = operands;
|
|
@@ -5761,7 +6354,7 @@ function comparedWithNone(comparison) {
|
|
|
5761
6354
|
}
|
|
5762
6355
|
var NONE_OPERATORS = /* @__PURE__ */ new Set(["is", "is not", "==", "!="]);
|
|
5763
6356
|
function peelParens(node) {
|
|
5764
|
-
const inner = node.type === "parenthesized_expression" ? node.
|
|
6357
|
+
const inner = node.type === "parenthesized_expression" ? node.namedChild(0) : null;
|
|
5765
6358
|
return inner === null || inner === void 0 ? node : peelParens(inner);
|
|
5766
6359
|
}
|
|
5767
6360
|
function climbParens(node) {
|
|
@@ -5819,7 +6412,7 @@ function envReadEffects(root, module, facts) {
|
|
|
5819
6412
|
const slots = [];
|
|
5820
6413
|
const readsHelpers = facts !== void 0 && sitesByDb.has(facts);
|
|
5821
6414
|
const startScope = module.scopeFor.get(root.id) ?? module.moduleScope;
|
|
5822
|
-
walkDescendants(root, startScope, {
|
|
6415
|
+
walkDescendants(root, startScope, children, {
|
|
5823
6416
|
at: (node, scope) => {
|
|
5824
6417
|
const syntax = envReadSyntaxAt(node, scope);
|
|
5825
6418
|
if (syntax !== null) {
|
|
@@ -5878,7 +6471,7 @@ function hasFallback(node, spelling, scope) {
|
|
|
5878
6471
|
}
|
|
5879
6472
|
function envFactsIn(filePath, root, module) {
|
|
5880
6473
|
const found = { sites: [], objects: [] };
|
|
5881
|
-
walkDescendants(root, module.moduleScope, {
|
|
6474
|
+
walkDescendants(root, module.moduleScope, children, {
|
|
5882
6475
|
at: (node, scope) => {
|
|
5883
6476
|
if (isEnviron(node, scope) && handsOnward(node)) {
|
|
5884
6477
|
found.objects.push(keyOf(filePath, node));
|
|
@@ -6096,137 +6689,6 @@ function readsThroughHelper(db, call, argumentAt2, siteById, named) {
|
|
|
6096
6689
|
);
|
|
6097
6690
|
}
|
|
6098
6691
|
|
|
6099
|
-
// src/paths/raisedResponses.ts
|
|
6100
|
-
import { constantOf as constantOf4 } from "@suss/values";
|
|
6101
|
-
var NESTED_DEFINITION_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
|
|
6102
|
-
function raisedResponses(body, options) {
|
|
6103
|
-
if (body === null || options.calls.length === 0) {
|
|
6104
|
-
return [];
|
|
6105
|
-
}
|
|
6106
|
-
const found = [];
|
|
6107
|
-
const walk = (node) => {
|
|
6108
|
-
for (const child of node.namedChildren) {
|
|
6109
|
-
if (child === null || NESTED_DEFINITION_TYPES2.has(child.type)) {
|
|
6110
|
-
continue;
|
|
6111
|
-
}
|
|
6112
|
-
const response = raisedResponseOf(child, options);
|
|
6113
|
-
if (response !== null) {
|
|
6114
|
-
found.push(response);
|
|
6115
|
-
}
|
|
6116
|
-
walk(child);
|
|
6117
|
-
}
|
|
6118
|
-
};
|
|
6119
|
-
walk(body);
|
|
6120
|
-
return found;
|
|
6121
|
-
}
|
|
6122
|
-
var ENDING_EXPRESSION = {
|
|
6123
|
-
raise_statement: (statement) => statement.namedChildren[0] ?? null,
|
|
6124
|
-
expression_statement: (statement) => {
|
|
6125
|
-
const only = statement.namedChildren[0];
|
|
6126
|
-
return only?.type === "call" ? only : null;
|
|
6127
|
-
}
|
|
6128
|
-
};
|
|
6129
|
-
function raisedResponseOf(statement, options) {
|
|
6130
|
-
const expression = ENDING_EXPRESSION[statement.type]?.(statement) ?? null;
|
|
6131
|
-
if (expression === null) {
|
|
6132
|
-
return null;
|
|
6133
|
-
}
|
|
6134
|
-
const thrownByCall = statement.type !== "raise_statement";
|
|
6135
|
-
const call = expression.type === "call" ? expression : null;
|
|
6136
|
-
const callee = calleeOf(expression, call);
|
|
6137
|
-
const declared = declaredCallFor(callee, options);
|
|
6138
|
-
if (declared === void 0 && thrownByCall) {
|
|
6139
|
-
return null;
|
|
6140
|
-
}
|
|
6141
|
-
return {
|
|
6142
|
-
statement,
|
|
6143
|
-
thrownByCall,
|
|
6144
|
-
terminal: terminalOf(statement, callee, call, declared, options.facts)
|
|
6145
|
-
};
|
|
6146
|
-
}
|
|
6147
|
-
function returnedResponseStatus(statement, options) {
|
|
6148
|
-
const returned = statement.namedChildren[0];
|
|
6149
|
-
if (options.calls.length === 0 || returned === void 0 || returned === null || returned.type !== "call") {
|
|
6150
|
-
return null;
|
|
6151
|
-
}
|
|
6152
|
-
const callee = field(returned, "function");
|
|
6153
|
-
if (callee === null) {
|
|
6154
|
-
return null;
|
|
6155
|
-
}
|
|
6156
|
-
const declared = declaredCallFor(callee, options);
|
|
6157
|
-
return declared === void 0 ? null : statusOf(declared, returned, options.facts);
|
|
6158
|
-
}
|
|
6159
|
-
function calleeOf(expression, call) {
|
|
6160
|
-
return call === null ? expression : field(call, "function") ?? expression;
|
|
6161
|
-
}
|
|
6162
|
-
function declaredCallFor(callee, options) {
|
|
6163
|
-
const origin = originOf(callee, options.module);
|
|
6164
|
-
if (origin === null) {
|
|
6165
|
-
return void 0;
|
|
6166
|
-
}
|
|
6167
|
-
const qualified = `${origin.module}.${origin.name}`;
|
|
6168
|
-
return options.calls.find((call) => call.callee === qualified);
|
|
6169
|
-
}
|
|
6170
|
-
function terminalOf(statement, callee, call, declared, facts) {
|
|
6171
|
-
return {
|
|
6172
|
-
kind: "throw",
|
|
6173
|
-
statusCode: declared === void 0 ? null : statusOf(declared, call, facts),
|
|
6174
|
-
body: null,
|
|
6175
|
-
exceptionType: lastSegmentOf(declared?.callee ?? callee.text),
|
|
6176
|
-
message: call === null ? null : writtenMessageOf(call),
|
|
6177
|
-
...declared === void 0 ? {} : { producesResponse: true },
|
|
6178
|
-
component: null,
|
|
6179
|
-
renderTree: null,
|
|
6180
|
-
delegateTarget: null,
|
|
6181
|
-
emitEvent: null,
|
|
6182
|
-
location: rangeOf(statement)
|
|
6183
|
-
};
|
|
6184
|
-
}
|
|
6185
|
-
function lastSegmentOf(dotted) {
|
|
6186
|
-
const segment = dotted.split(".").pop();
|
|
6187
|
-
return segment === void 0 || segment === "" ? null : segment;
|
|
6188
|
-
}
|
|
6189
|
-
function statusOf(declared, call, facts) {
|
|
6190
|
-
const written = call === null ? null : statusArgumentOf(declared, call);
|
|
6191
|
-
if (written === null) {
|
|
6192
|
-
return declared.defaultStatusCode === void 0 ? null : { type: "literal", value: declared.defaultStatusCode };
|
|
6193
|
-
}
|
|
6194
|
-
const value = constantOf4(evaluatedValue(written, facts));
|
|
6195
|
-
if (typeof value === "number") {
|
|
6196
|
-
return { type: "literal", value };
|
|
6197
|
-
}
|
|
6198
|
-
return { type: "dynamic", sourceText: written.text };
|
|
6199
|
-
}
|
|
6200
|
-
function argumentsOf2(call) {
|
|
6201
|
-
return (field(call, "arguments")?.namedChildren ?? []).filter(
|
|
6202
|
-
(child) => child !== null
|
|
6203
|
-
);
|
|
6204
|
-
}
|
|
6205
|
-
function statusArgumentOf(declared, call) {
|
|
6206
|
-
const args = argumentsOf2(call);
|
|
6207
|
-
const keyed = args.find(
|
|
6208
|
-
(arg) => arg.type === "keyword_argument" && field(arg, "name")?.text === declared.statusKeyword
|
|
6209
|
-
);
|
|
6210
|
-
if (keyed !== void 0) {
|
|
6211
|
-
return field(keyed, "value");
|
|
6212
|
-
}
|
|
6213
|
-
if (declared.statusArgument === void 0) {
|
|
6214
|
-
return null;
|
|
6215
|
-
}
|
|
6216
|
-
const positional = args.filter((arg) => arg.type !== "keyword_argument");
|
|
6217
|
-
return positional[declared.statusArgument] ?? null;
|
|
6218
|
-
}
|
|
6219
|
-
function writtenMessageOf(call) {
|
|
6220
|
-
for (const arg of argumentsOf2(call)) {
|
|
6221
|
-
const value = arg.type === "keyword_argument" ? field(arg, "value") : arg;
|
|
6222
|
-
const literal = value === null ? null : stringLiteralValue(value);
|
|
6223
|
-
if (literal !== null) {
|
|
6224
|
-
return literal;
|
|
6225
|
-
}
|
|
6226
|
-
}
|
|
6227
|
-
return null;
|
|
6228
|
-
}
|
|
6229
|
-
|
|
6230
6692
|
// src/paths/returnedShape.ts
|
|
6231
6693
|
var MAX_DEPTH = 6;
|
|
6232
6694
|
var SCALARS = {
|
|
@@ -6286,7 +6748,7 @@ function shapeOfReturned(node, depth = 0) {
|
|
|
6286
6748
|
return { type: "unknown" };
|
|
6287
6749
|
}
|
|
6288
6750
|
function returnedBodyShape(statement) {
|
|
6289
|
-
const returned = statement.
|
|
6751
|
+
const returned = statement.namedChild(0);
|
|
6290
6752
|
if (returned == null) {
|
|
6291
6753
|
return null;
|
|
6292
6754
|
}
|
|
@@ -6310,7 +6772,7 @@ function isStdlibModule(node, scope, module) {
|
|
|
6310
6772
|
const binding = resolveName(scope, node.text);
|
|
6311
6773
|
return binding?.kind === "import" && binding.module === module && binding.relativeLevel === 0;
|
|
6312
6774
|
}
|
|
6313
|
-
function
|
|
6775
|
+
function isBuiltin2(node, scope, name) {
|
|
6314
6776
|
return node.type === "identifier" && node.text === name && resolveName(scope, name) === null;
|
|
6315
6777
|
}
|
|
6316
6778
|
function isStdlibMember(node, scope, module, name) {
|
|
@@ -6332,7 +6794,7 @@ var DEFERRED_BODY_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lamb
|
|
|
6332
6794
|
function streamWriteEffects(root, module) {
|
|
6333
6795
|
const found = [];
|
|
6334
6796
|
const startScope = module.scopeFor.get(root.id) ?? module.moduleScope;
|
|
6335
|
-
walkDescendants2(root, startScope, {
|
|
6797
|
+
walkDescendants2(root, startScope, children, {
|
|
6336
6798
|
at: (node, scope) => {
|
|
6337
6799
|
if (node.type !== "call") {
|
|
6338
6800
|
return;
|
|
@@ -6358,7 +6820,7 @@ function streamWriteAt(call, scope) {
|
|
|
6358
6820
|
}
|
|
6359
6821
|
const written = callArguments(call);
|
|
6360
6822
|
const positional = written.filter((argument) => argument.kind === "positional").map((argument) => argument.node);
|
|
6361
|
-
if (callee.type === "identifier" &&
|
|
6823
|
+
if (callee.type === "identifier" && isBuiltin2(callee, scope, "print")) {
|
|
6362
6824
|
const file = written.find(
|
|
6363
6825
|
(argument) => argument.kind === "keyword" && argument.name === "file"
|
|
6364
6826
|
);
|
|
@@ -6419,7 +6881,7 @@ function jsonDumped(node, scope) {
|
|
|
6419
6881
|
// src/discovery.ts
|
|
6420
6882
|
function decoratedNodes(root) {
|
|
6421
6883
|
const found = [];
|
|
6422
|
-
walkDescendants3(root, null, {
|
|
6884
|
+
walkDescendants3(root, null, children, {
|
|
6423
6885
|
at: (node) => {
|
|
6424
6886
|
if (node.type !== "decorated_definition") {
|
|
6425
6887
|
return;
|
|
@@ -6802,7 +7264,7 @@ function readRouterPrefix(pattern, classification, module, options, range) {
|
|
|
6802
7264
|
}
|
|
6803
7265
|
return absentReading;
|
|
6804
7266
|
}
|
|
6805
|
-
function readStatusCode(pattern, classification) {
|
|
7267
|
+
function readStatusCode(pattern, classification, options) {
|
|
6806
7268
|
if (pattern.statusCodeKeyword === void 0) {
|
|
6807
7269
|
return absentReading;
|
|
6808
7270
|
}
|
|
@@ -6810,11 +7272,15 @@ function readStatusCode(pattern, classification) {
|
|
|
6810
7272
|
if (arg === void 0) {
|
|
6811
7273
|
return absentReading;
|
|
6812
7274
|
}
|
|
6813
|
-
|
|
6814
|
-
|
|
7275
|
+
const status = statusNumberOf(arg.node, {
|
|
7276
|
+
...options,
|
|
7277
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
7278
|
+
});
|
|
7279
|
+
if (status !== null) {
|
|
7280
|
+
return writtenReading(status, classification.range);
|
|
6815
7281
|
}
|
|
6816
7282
|
return unreadableReading(
|
|
6817
|
-
"The status this route's decorator states
|
|
7283
|
+
"The status this route's decorator states does not come to a number here, so the response claims no status",
|
|
6818
7284
|
classification.range
|
|
6819
7285
|
);
|
|
6820
7286
|
}
|
|
@@ -6835,11 +7301,14 @@ function statusFromReturnedValue(node, facts) {
|
|
|
6835
7301
|
return digits === null ? null : Number.parseInt(digits[1], 10);
|
|
6836
7302
|
}
|
|
6837
7303
|
function statusOfReturn(statement, facts) {
|
|
6838
|
-
const returned = statement.
|
|
7304
|
+
const returned = statement.namedChild(0);
|
|
6839
7305
|
if (returned?.type !== "expression_list") {
|
|
6840
7306
|
return { kind: "none" };
|
|
6841
7307
|
}
|
|
6842
|
-
const status = statusFromReturnedValue(
|
|
7308
|
+
const status = statusFromReturnedValue(
|
|
7309
|
+
returned.namedChild(1) ?? void 0,
|
|
7310
|
+
facts
|
|
7311
|
+
);
|
|
6843
7312
|
return status === null ? { kind: "unreadable" } : { kind: "status", value: status };
|
|
6844
7313
|
}
|
|
6845
7314
|
function returnStatusReading(statement, ctx) {
|
|
@@ -6859,6 +7328,22 @@ function returnStatusReading(statement, ctx) {
|
|
|
6859
7328
|
function returnBranch(statement, ctx) {
|
|
6860
7329
|
const range = rangeOf(statement);
|
|
6861
7330
|
const writtenBody = returnedBodyShape(statement);
|
|
7331
|
+
return responseBranchAt(
|
|
7332
|
+
range,
|
|
7333
|
+
returnStatusReading(statement, ctx),
|
|
7334
|
+
writtenBody === null ? ctx.responseShape.reading : writtenReading(writtenBody, range),
|
|
7335
|
+
ctx
|
|
7336
|
+
);
|
|
7337
|
+
}
|
|
7338
|
+
function fallthroughBranch(definitionNode, ctx) {
|
|
7339
|
+
return responseBranchAt(
|
|
7340
|
+
rangeOf(definitionNode),
|
|
7341
|
+
ctx.pattern.statusFromReturnedTuple === true ? absentReading : ctx.declaredStatus.reading,
|
|
7342
|
+
ctx.responseShape.reading,
|
|
7343
|
+
ctx
|
|
7344
|
+
);
|
|
7345
|
+
}
|
|
7346
|
+
function responseBranchAt(range, status, body, ctx) {
|
|
6862
7347
|
return {
|
|
6863
7348
|
terminal: {
|
|
6864
7349
|
kind: "response",
|
|
@@ -6875,12 +7360,10 @@ function returnBranch(statement, ctx) {
|
|
|
6875
7360
|
location: range
|
|
6876
7361
|
},
|
|
6877
7362
|
statusCodeReading: {
|
|
6878
|
-
reading:
|
|
7363
|
+
reading: status,
|
|
6879
7364
|
...ctx.declaredStatus.libraryDefault !== void 0 ? { libraryDefault: ctx.declaredStatus.libraryDefault } : {}
|
|
6880
7365
|
},
|
|
6881
|
-
bodyShapeReading: {
|
|
6882
|
-
reading: writtenBody === null ? ctx.responseShape.reading : writtenReading(writtenBody, range)
|
|
6883
|
-
},
|
|
7366
|
+
bodyShapeReading: { reading: body },
|
|
6884
7367
|
location: range
|
|
6885
7368
|
};
|
|
6886
7369
|
}
|
|
@@ -6901,11 +7384,12 @@ function branchesPerTerminal(options) {
|
|
|
6901
7384
|
const raised = raisedResponses(body, {
|
|
6902
7385
|
calls: options.responseStatusCalls,
|
|
6903
7386
|
module: options.ctx.module,
|
|
6904
|
-
facts: options.ctx.facts
|
|
7387
|
+
facts: options.ctx.facts,
|
|
7388
|
+
constants: options.ctx.pattern.statusCodeConstants ?? {}
|
|
6905
7389
|
});
|
|
6906
7390
|
const terminals = bodyTerminals(body, raised);
|
|
6907
7391
|
const soleReturnWritesBody = terminals.length === 1 && terminals[0]?.type === "return" && returnedBodyShape(terminals[0].statement) !== null;
|
|
6908
|
-
if (terminals.length
|
|
7392
|
+
if (terminals.length === 0) {
|
|
6909
7393
|
return null;
|
|
6910
7394
|
}
|
|
6911
7395
|
const branches = enumerateBodyBranches({
|
|
@@ -6914,6 +7398,7 @@ function branchesPerTerminal(options) {
|
|
|
6914
7398
|
raised,
|
|
6915
7399
|
effects: options.effects,
|
|
6916
7400
|
branchOf: (found) => terminalBranchOf(found, options.ctx),
|
|
7401
|
+
fallthrough: fallthroughBranch(options.definitionNode, options.ctx),
|
|
6917
7402
|
facts: options.ctx.facts
|
|
6918
7403
|
});
|
|
6919
7404
|
return branches.length > 1 || soleReturnWritesBody ? branches : null;
|
|
@@ -6922,7 +7407,8 @@ function statusOfReturnIn(statement, pattern, options) {
|
|
|
6922
7407
|
const constructed = returnedResponseStatus(statement, {
|
|
6923
7408
|
calls: pattern.responseConstructors ?? [],
|
|
6924
7409
|
module: options.module,
|
|
6925
|
-
facts: options.facts
|
|
7410
|
+
facts: options.facts,
|
|
7411
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
6926
7412
|
});
|
|
6927
7413
|
if (constructed !== null) {
|
|
6928
7414
|
return constructed.type === "literal" ? { kind: "status", value: constructed.value } : { kind: "unreadable" };
|
|
@@ -7016,6 +7502,25 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7016
7502
|
module.scopeFor,
|
|
7017
7503
|
options.importedDefinition ?? null
|
|
7018
7504
|
);
|
|
7505
|
+
const wrappers = wrappersAround(
|
|
7506
|
+
pattern,
|
|
7507
|
+
pack,
|
|
7508
|
+
classification,
|
|
7509
|
+
functionNode,
|
|
7510
|
+
module,
|
|
7511
|
+
options
|
|
7512
|
+
);
|
|
7513
|
+
const dependencyParameters = options.wrappers?.dependencyParameters(
|
|
7514
|
+
wrappers
|
|
7515
|
+
) ?? { names: /* @__PURE__ */ new Set(), declaresSource: false };
|
|
7516
|
+
const declaredStatuses = declaredStatusesOf(
|
|
7517
|
+
pattern,
|
|
7518
|
+
pack,
|
|
7519
|
+
classification,
|
|
7520
|
+
functionNode,
|
|
7521
|
+
module,
|
|
7522
|
+
options
|
|
7523
|
+
);
|
|
7019
7524
|
return readRoutePaths(
|
|
7020
7525
|
pattern,
|
|
7021
7526
|
readPathArgument(classification, options),
|
|
@@ -7028,6 +7533,8 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7028
7533
|
pack,
|
|
7029
7534
|
name: functionName,
|
|
7030
7535
|
exportPath: [functionName],
|
|
7536
|
+
dependencyParameters,
|
|
7537
|
+
declaredStatuses,
|
|
7031
7538
|
method: verb,
|
|
7032
7539
|
routePath: entry.routePath,
|
|
7033
7540
|
...entry.mount !== void 0 ? { mount: entry.mount } : {},
|
|
@@ -7044,7 +7551,10 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7044
7551
|
responseShape: readResponseModel(pattern, classification, module, ctx),
|
|
7045
7552
|
statusCode: defaultedStatus(
|
|
7046
7553
|
declaredOrReturnedStatus(
|
|
7047
|
-
readStatusCode(pattern, classification
|
|
7554
|
+
readStatusCode(pattern, classification, {
|
|
7555
|
+
module,
|
|
7556
|
+
facts: options.facts
|
|
7557
|
+
}),
|
|
7048
7558
|
readReturnedStatus(pattern, functionNode, {
|
|
7049
7559
|
module,
|
|
7050
7560
|
facts: options.facts
|
|
@@ -7055,14 +7565,7 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7055
7565
|
definitionsCtx: ctx,
|
|
7056
7566
|
storage: options.storage,
|
|
7057
7567
|
importedDefinition: options.importedDefinition,
|
|
7058
|
-
wrappers
|
|
7059
|
-
pattern,
|
|
7060
|
-
pack,
|
|
7061
|
-
classification,
|
|
7062
|
-
functionNode,
|
|
7063
|
-
module,
|
|
7064
|
-
options
|
|
7065
|
-
)
|
|
7568
|
+
wrappers
|
|
7066
7569
|
},
|
|
7067
7570
|
options
|
|
7068
7571
|
)
|
|
@@ -7081,6 +7584,38 @@ function wrappersAround(pattern, pack, classification, definitionNode, module, o
|
|
|
7081
7584
|
definitionNode
|
|
7082
7585
|
});
|
|
7083
7586
|
}
|
|
7587
|
+
function declaredStatusesOf(pattern, pack, classification, definitionNode, module, options) {
|
|
7588
|
+
const keyword = pattern.responsesKeyword;
|
|
7589
|
+
if (keyword === void 0) {
|
|
7590
|
+
return [];
|
|
7591
|
+
}
|
|
7592
|
+
const above = options.wrappers?.callsAbove({
|
|
7593
|
+
pack,
|
|
7594
|
+
pattern,
|
|
7595
|
+
file: options.absoluteFile ?? options.filePath,
|
|
7596
|
+
module,
|
|
7597
|
+
classification,
|
|
7598
|
+
definitionNode
|
|
7599
|
+
}) ?? [];
|
|
7600
|
+
const dictionaries = [
|
|
7601
|
+
classification.keywordArgs[keyword]?.node,
|
|
7602
|
+
...above.map(
|
|
7603
|
+
(call) => readCallArguments(field(call, "arguments")).keywordArgs[keyword]?.node
|
|
7604
|
+
)
|
|
7605
|
+
].filter((node) => node?.type === "dictionary");
|
|
7606
|
+
const statuses = dictionaries.flatMap(
|
|
7607
|
+
(dictionary) => children(dictionary).flatMap((pair) => {
|
|
7608
|
+
const key = pair?.type === "pair" ? field(pair, "key") : null;
|
|
7609
|
+
const status = key === null ? null : statusNumberOf(key, {
|
|
7610
|
+
module: moduleOf(key),
|
|
7611
|
+
facts: options.facts,
|
|
7612
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
7613
|
+
});
|
|
7614
|
+
return status === null ? [] : [status];
|
|
7615
|
+
})
|
|
7616
|
+
);
|
|
7617
|
+
return [...new Set(statuses)].sort((a, b) => a - b);
|
|
7618
|
+
}
|
|
7084
7619
|
function readResponseShape(declared, readAnnotation) {
|
|
7085
7620
|
if (declared.kind === "written") {
|
|
7086
7621
|
return { reading: declared, passedOver: [] };
|
|
@@ -7164,6 +7699,8 @@ function buildRouteUnit(options) {
|
|
|
7164
7699
|
pathParamNames: template?.paramNames ?? null,
|
|
7165
7700
|
requestBodyFromAnnotatedClass,
|
|
7166
7701
|
injectedCallees,
|
|
7702
|
+
injectedTypes: new Set(pattern.injectedParameterTypes ?? []),
|
|
7703
|
+
module,
|
|
7167
7704
|
sources: pattern.parameterSources ?? {},
|
|
7168
7705
|
aliasKeyword: pattern.parameterAliasKeyword
|
|
7169
7706
|
},
|
|
@@ -7220,6 +7757,22 @@ function buildRouteUnit(options) {
|
|
|
7220
7757
|
};
|
|
7221
7758
|
branches.push(withBodyEffects(bare, extra));
|
|
7222
7759
|
}
|
|
7760
|
+
if (branches.length > 0) {
|
|
7761
|
+
branches.push(
|
|
7762
|
+
...validationFailureBranches(
|
|
7763
|
+
pattern,
|
|
7764
|
+
readsTheRequest(
|
|
7765
|
+
parameters,
|
|
7766
|
+
template,
|
|
7767
|
+
options.dependencyParameters ?? {
|
|
7768
|
+
names: /* @__PURE__ */ new Set(),
|
|
7769
|
+
declaresSource: false
|
|
7770
|
+
}
|
|
7771
|
+
),
|
|
7772
|
+
rangeOf(definitionNode)
|
|
7773
|
+
)
|
|
7774
|
+
);
|
|
7775
|
+
}
|
|
7223
7776
|
const bodyNode = field(definitionNode, "body");
|
|
7224
7777
|
return {
|
|
7225
7778
|
identity: {
|
|
@@ -7251,9 +7804,51 @@ function buildRouteUnit(options) {
|
|
|
7251
7804
|
...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {},
|
|
7252
7805
|
...options.mount !== void 0 ? { mount: options.mount } : {},
|
|
7253
7806
|
...options.wrappers !== void 0 && options.wrappers.length > 0 ? { wrappers: options.wrappers } : {},
|
|
7254
|
-
...pack.requestSpelling === void 0 ? {} : { requestSpelling: pack.requestSpelling }
|
|
7807
|
+
...pack.requestSpelling === void 0 ? {} : { requestSpelling: pack.requestSpelling },
|
|
7808
|
+
...options.declaredStatuses !== void 0 && options.declaredStatuses.length > 0 ? { declaredStatuses: options.declaredStatuses } : {}
|
|
7255
7809
|
};
|
|
7256
7810
|
}
|
|
7811
|
+
function readsTheRequest(parameters, template, dependencies) {
|
|
7812
|
+
if (dependencies.declaresSource || parameters.some((parameter) => parameter.role !== null)) {
|
|
7813
|
+
return true;
|
|
7814
|
+
}
|
|
7815
|
+
return [...template?.paramNames ?? []].some(
|
|
7816
|
+
(name) => dependencies.names.has(name)
|
|
7817
|
+
);
|
|
7818
|
+
}
|
|
7819
|
+
function validationFailureBranches(pattern, readsRequest, range) {
|
|
7820
|
+
const status = pattern.validationFailureStatus;
|
|
7821
|
+
if (status === void 0 || !readsRequest) {
|
|
7822
|
+
return [];
|
|
7823
|
+
}
|
|
7824
|
+
return [
|
|
7825
|
+
{
|
|
7826
|
+
conditions: [
|
|
7827
|
+
{
|
|
7828
|
+
sourceText: "request input fails validation",
|
|
7829
|
+
structured: null,
|
|
7830
|
+
polarity: "positive",
|
|
7831
|
+
source: "earlyThrow"
|
|
7832
|
+
}
|
|
7833
|
+
],
|
|
7834
|
+
terminal: {
|
|
7835
|
+
kind: "response",
|
|
7836
|
+
statusCode: { type: "literal", value: status },
|
|
7837
|
+
body: null,
|
|
7838
|
+
exceptionType: null,
|
|
7839
|
+
message: null,
|
|
7840
|
+
component: null,
|
|
7841
|
+
renderTree: null,
|
|
7842
|
+
delegateTarget: null,
|
|
7843
|
+
emitEvent: null,
|
|
7844
|
+
location: range
|
|
7845
|
+
},
|
|
7846
|
+
effects: [],
|
|
7847
|
+
location: range,
|
|
7848
|
+
isDefault: false
|
|
7849
|
+
}
|
|
7850
|
+
];
|
|
7851
|
+
}
|
|
7257
7852
|
function unreadRoleReadings(parameters, range) {
|
|
7258
7853
|
if (!parameters.some((parameter) => parameter.role === null)) {
|
|
7259
7854
|
return [];
|
|
@@ -7320,10 +7915,7 @@ function readParameters(definitionNode, reading, skipReceiverParam) {
|
|
|
7320
7915
|
}
|
|
7321
7916
|
const out = [];
|
|
7322
7917
|
let position = 0;
|
|
7323
|
-
for (const param of parametersNode
|
|
7324
|
-
if (param === null) {
|
|
7325
|
-
continue;
|
|
7326
|
-
}
|
|
7918
|
+
for (const param of children(parametersNode)) {
|
|
7327
7919
|
if (skipReceiverParam && position === 0 && isReceiverParam(param)) {
|
|
7328
7920
|
position += 1;
|
|
7329
7921
|
continue;
|
|
@@ -7347,7 +7939,7 @@ function readParameter(param, reading, position) {
|
|
|
7347
7939
|
const { name, typeNode } = info;
|
|
7348
7940
|
const shape = typeNode !== null ? annotationToShape(typeNode, reading.scope, reading.ctx) : null;
|
|
7349
7941
|
const typeText = typeNode !== null ? typeNode.text : null;
|
|
7350
|
-
if (isInjectedParameter(param, reading)) {
|
|
7942
|
+
if (isInjectedParameter(param, reading) || isInjectedType(typeNode, reading)) {
|
|
7351
7943
|
return { name, position, role: null, typeText };
|
|
7352
7944
|
}
|
|
7353
7945
|
const declared = declaringCall(
|
|
@@ -7427,6 +8019,14 @@ function calleeName2(call) {
|
|
|
7427
8019
|
function isInjectedParameter(param, reading) {
|
|
7428
8020
|
return declaringCall(param, reading.injectedCallees, reading) !== null;
|
|
7429
8021
|
}
|
|
8022
|
+
function isInjectedType(typeNode, reading) {
|
|
8023
|
+
if (typeNode === null || reading.injectedTypes.size === 0) {
|
|
8024
|
+
return false;
|
|
8025
|
+
}
|
|
8026
|
+
const written = typeNode.type === "type" ? typeNode.namedChild(0) ?? null : typeNode;
|
|
8027
|
+
const origin = written === null ? null : originOf(written, reading.module);
|
|
8028
|
+
return origin !== null && reading.injectedTypes.has(`${origin.module}.${origin.name}`);
|
|
8029
|
+
}
|
|
7430
8030
|
function declaringCall(param, callees, reading) {
|
|
7431
8031
|
if (callees.size === 0) {
|
|
7432
8032
|
return null;
|
|
@@ -7660,6 +8260,7 @@ import {
|
|
|
7660
8260
|
placeArgTargets as placeArgTargets2,
|
|
7661
8261
|
placeCalleeParameters as placeCalleeParameters2,
|
|
7662
8262
|
placeCalls as placeCalls2,
|
|
8263
|
+
placePossibleCalls as placePossibleCalls2,
|
|
7663
8264
|
recordParameterGaps as recordParameterGaps2,
|
|
7664
8265
|
summaryIdFromParts,
|
|
7665
8266
|
unfollowedCallGap as unfollowedCallGap2
|
|
@@ -7671,10 +8272,12 @@ import {
|
|
|
7671
8272
|
createCacheLayer,
|
|
7672
8273
|
createTimer,
|
|
7673
8274
|
effectToIR,
|
|
8275
|
+
extractionCacheDirFor,
|
|
7674
8276
|
extractionConfigStamp,
|
|
7675
8277
|
KeptParses,
|
|
7676
8278
|
moduleInitStructure,
|
|
7677
8279
|
noopTimer,
|
|
8280
|
+
ownersWhereWritten,
|
|
7678
8281
|
runDigest,
|
|
7679
8282
|
stampModuleImports,
|
|
7680
8283
|
stampModules
|
|
@@ -7724,7 +8327,7 @@ var DEFERRED_BODY_TYPES3 = /* @__PURE__ */ new Set(["function_definition", "lamb
|
|
|
7724
8327
|
function exitSites(root, module) {
|
|
7725
8328
|
const found = [];
|
|
7726
8329
|
const startScope = module.scopeFor.get(root.id) ?? module.moduleScope;
|
|
7727
|
-
walkDescendants4(root, startScope, {
|
|
8330
|
+
walkDescendants4(root, startScope, children, {
|
|
7728
8331
|
at: (node, scope) => {
|
|
7729
8332
|
const site = exitSiteAt(node, scope);
|
|
7730
8333
|
if (site !== null) {
|
|
@@ -7741,7 +8344,7 @@ function exitSites(root, module) {
|
|
|
7741
8344
|
return found;
|
|
7742
8345
|
}
|
|
7743
8346
|
function exitSiteAt(statement, scope) {
|
|
7744
|
-
const expression = statement.
|
|
8347
|
+
const expression = statement.namedChild(0) ?? null;
|
|
7745
8348
|
if (expression === null) {
|
|
7746
8349
|
return null;
|
|
7747
8350
|
}
|
|
@@ -7755,12 +8358,12 @@ function exitSiteAt(statement, scope) {
|
|
|
7755
8358
|
return endsTheProcess(callee, scope) ? { statement, code, raised: false } : null;
|
|
7756
8359
|
}
|
|
7757
8360
|
if (statement.type === "raise_statement") {
|
|
7758
|
-
return
|
|
8361
|
+
return isBuiltin2(callee, scope, "SystemExit") ? { statement, code, raised: true } : null;
|
|
7759
8362
|
}
|
|
7760
8363
|
return null;
|
|
7761
8364
|
}
|
|
7762
8365
|
function endsTheProcess(callee, scope) {
|
|
7763
|
-
return isStdlibMember(callee, scope, "sys", "exit") ||
|
|
8366
|
+
return isStdlibMember(callee, scope, "sys", "exit") || isBuiltin2(callee, scope, "exit") || isBuiltin2(callee, scope, "quit");
|
|
7764
8367
|
}
|
|
7765
8368
|
function firstArgument(call) {
|
|
7766
8369
|
return callArguments(call).find(
|
|
@@ -7921,7 +8524,9 @@ import {
|
|
|
7921
8524
|
placeArgTargets,
|
|
7922
8525
|
placeCalleeParameters,
|
|
7923
8526
|
placeCalls,
|
|
8527
|
+
placePossibleCalls,
|
|
7924
8528
|
recordParameterGaps,
|
|
8529
|
+
StopList,
|
|
7925
8530
|
TargetPlacements,
|
|
7926
8531
|
unfollowedCallGap,
|
|
7927
8532
|
worthRecording
|
|
@@ -7944,7 +8549,7 @@ function argparseFlagReads(definition, module, parameterNames2) {
|
|
|
7944
8549
|
const parsers = /* @__PURE__ */ new Map();
|
|
7945
8550
|
const handedTo = /* @__PURE__ */ new Map();
|
|
7946
8551
|
const startScope = module.scopeFor.get(definition.id) ?? module.moduleScope;
|
|
7947
|
-
walkDescendants5(definition, startScope, {
|
|
8552
|
+
walkDescendants5(definition, startScope, children, {
|
|
7948
8553
|
at: (node, scope) => {
|
|
7949
8554
|
noteParser(node, scope, parsers);
|
|
7950
8555
|
noteArgument(node, parsers);
|
|
@@ -8020,7 +8625,9 @@ function methodCalledOn(call) {
|
|
|
8020
8625
|
import {
|
|
8021
8626
|
calleeOutcomeOf,
|
|
8022
8627
|
calleeOutcomes,
|
|
8628
|
+
dispatchOutcomes,
|
|
8023
8629
|
noteKeyRead as noteKeyRead3,
|
|
8630
|
+
RECEIVER_STORE_NAME as RECEIVER_STORE_NAME2,
|
|
8024
8631
|
writtenSourcesOf
|
|
8025
8632
|
} from "@suss/resolution";
|
|
8026
8633
|
var STOP_FOR = {
|
|
@@ -8051,11 +8658,77 @@ function resolveCallee2(call, site, ctx, read) {
|
|
|
8051
8658
|
return spelling;
|
|
8052
8659
|
}
|
|
8053
8660
|
const outcome = read?.outcomes.get(spelling.key) ?? calleeOutcomeOf(ctx.facts, spelling.key);
|
|
8661
|
+
if (selfCallInMixin(call, outcome, site, ctx)) {
|
|
8662
|
+
return { kind: "stopped", reason: "selfCallInMixin" };
|
|
8663
|
+
}
|
|
8054
8664
|
return asCallee(outcome, site.owner, ctx);
|
|
8055
8665
|
}
|
|
8666
|
+
function selfCallInMixin(call, outcome, site, ctx) {
|
|
8667
|
+
if (outcome.kind !== "callerSupplied" || !outcome.key.startsWith(`${site.owner}#`)) {
|
|
8668
|
+
return false;
|
|
8669
|
+
}
|
|
8670
|
+
const callee = readThrough(field(call, "function"));
|
|
8671
|
+
const receiver = callee?.type === "attribute" ? field(callee, "object") : null;
|
|
8672
|
+
const name = callee === null ? null : field(callee, "attribute")?.text;
|
|
8673
|
+
if (receiver?.type !== "identifier" || name === void 0 || name === null) {
|
|
8674
|
+
return false;
|
|
8675
|
+
}
|
|
8676
|
+
if (outcome.key !== `${site.owner}#${receiver.text}`) {
|
|
8677
|
+
return false;
|
|
8678
|
+
}
|
|
8679
|
+
return ctx.facts.lookup("instanceOf", 0, outcome.key).some((row) => {
|
|
8680
|
+
const classKey = String(row[1]);
|
|
8681
|
+
return ctx.facts.has("plainClass", [classKey]) && !instancesHaveAttribute(ctx.facts, classKey, name);
|
|
8682
|
+
});
|
|
8683
|
+
}
|
|
8684
|
+
var FALLBACK_ATTRIBUTE = "__getattr__";
|
|
8685
|
+
function instancesHaveAttribute(facts, classKey, name) {
|
|
8686
|
+
return facts.lookup("holdsProperty", 0, classKey).some((member) => {
|
|
8687
|
+
if (String(member[1]) === FALLBACK_ATTRIBUTE) {
|
|
8688
|
+
return true;
|
|
8689
|
+
}
|
|
8690
|
+
return facts.lookup("storesProperty", 0, String(member[2])).some(
|
|
8691
|
+
(store) => String(store[1]) === name && store[3] === RECEIVER_STORE_NAME2
|
|
8692
|
+
);
|
|
8693
|
+
});
|
|
8694
|
+
}
|
|
8056
8695
|
function namedOutcomes(keys, ctx) {
|
|
8057
8696
|
return calleeOutcomes(ctx.facts, [...new Set(keys)]);
|
|
8058
8697
|
}
|
|
8698
|
+
function dispatchedCalls(calls, ctx) {
|
|
8699
|
+
const byKey = new Map(
|
|
8700
|
+
calls.map(({ call, site }) => [nodeId(site.file.file, call), call])
|
|
8701
|
+
);
|
|
8702
|
+
const found = /* @__PURE__ */ new Map();
|
|
8703
|
+
for (const [key, outcome] of dispatchOutcomes(ctx.facts, [...byKey.keys()])) {
|
|
8704
|
+
const call = byKey.get(key);
|
|
8705
|
+
if (call === void 0) {
|
|
8706
|
+
continue;
|
|
8707
|
+
}
|
|
8708
|
+
const targets = /* @__PURE__ */ new Map();
|
|
8709
|
+
for (const fn of outcome.functions) {
|
|
8710
|
+
for (const target of reachedThrough(fn, outcome.through, ctx)) {
|
|
8711
|
+
targets.set(nodeId(target.file.file, target.node), target);
|
|
8712
|
+
}
|
|
8713
|
+
}
|
|
8714
|
+
found.set(call.id, {
|
|
8715
|
+
targets: [...targets.values()],
|
|
8716
|
+
certain: outcome.certain && outcome.functions.every((fn) => !isLambda(fn, ctx)),
|
|
8717
|
+
unresolved: outcome.unresolved
|
|
8718
|
+
});
|
|
8719
|
+
}
|
|
8720
|
+
return found;
|
|
8721
|
+
}
|
|
8722
|
+
function reachedThrough(key, through, ctx) {
|
|
8723
|
+
const keys = isLambda(key, ctx) ? through.get(key) ?? [] : [key];
|
|
8724
|
+
return keys.flatMap((one) => {
|
|
8725
|
+
const target = isLambda(one, ctx) ? null : functionAt(one, ctx);
|
|
8726
|
+
return target === null ? [] : [target];
|
|
8727
|
+
});
|
|
8728
|
+
}
|
|
8729
|
+
function isLambda(key, ctx) {
|
|
8730
|
+
return ctx.definitions.get(key)?.type === "lambda";
|
|
8731
|
+
}
|
|
8059
8732
|
function functionNamed(nameKey2, ctx, read) {
|
|
8060
8733
|
if (assignedElsewhere(ctx.facts, nameKey2)) {
|
|
8061
8734
|
return null;
|
|
@@ -8274,6 +8947,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8274
8947
|
const targetsByKey = /* @__PURE__ */ new Map();
|
|
8275
8948
|
const stopsByKey = /* @__PURE__ */ new Map();
|
|
8276
8949
|
const argTargetsByKey = /* @__PURE__ */ new Map();
|
|
8950
|
+
const possibleTargetsByKey = /* @__PURE__ */ new Map();
|
|
8277
8951
|
const parameterCallsByKey = /* @__PURE__ */ new Map();
|
|
8278
8952
|
const callsByKey = /* @__PURE__ */ new Map();
|
|
8279
8953
|
const passedPositions = /* @__PURE__ */ new Set();
|
|
@@ -8336,6 +9010,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8336
9010
|
}
|
|
8337
9011
|
targetsByKey.set(key, scan.targets);
|
|
8338
9012
|
argTargetsByKey.set(key, scan.argTargets);
|
|
9013
|
+
possibleTargetsByKey.set(key, scan.possibleTargets);
|
|
8339
9014
|
if (scan.parameterCalls.length > 0) {
|
|
8340
9015
|
parameterCallsByKey.set(key, scan.parameterCalls);
|
|
8341
9016
|
}
|
|
@@ -8386,6 +9061,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8386
9061
|
}
|
|
8387
9062
|
placeCalls(summary2, targetsByKey.get(key));
|
|
8388
9063
|
placeArgTargets(summary2, argTargetsByKey.get(key));
|
|
9064
|
+
placePossibleCalls(summary2, possibleTargetsByKey.get(key));
|
|
8389
9065
|
placeCalleeParameters(summary2, parameterCallsByKey.get(key));
|
|
8390
9066
|
return summary2;
|
|
8391
9067
|
};
|
|
@@ -8409,6 +9085,7 @@ function reachedFunctions(seeds, options) {
|
|
|
8409
9085
|
targetsByKey,
|
|
8410
9086
|
stopsByKey,
|
|
8411
9087
|
argTargetsByKey,
|
|
9088
|
+
possibleTargetsByKey,
|
|
8412
9089
|
parameterCallsByKey,
|
|
8413
9090
|
callsByKey,
|
|
8414
9091
|
passedPositions,
|
|
@@ -8432,24 +9109,42 @@ function chargeOf(charges, key) {
|
|
|
8432
9109
|
}
|
|
8433
9110
|
return charge;
|
|
8434
9111
|
}
|
|
9112
|
+
function dispatchedAmong(written, spellings, ctx) {
|
|
9113
|
+
return dispatchedCalls(
|
|
9114
|
+
written.filter(({ call, site }) => {
|
|
9115
|
+
if (!ENTRY_CALLEE_TYPES.has(field(call, "function")?.type ?? "")) {
|
|
9116
|
+
return false;
|
|
9117
|
+
}
|
|
9118
|
+
const outcome = resolveCallee2(call, site, ctx, spellings);
|
|
9119
|
+
return outcome.kind === "stopped" && outcome.reason !== "callerSupplied";
|
|
9120
|
+
}),
|
|
9121
|
+
ctx
|
|
9122
|
+
);
|
|
9123
|
+
}
|
|
9124
|
+
var ENTRY_CALLEE_TYPES = /* @__PURE__ */ new Set(["subscript", "call", "identifier"]);
|
|
8435
9125
|
function batchedReads(round, ctx) {
|
|
8436
9126
|
const bodies = round.flatMap(
|
|
8437
9127
|
(entry) => "source" in entry ? [{ key: entry.key, source: entry.source, ...bodyOf(entry.source) }] : []
|
|
8438
9128
|
);
|
|
8439
|
-
const
|
|
8440
|
-
|
|
8441
|
-
ctx
|
|
8442
|
-
);
|
|
9129
|
+
const written = bodies.flatMap((body) => body.written);
|
|
9130
|
+
const spellings = calleeSpellings(written, ctx);
|
|
8443
9131
|
const passed = namedOutcomes(
|
|
8444
9132
|
bodies.flatMap(
|
|
8445
|
-
({ source, written }) =>
|
|
9133
|
+
({ source, written: written2 }) => written2.flatMap(({ call }) => passedNameKeys(source.file, call))
|
|
8446
9134
|
),
|
|
8447
9135
|
ctx
|
|
8448
9136
|
);
|
|
9137
|
+
const dispatched = dispatchedAmong(written, spellings, ctx);
|
|
8449
9138
|
return new Map(
|
|
8450
9139
|
bodies.map((body) => [
|
|
8451
9140
|
body.key,
|
|
8452
|
-
{
|
|
9141
|
+
{
|
|
9142
|
+
body: body.body,
|
|
9143
|
+
written: body.written,
|
|
9144
|
+
spellings,
|
|
9145
|
+
passed,
|
|
9146
|
+
dispatched
|
|
9147
|
+
}
|
|
8453
9148
|
])
|
|
8454
9149
|
);
|
|
8455
9150
|
}
|
|
@@ -8480,13 +9175,15 @@ function scanOnce(source, key, ctx, options, read, charges) {
|
|
|
8480
9175
|
}
|
|
8481
9176
|
function ownReads(source, ctx) {
|
|
8482
9177
|
const body = bodyOf(source);
|
|
9178
|
+
const spellings = calleeSpellings(body.written, ctx);
|
|
8483
9179
|
return {
|
|
8484
9180
|
...body,
|
|
8485
|
-
spellings
|
|
9181
|
+
spellings,
|
|
8486
9182
|
passed: namedOutcomes(
|
|
8487
9183
|
body.written.flatMap(({ call }) => passedNameKeys(source.file, call)),
|
|
8488
9184
|
ctx
|
|
8489
|
-
)
|
|
9185
|
+
),
|
|
9186
|
+
dispatched: dispatchedAmong(body.written, spellings, ctx)
|
|
8490
9187
|
};
|
|
8491
9188
|
}
|
|
8492
9189
|
function storedScan(scan) {
|
|
@@ -8502,6 +9199,10 @@ function storedScan(scan) {
|
|
|
8502
9199
|
callee,
|
|
8503
9200
|
[...byPosition]
|
|
8504
9201
|
]),
|
|
9202
|
+
possibleTargets: [...scan.possibleTargets].map(([callee, places]) => [
|
|
9203
|
+
callee,
|
|
9204
|
+
[...places]
|
|
9205
|
+
]),
|
|
8505
9206
|
parameterCalls: [...scan.parameterCalls],
|
|
8506
9207
|
passedPositions: [...scan.passedPositions]
|
|
8507
9208
|
};
|
|
@@ -8517,6 +9218,7 @@ function scanFromStored(stored, functionFor) {
|
|
|
8517
9218
|
new Map(byPosition)
|
|
8518
9219
|
])
|
|
8519
9220
|
),
|
|
9221
|
+
possibleTargets: new Map(stored.possibleTargets),
|
|
8520
9222
|
parameterCalls: stored.parameterCalls,
|
|
8521
9223
|
passedPositions: new Set(stored.passedPositions)
|
|
8522
9224
|
};
|
|
@@ -8545,6 +9247,7 @@ var EMPTY_SCAN = {
|
|
|
8545
9247
|
stops: [],
|
|
8546
9248
|
targets: /* @__PURE__ */ new Map(),
|
|
8547
9249
|
argTargets: /* @__PURE__ */ new Map(),
|
|
9250
|
+
possibleTargets: /* @__PURE__ */ new Map(),
|
|
8548
9251
|
parameterCalls: [],
|
|
8549
9252
|
passedPositions: /* @__PURE__ */ new Set()
|
|
8550
9253
|
};
|
|
@@ -8602,14 +9305,14 @@ function passedNameKeys(file, call) {
|
|
|
8602
9305
|
if (args === null) {
|
|
8603
9306
|
return [];
|
|
8604
9307
|
}
|
|
8605
|
-
return args.
|
|
9308
|
+
return children(args).flatMap((arg) => {
|
|
8606
9309
|
const key = passedNameKeyOf(file, arg);
|
|
8607
9310
|
return key === null ? [] : [key];
|
|
8608
9311
|
});
|
|
8609
9312
|
}
|
|
8610
9313
|
function scanBody(source, ctx, recognized, read, implied) {
|
|
8611
9314
|
const followed = [];
|
|
8612
|
-
const stops =
|
|
9315
|
+
const stops = new StopList();
|
|
8613
9316
|
const placements = new TargetPlacements();
|
|
8614
9317
|
const parameterCalls = [];
|
|
8615
9318
|
const passedPositions = /* @__PURE__ */ new Set();
|
|
@@ -8621,12 +9324,25 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8621
9324
|
return EMPTY_SCAN;
|
|
8622
9325
|
}
|
|
8623
9326
|
const ownParameters = callParameterNames(node, source.exportPath.length > 1);
|
|
9327
|
+
const follow = (target) => {
|
|
9328
|
+
const key = keyOf2(target);
|
|
9329
|
+
if (!seen.has(key)) {
|
|
9330
|
+
seen.add(key);
|
|
9331
|
+
followed.push(target);
|
|
9332
|
+
}
|
|
9333
|
+
};
|
|
8624
9334
|
const recordPassedArgs = (call, callee, calleeKey2) => {
|
|
8625
9335
|
const args = field(call, "arguments");
|
|
8626
9336
|
if (args === null) {
|
|
8627
9337
|
return;
|
|
8628
9338
|
}
|
|
8629
|
-
args.
|
|
9339
|
+
children(args).forEach((arg, position) => {
|
|
9340
|
+
if (arg.type === "lambda") {
|
|
9341
|
+
if (calleeKey2 !== null) {
|
|
9342
|
+
passedPositions.add(`${calleeKey2}#${position}`);
|
|
9343
|
+
}
|
|
9344
|
+
return;
|
|
9345
|
+
}
|
|
8630
9346
|
const nameKey2 = passedNameKeyOf(file, arg);
|
|
8631
9347
|
if (nameKey2 === null) {
|
|
8632
9348
|
return;
|
|
@@ -8635,11 +9351,7 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8635
9351
|
if (resolved === null) {
|
|
8636
9352
|
return;
|
|
8637
9353
|
}
|
|
8638
|
-
|
|
8639
|
-
if (!seen.has(key)) {
|
|
8640
|
-
seen.add(key);
|
|
8641
|
-
followed.push(resolved);
|
|
8642
|
-
}
|
|
9354
|
+
follow(resolved);
|
|
8643
9355
|
placements.placeArg(callee, position, {
|
|
8644
9356
|
file: resolved.file.displayPath,
|
|
8645
9357
|
span: spanOf(resolved.node)
|
|
@@ -8649,9 +9361,30 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8649
9361
|
}
|
|
8650
9362
|
});
|
|
8651
9363
|
};
|
|
9364
|
+
const recordPossible = (call, callee, dispatched) => {
|
|
9365
|
+
dispatched.targets.forEach(follow);
|
|
9366
|
+
placements.placePossible(
|
|
9367
|
+
callee,
|
|
9368
|
+
dispatched.targets.map((target) => ({
|
|
9369
|
+
file: target.file.displayPath,
|
|
9370
|
+
span: spanOf(target.node)
|
|
9371
|
+
}))
|
|
9372
|
+
);
|
|
9373
|
+
recordPassedArgs(call, callee, null);
|
|
9374
|
+
if (dispatched.unresolved > 0 && !recognized.has(call.id)) {
|
|
9375
|
+
stops.add({ callee, reason: "unsettledValue" });
|
|
9376
|
+
}
|
|
9377
|
+
};
|
|
8652
9378
|
const record = (call, site) => {
|
|
8653
9379
|
const callee = calleeText(call);
|
|
8654
|
-
const
|
|
9380
|
+
const settled = resolveCallee2(call, site, ctx, spellings);
|
|
9381
|
+
const dispatched = settled.kind === "stopped" ? read.dispatched.get(call.id) : void 0;
|
|
9382
|
+
const [only] = dispatched?.targets ?? [];
|
|
9383
|
+
if (dispatched !== void 0 && only !== void 0 && !dispatched.certain) {
|
|
9384
|
+
recordPossible(call, callee, dispatched);
|
|
9385
|
+
return;
|
|
9386
|
+
}
|
|
9387
|
+
const outcome = only === void 0 ? settled : { kind: "followed", target: only };
|
|
8655
9388
|
placeCallee(placements, callee, outcome, call, file);
|
|
8656
9389
|
recordPassedArgs(
|
|
8657
9390
|
call,
|
|
@@ -8659,10 +9392,12 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8659
9392
|
outcome.kind === "followed" ? keyOf2(outcome.target) : null
|
|
8660
9393
|
);
|
|
8661
9394
|
if (outcome.kind === "stopped") {
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
9395
|
+
if (!recognized.has(call.id) && worthRecording(outcome.reason)) {
|
|
9396
|
+
stops.add({
|
|
9397
|
+
callee,
|
|
9398
|
+
reason: outcome.reason,
|
|
9399
|
+
...resultUsedAsValue(call) ? { usedAsValue: true } : {}
|
|
9400
|
+
});
|
|
8666
9401
|
}
|
|
8667
9402
|
if (outcome.reason === "callerSupplied" && !parameterCallsSeen.has(callee)) {
|
|
8668
9403
|
const parameterIndex = ownParameters.indexOf(callee);
|
|
@@ -8673,11 +9408,7 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8673
9408
|
}
|
|
8674
9409
|
return;
|
|
8675
9410
|
}
|
|
8676
|
-
|
|
8677
|
-
if (!seen.has(key)) {
|
|
8678
|
-
seen.add(key);
|
|
8679
|
-
followed.push(outcome.target);
|
|
8680
|
-
}
|
|
9411
|
+
follow(outcome.target);
|
|
8681
9412
|
};
|
|
8682
9413
|
for (const { call, site } of written) {
|
|
8683
9414
|
record(call, site);
|
|
@@ -8687,24 +9418,21 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8687
9418
|
file: target.file.displayPath,
|
|
8688
9419
|
span: spanOf(target.node)
|
|
8689
9420
|
});
|
|
8690
|
-
|
|
8691
|
-
if (!seen.has(key)) {
|
|
8692
|
-
seen.add(key);
|
|
8693
|
-
followed.push(target);
|
|
8694
|
-
}
|
|
9421
|
+
follow(target);
|
|
8695
9422
|
}
|
|
8696
9423
|
return {
|
|
8697
9424
|
followed,
|
|
8698
|
-
stops,
|
|
9425
|
+
stops: stops.stops,
|
|
8699
9426
|
targets: placements.targets,
|
|
8700
9427
|
argTargets: placements.argTargets,
|
|
9428
|
+
possibleTargets: placements.possibleTargets,
|
|
8701
9429
|
parameterCalls,
|
|
8702
9430
|
passedPositions
|
|
8703
9431
|
};
|
|
8704
9432
|
}
|
|
8705
9433
|
function callsWritten(file, body, outer, owner, limit) {
|
|
8706
9434
|
const found = [];
|
|
8707
|
-
walkDescendants6(body, outer, {
|
|
9435
|
+
walkDescendants6(body, outer, children, {
|
|
8708
9436
|
at: (child, scope) => {
|
|
8709
9437
|
if (child.type === "call") {
|
|
8710
9438
|
found.push({ call: child, site: { file, scope, owner } });
|
|
@@ -8730,7 +9458,7 @@ function identifiersUnder(node, found = []) {
|
|
|
8730
9458
|
found.push(node.text);
|
|
8731
9459
|
return found;
|
|
8732
9460
|
}
|
|
8733
|
-
for (const child of node
|
|
9461
|
+
for (const child of children(node)) {
|
|
8734
9462
|
if (child !== null && child.type !== "attribute" && child.type !== "subscript") {
|
|
8735
9463
|
identifiersUnder(child, found);
|
|
8736
9464
|
}
|
|
@@ -8831,10 +9559,7 @@ function positionalParameters(node, isMethod2) {
|
|
|
8831
9559
|
}
|
|
8832
9560
|
const out = [];
|
|
8833
9561
|
let position = 0;
|
|
8834
|
-
for (const param of parameters
|
|
8835
|
-
if (param === null) {
|
|
8836
|
-
continue;
|
|
8837
|
-
}
|
|
9562
|
+
for (const param of children(parameters)) {
|
|
8838
9563
|
const name = parameterName2(param);
|
|
8839
9564
|
if (name === null) {
|
|
8840
9565
|
continue;
|
|
@@ -8854,10 +9579,7 @@ function callParameterNames(node, isMethod2) {
|
|
|
8854
9579
|
return [];
|
|
8855
9580
|
}
|
|
8856
9581
|
const names = [];
|
|
8857
|
-
for (const param of parameters
|
|
8858
|
-
if (param === null) {
|
|
8859
|
-
continue;
|
|
8860
|
-
}
|
|
9582
|
+
for (const param of children(parameters)) {
|
|
8861
9583
|
const name = parameterName2(param);
|
|
8862
9584
|
if (name === null) {
|
|
8863
9585
|
continue;
|
|
@@ -8954,7 +9676,7 @@ function exportsOf(file, node, exportName) {
|
|
|
8954
9676
|
if (node.type !== "class_definition" || body === null) {
|
|
8955
9677
|
return [];
|
|
8956
9678
|
}
|
|
8957
|
-
return body.
|
|
9679
|
+
return children(body).flatMap((child) => {
|
|
8958
9680
|
if (child === null) {
|
|
8959
9681
|
return [];
|
|
8960
9682
|
}
|
|
@@ -9027,6 +9749,10 @@ var PackPositions = class {
|
|
|
9027
9749
|
const [packAt, patternAt] = id.split("/").map(Number);
|
|
9028
9750
|
return this.packs[packAt ?? -1]?.discovery[patternAt ?? -1];
|
|
9029
9751
|
}
|
|
9752
|
+
packOf(id) {
|
|
9753
|
+
const [packAt] = id.split("/").map(Number);
|
|
9754
|
+
return this.packs[packAt ?? -1];
|
|
9755
|
+
}
|
|
9030
9756
|
formAt(at) {
|
|
9031
9757
|
const pack = this.packs[at[0]];
|
|
9032
9758
|
const pattern = pack?.discovery[at[1]];
|
|
@@ -9077,6 +9803,11 @@ function watchRouterIndex(index, db, positions, fileOfModule) {
|
|
|
9077
9803
|
found
|
|
9078
9804
|
);
|
|
9079
9805
|
return found;
|
|
9806
|
+
},
|
|
9807
|
+
// The wrapper index notes what it reads through the mounts, in terms
|
|
9808
|
+
// it can look up again.
|
|
9809
|
+
mountsAbove(pattern, constructionKey) {
|
|
9810
|
+
return index.mountsAbove(pattern, constructionKey);
|
|
9080
9811
|
}
|
|
9081
9812
|
};
|
|
9082
9813
|
}
|
|
@@ -9181,9 +9912,33 @@ function buildRouterIndex(files, packs, resolverOptions) {
|
|
|
9181
9912
|
};
|
|
9182
9913
|
}
|
|
9183
9914
|
return NOT_ROUTER;
|
|
9915
|
+
},
|
|
9916
|
+
mountsAbove(pattern, constructionKey) {
|
|
9917
|
+
const index = byPattern.get(pattern);
|
|
9918
|
+
return index === void 0 ? null : hopsAbove(index, constructionKey);
|
|
9184
9919
|
}
|
|
9185
9920
|
};
|
|
9186
9921
|
}
|
|
9922
|
+
function hopsAbove(index, key) {
|
|
9923
|
+
const hops = [];
|
|
9924
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9925
|
+
let current = key;
|
|
9926
|
+
while (current !== null) {
|
|
9927
|
+
const construction = index.byValueKey.get(current);
|
|
9928
|
+
if (construction === void 0 || seen.has(current)) {
|
|
9929
|
+
return null;
|
|
9930
|
+
}
|
|
9931
|
+
seen.add(current);
|
|
9932
|
+
const states = index.mounts.get(construction) ?? [];
|
|
9933
|
+
const only = states.length === 1 ? states[0] : void 0;
|
|
9934
|
+
if (only?.kind !== "mounted" || only.written === void 0) {
|
|
9935
|
+
return null;
|
|
9936
|
+
}
|
|
9937
|
+
hops.push({ ...only.written, parentKey: only.parentValueKey });
|
|
9938
|
+
current = only.parentValueKey;
|
|
9939
|
+
}
|
|
9940
|
+
return hops;
|
|
9941
|
+
}
|
|
9187
9942
|
function composedPrefixOf(index, construction, routerPath) {
|
|
9188
9943
|
const ownPrefix = composedOwnPrefix(construction.prefix, index.composition);
|
|
9189
9944
|
if (ownPrefix.kind === "abstain") {
|
|
@@ -9466,8 +10221,8 @@ function constructionStatement(stmt, module, importModule) {
|
|
|
9466
10221
|
if (stmt.type !== "expression_statement") {
|
|
9467
10222
|
return null;
|
|
9468
10223
|
}
|
|
9469
|
-
const assignment2 = stmt.
|
|
9470
|
-
(child) => child
|
|
10224
|
+
const assignment2 = children(stmt).find(
|
|
10225
|
+
(child) => child.type === "assignment"
|
|
9471
10226
|
);
|
|
9472
10227
|
if (assignment2 === void 0) {
|
|
9473
10228
|
return null;
|
|
@@ -9541,7 +10296,7 @@ function collectReturnedConstructions(bound, importModule, composition, index) {
|
|
|
9541
10296
|
if (inner.type !== "return_statement") {
|
|
9542
10297
|
continue;
|
|
9543
10298
|
}
|
|
9544
|
-
const returned = inner.
|
|
10299
|
+
const returned = inner.namedChild(0);
|
|
9545
10300
|
if (returned?.type !== "call") {
|
|
9546
10301
|
continue;
|
|
9547
10302
|
}
|
|
@@ -9721,7 +10476,7 @@ function sequenceElementNames(node) {
|
|
|
9721
10476
|
return null;
|
|
9722
10477
|
}
|
|
9723
10478
|
const names = [];
|
|
9724
|
-
for (const child of node
|
|
10479
|
+
for (const child of children(node)) {
|
|
9725
10480
|
if (child?.type !== "identifier") {
|
|
9726
10481
|
return null;
|
|
9727
10482
|
}
|
|
@@ -9934,8 +10689,9 @@ function recordMountStatement(stmt, position, scan) {
|
|
|
9934
10689
|
scan.index.facts
|
|
9935
10690
|
);
|
|
9936
10691
|
const mounted = args[0] ?? (scan.composition.routerKeyword === void 0 ? void 0 : keywordArgs[scan.composition.routerKeyword]);
|
|
10692
|
+
const recorded = state.kind === "mounted" ? { ...state, written: { call: mountCall.call, file: scan.bound.file } } : state;
|
|
9937
10693
|
for (const target of mountedConstructions(mounted, position, scan)) {
|
|
9938
|
-
recordMount(scan.index, target,
|
|
10694
|
+
recordMount(scan.index, target, recorded);
|
|
9939
10695
|
}
|
|
9940
10696
|
}
|
|
9941
10697
|
function mountStateOf(includerConstructorName, includer, keywordArgs, objectPrefix, composition, site, facts) {
|
|
@@ -11047,6 +11803,8 @@ import { absentReading as absentReading2, walkDescendants as walkDescendants7 }
|
|
|
11047
11803
|
import { noteKeyRead as noteKeyRead6, noteLookup as noteLookup3 } from "@suss/resolution";
|
|
11048
11804
|
var EVERY_ROUTE = "wrapEvery ";
|
|
11049
11805
|
var OWN_ROUTES = "wrapOwn ";
|
|
11806
|
+
var MOUNTED = "wrapMounted ";
|
|
11807
|
+
var MOUNTED_SEPARATOR = "\0";
|
|
11050
11808
|
function describeRegistered(found) {
|
|
11051
11809
|
return (found ?? []).map(
|
|
11052
11810
|
({ reference }) => `${reference.file}:${reference.name}:${reference.onThrow === true}`
|
|
@@ -11084,8 +11842,15 @@ var PythonWrapperIndex = class {
|
|
|
11084
11842
|
/** By construction key: what a router or a blueprint registered. */
|
|
11085
11843
|
ownRoutes = /* @__PURE__ */ new Map();
|
|
11086
11844
|
unitsByKey = /* @__PURE__ */ new Map();
|
|
11845
|
+
/** By pack name: the app constructions its routes run under. */
|
|
11846
|
+
appCalls = /* @__PURE__ */ new Map();
|
|
11847
|
+
/** By wrapper reference: the parameters a dependency function declares, and its file. */
|
|
11848
|
+
dependencyParameterTable = /* @__PURE__ */ new Map();
|
|
11087
11849
|
unitsByFile = /* @__PURE__ */ new Map();
|
|
11088
|
-
/**
|
|
11850
|
+
/**
|
|
11851
|
+
* Told about every registration, a pack's form or a project decorator's
|
|
11852
|
+
* closure, so a cache can repeat the ones a file's discovery made.
|
|
11853
|
+
*/
|
|
11089
11854
|
onRegistered = null;
|
|
11090
11855
|
/**
|
|
11091
11856
|
* The same lookup `wrappersFor` noted under `id`, made again over this
|
|
@@ -11102,6 +11867,12 @@ var PythonWrapperIndex = class {
|
|
|
11102
11867
|
this.ownRoutes.get(id.slice(OWN_ROUTES.length))
|
|
11103
11868
|
);
|
|
11104
11869
|
}
|
|
11870
|
+
if (id.startsWith(MOUNTED)) {
|
|
11871
|
+
const [packName, position, key] = id.slice(MOUNTED.length).split(MOUNTED_SEPARATOR);
|
|
11872
|
+
const pack = this.options.packs.find((one) => one.name === packName);
|
|
11873
|
+
const pattern = pack?.discovery[Number(position)];
|
|
11874
|
+
return pack === void 0 || pattern === void 0 || key === void 0 ? describeRegistered([]) : describeRegistered(this.registeredAbove(pack, pattern, key));
|
|
11875
|
+
}
|
|
11105
11876
|
return null;
|
|
11106
11877
|
}
|
|
11107
11878
|
noted(kind, key, found) {
|
|
@@ -11143,14 +11914,65 @@ var PythonWrapperIndex = class {
|
|
|
11143
11914
|
inFile.push(unit);
|
|
11144
11915
|
this.unitsByFile.set(target.file.file, inFile);
|
|
11145
11916
|
}
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
...isThrowForm(declared.form) ? { onThrow: true } : {}
|
|
11151
|
-
},
|
|
11152
|
-
form: declared.form
|
|
11917
|
+
const reference = {
|
|
11918
|
+
file: target.file.displayPath,
|
|
11919
|
+
name: target.name,
|
|
11920
|
+
...isThrowForm(declared.form) ? { onThrow: true } : {}
|
|
11153
11921
|
};
|
|
11922
|
+
if (declared.form.type === "dependency") {
|
|
11923
|
+
this.dependencyParameterTable.set(referenceKey(reference), {
|
|
11924
|
+
file: target.file.file,
|
|
11925
|
+
names: parameterNamesOf(target.node),
|
|
11926
|
+
declaresSource: declaresSourcedParameter(
|
|
11927
|
+
target.node,
|
|
11928
|
+
Object.keys(declared.pattern.parameterSources ?? {})
|
|
11929
|
+
)
|
|
11930
|
+
});
|
|
11931
|
+
}
|
|
11932
|
+
return { reference, form: declared.form };
|
|
11933
|
+
}
|
|
11934
|
+
/**
|
|
11935
|
+
* The unit for the closure a project's decorator hands back, built once
|
|
11936
|
+
* however many routes the decorator is written on. Its name is what
|
|
11937
|
+
* calling the decorator writes, since the decorator may have a summary
|
|
11938
|
+
* of its own under its name.
|
|
11939
|
+
*/
|
|
11940
|
+
registeredClosure(target, closure) {
|
|
11941
|
+
this.onRegistered?.(target, closure);
|
|
11942
|
+
const span = spanOf(target.node);
|
|
11943
|
+
const key = `${target.file.file}:${span.start}-${span.end}`;
|
|
11944
|
+
if (!this.unitsByKey.has(key)) {
|
|
11945
|
+
const unit = closureUnit(target, closure, this.options);
|
|
11946
|
+
this.unitsByKey.set(key, unit);
|
|
11947
|
+
const inFile = this.unitsByFile.get(target.file.file) ?? [];
|
|
11948
|
+
inFile.push(unit);
|
|
11949
|
+
this.unitsByFile.set(target.file.file, inFile);
|
|
11950
|
+
}
|
|
11951
|
+
return { file: target.file.displayPath, name: target.name };
|
|
11952
|
+
}
|
|
11953
|
+
/**
|
|
11954
|
+
* The parameters the dependencies among these wrappers declare, and
|
|
11955
|
+
* whether one is declared through a parameter source such as `Query()`.
|
|
11956
|
+
* The library fills those from the request and validates them, the same
|
|
11957
|
+
* as parameters the route declares.
|
|
11958
|
+
*/
|
|
11959
|
+
dependencyParameters(references) {
|
|
11960
|
+
const names = /* @__PURE__ */ new Set();
|
|
11961
|
+
let declaresSource = false;
|
|
11962
|
+
for (const reference of references) {
|
|
11963
|
+
const found = this.dependencyParameterTable.get(referenceKey(reference));
|
|
11964
|
+
if (found === void 0) {
|
|
11965
|
+
continue;
|
|
11966
|
+
}
|
|
11967
|
+
if (this.options.facts !== void 0) {
|
|
11968
|
+
noteKeyRead6(this.options.facts, found.file);
|
|
11969
|
+
}
|
|
11970
|
+
for (const name of found.names) {
|
|
11971
|
+
names.add(name);
|
|
11972
|
+
}
|
|
11973
|
+
declaresSource ||= found.declaresSource;
|
|
11974
|
+
}
|
|
11975
|
+
return { names, declaresSource };
|
|
11154
11976
|
}
|
|
11155
11977
|
wrappersFor(query) {
|
|
11156
11978
|
const file = this.filesByPath.get(query.file);
|
|
@@ -11159,16 +11981,22 @@ var PythonWrapperIndex = class {
|
|
|
11159
11981
|
pattern: query.pattern,
|
|
11160
11982
|
form
|
|
11161
11983
|
}));
|
|
11162
|
-
if (file === void 0
|
|
11984
|
+
if (file === void 0) {
|
|
11163
11985
|
return [];
|
|
11164
11986
|
}
|
|
11987
|
+
const decorators = this.decoratorLayers(query, file);
|
|
11988
|
+
if (forms.length === 0) {
|
|
11989
|
+
return decorators;
|
|
11990
|
+
}
|
|
11991
|
+
const own = this.ownRoutesOf(query);
|
|
11165
11992
|
const found = [
|
|
11166
11993
|
...this.noted(
|
|
11167
11994
|
EVERY_ROUTE,
|
|
11168
11995
|
query.pack.name,
|
|
11169
11996
|
this.everyRoute.get(query.pack.name)
|
|
11170
11997
|
),
|
|
11171
|
-
...this.
|
|
11998
|
+
...own === null ? [] : this.mountedAbove(query, own.key),
|
|
11999
|
+
...own?.registered ?? []
|
|
11172
12000
|
];
|
|
11173
12001
|
for (const declared of forms) {
|
|
11174
12002
|
if (declared.form.type !== "dependency") {
|
|
@@ -11197,13 +12025,128 @@ var PythonWrapperIndex = class {
|
|
|
11197
12025
|
seen.add(key);
|
|
11198
12026
|
ordered.push(wrapper.reference);
|
|
11199
12027
|
}
|
|
11200
|
-
return
|
|
12028
|
+
return [
|
|
12029
|
+
...ordered.filter((one) => one.onThrow !== true),
|
|
12030
|
+
...decorators,
|
|
12031
|
+
...ordered.filter((one) => one.onThrow === true)
|
|
12032
|
+
];
|
|
12033
|
+
}
|
|
12034
|
+
/**
|
|
12035
|
+
* The decorators written on the route's function below the one that
|
|
12036
|
+
* registers it, outermost first. Each wraps the function the library
|
|
12037
|
+
* calls. None has a summary: a library's has no body in the run, and a
|
|
12038
|
+
* project's own is not composed into the route yet, so a project
|
|
12039
|
+
* decorator goes by what calling it writes, `require_admin(fn)`, which
|
|
12040
|
+
* no summary is named. The decorators the packs read, such as the
|
|
12041
|
+
* route's own and the namespace's `@ns.doc`, are left out.
|
|
12042
|
+
*/
|
|
12043
|
+
decoratorLayers(query, file) {
|
|
12044
|
+
const decorated = query.definitionNode.parent;
|
|
12045
|
+
if (decorated === null || decorated.type !== "decorated_definition") {
|
|
12046
|
+
return [];
|
|
12047
|
+
}
|
|
12048
|
+
const written = stripDecorators(decorated).decorators;
|
|
12049
|
+
const routeAt = written.findIndex(
|
|
12050
|
+
(decorator) => sameRange(rangeOf(decorator), query.classification.range)
|
|
12051
|
+
);
|
|
12052
|
+
return written.slice(routeAt + 1).flatMap((decorator) => this.decoratorLayer(decorator, query, file));
|
|
12053
|
+
}
|
|
12054
|
+
decoratorLayer(decorator, query, file) {
|
|
12055
|
+
const facts = this.options.facts;
|
|
12056
|
+
const direct = classifyDecorator(decorator, query.module, facts);
|
|
12057
|
+
const written = decoratorCallee(decorator);
|
|
12058
|
+
if (written === null || direct.module !== null && readByAPack(direct.module, this.options) || direct.objectName !== null && direct.objectName === query.classification.objectName || unwrapDecorator(decorator, facts) !== null) {
|
|
12059
|
+
return [];
|
|
12060
|
+
}
|
|
12061
|
+
const project = written.type === "identifier" ? this.functionCalled(file.file, written.text) : null;
|
|
12062
|
+
if (project !== null) {
|
|
12063
|
+
if (facts !== void 0) {
|
|
12064
|
+
noteKeyRead6(facts, project.file.file);
|
|
12065
|
+
}
|
|
12066
|
+
return [this.projectDecoratorLayer(project, query)];
|
|
12067
|
+
}
|
|
12068
|
+
return [{ file: direct.module ?? file.displayPath, name: written.text }];
|
|
12069
|
+
}
|
|
12070
|
+
/**
|
|
12071
|
+
* The layer a project's own decorator puts around the route. When it
|
|
12072
|
+
* hands back a closure written inside it that returns what calling the
|
|
12073
|
+
* function it was given returns, the closure is summarized and
|
|
12074
|
+
* composed into the route. Any other decorator, including one whose
|
|
12075
|
+
* closure keeps going after that call, goes by the same name with no
|
|
12076
|
+
* summary behind it.
|
|
12077
|
+
*/
|
|
12078
|
+
projectDecoratorLayer(decorator, query) {
|
|
12079
|
+
const continuation = parameterNamesOf(decorator.node)[0] ?? "";
|
|
12080
|
+
const name = `${decorator.name}(${continuation})`;
|
|
12081
|
+
const closure = closureReturnedBy(decorator.node);
|
|
12082
|
+
const handsOn = closure === null || continuation === "" ? [] : callsThrough(closure, continuation);
|
|
12083
|
+
if (closure === null || handsOn.length === 0 || !handsOn.every((statement) => returnsCallTo(statement, continuation))) {
|
|
12084
|
+
return { file: decorator.file.displayPath, name };
|
|
12085
|
+
}
|
|
12086
|
+
return this.registeredClosure(
|
|
12087
|
+
{ file: decorator.file, node: closure, name, exportPath: [] },
|
|
12088
|
+
{ pack: query.pack, pattern: query.pattern, continuation }
|
|
12089
|
+
);
|
|
12090
|
+
}
|
|
12091
|
+
/**
|
|
12092
|
+
* What the mounts above the route's router register on the way down:
|
|
12093
|
+
* the dependencies an `include_router` call lists, and those of each
|
|
12094
|
+
* router it is mounted onto, outermost first, the order they run in.
|
|
12095
|
+
*/
|
|
12096
|
+
mountedAbove(query, key) {
|
|
12097
|
+
const position = query.pack.discovery.indexOf(query.pattern);
|
|
12098
|
+
return [
|
|
12099
|
+
...this.noted(
|
|
12100
|
+
MOUNTED,
|
|
12101
|
+
[query.pack.name, position, key].join(MOUNTED_SEPARATOR),
|
|
12102
|
+
this.registeredAbove(query.pack, query.pattern, key)
|
|
12103
|
+
)
|
|
12104
|
+
];
|
|
12105
|
+
}
|
|
12106
|
+
registeredAbove(pack, pattern, key) {
|
|
12107
|
+
const hops = this.options.routers?.mountsAbove(pattern, key) ?? null;
|
|
12108
|
+
if (hops === null) {
|
|
12109
|
+
return [];
|
|
12110
|
+
}
|
|
12111
|
+
const forms = (pattern.wrappers ?? []).flatMap(
|
|
12112
|
+
(form) => form.type === "dependency" ? [{ pack, pattern, form }] : []
|
|
12113
|
+
);
|
|
12114
|
+
const found = [];
|
|
12115
|
+
for (const hop of [...hops].reverse()) {
|
|
12116
|
+
found.push(
|
|
12117
|
+
...hop.parentKey === null ? [] : this.ownRoutes.get(hop.parentKey) ?? []
|
|
12118
|
+
);
|
|
12119
|
+
const { keywordArgs } = readCallArguments(field(hop.call, "arguments"));
|
|
12120
|
+
for (const declared of forms) {
|
|
12121
|
+
const listed = keywordArgs[declared.form.keyword];
|
|
12122
|
+
const names = listed === void 0 ? [] : dependencyNamesIn(listed.node, declared.form);
|
|
12123
|
+
for (const name of names) {
|
|
12124
|
+
const target = this.functionCalled(hop.file, name);
|
|
12125
|
+
if (target !== null) {
|
|
12126
|
+
found.push(this.registered(target, declared));
|
|
12127
|
+
}
|
|
12128
|
+
}
|
|
12129
|
+
}
|
|
12130
|
+
}
|
|
12131
|
+
return found;
|
|
11201
12132
|
}
|
|
11202
12133
|
ownRoutesOf(query) {
|
|
12134
|
+
const match = this.ownRouterOf(query);
|
|
12135
|
+
return match === null ? null : {
|
|
12136
|
+
key: match.key,
|
|
12137
|
+
registered: this.noted(
|
|
12138
|
+
OWN_ROUTES,
|
|
12139
|
+
match.key,
|
|
12140
|
+
this.ownRoutes.get(match.key)
|
|
12141
|
+
)
|
|
12142
|
+
};
|
|
12143
|
+
}
|
|
12144
|
+
/** The construction call of the router a route is decorated on, when a registrar reads it. */
|
|
12145
|
+
ownRouterOf(query) {
|
|
11203
12146
|
const site = this.objectSiteOf(query);
|
|
11204
12147
|
const bound = site === null ? void 0 : this.filesByPath.get(site.file);
|
|
11205
12148
|
if (site === null || bound === void 0) {
|
|
11206
|
-
return
|
|
12149
|
+
return null;
|
|
11207
12150
|
}
|
|
11208
12151
|
if (this.options.facts !== void 0) {
|
|
11209
12152
|
noteKeyRead6(this.options.facts, site.file);
|
|
@@ -11217,12 +12160,46 @@ var PythonWrapperIndex = class {
|
|
|
11217
12160
|
{ pack: query.pack, pattern: query.pattern, form }
|
|
11218
12161
|
);
|
|
11219
12162
|
if (match !== null && match.registrar.covers === "ownRoutes") {
|
|
11220
|
-
return
|
|
11221
|
-
...this.noted(OWN_ROUTES, match.key, this.ownRoutes.get(match.key))
|
|
11222
|
-
];
|
|
12163
|
+
return match;
|
|
11223
12164
|
}
|
|
11224
12165
|
}
|
|
11225
|
-
return
|
|
12166
|
+
return null;
|
|
12167
|
+
}
|
|
12168
|
+
/** Records the app a pack's routes run under, for the keywords written on its construction. */
|
|
12169
|
+
recordApp(pack, call, file) {
|
|
12170
|
+
const calls = this.appCalls.get(pack) ?? [];
|
|
12171
|
+
if (!calls.some((one) => one.call === call)) {
|
|
12172
|
+
calls.push({ call, file });
|
|
12173
|
+
}
|
|
12174
|
+
this.appCalls.set(pack, calls);
|
|
12175
|
+
}
|
|
12176
|
+
/**
|
|
12177
|
+
* Every call that registers something for a route on the way to it:
|
|
12178
|
+
* the app's construction, the mount calls and the routers they mount
|
|
12179
|
+
* onto, and the route's own router. A caller reads a keyword off each.
|
|
12180
|
+
*/
|
|
12181
|
+
callsAbove(query) {
|
|
12182
|
+
const own = this.ownRouterOf(query);
|
|
12183
|
+
const hops = own === null ? [] : this.options.routers?.mountsAbove(query.pattern, own.key) ?? [];
|
|
12184
|
+
const parents = hops.flatMap((hop) => {
|
|
12185
|
+
const node = hop.parentKey === null ? null : nodeOfResolutionKey(hop.parentKey, this.options.facts);
|
|
12186
|
+
return node === null ? [] : [node];
|
|
12187
|
+
});
|
|
12188
|
+
const files = [
|
|
12189
|
+
...(this.appCalls.get(query.pack.name) ?? []).map((one) => one.file),
|
|
12190
|
+
...hops.map((hop) => hop.file)
|
|
12191
|
+
];
|
|
12192
|
+
if (this.options.facts !== void 0) {
|
|
12193
|
+
for (const file of files) {
|
|
12194
|
+
noteKeyRead6(this.options.facts, file);
|
|
12195
|
+
}
|
|
12196
|
+
}
|
|
12197
|
+
return [
|
|
12198
|
+
...(this.appCalls.get(query.pack.name) ?? []).map((one) => one.call),
|
|
12199
|
+
...hops.map((hop) => hop.call),
|
|
12200
|
+
...parents,
|
|
12201
|
+
...own === null ? [] : [own.call]
|
|
12202
|
+
];
|
|
11226
12203
|
}
|
|
11227
12204
|
/**
|
|
11228
12205
|
* Where the decorator's object was built: the route's own file, the file
|
|
@@ -11267,6 +12244,38 @@ var PythonWrapperIndex = class {
|
|
|
11267
12244
|
return this.unitsByFile.get(file) ?? [];
|
|
11268
12245
|
}
|
|
11269
12246
|
};
|
|
12247
|
+
function referenceKey(reference) {
|
|
12248
|
+
return `${reference.file}::${reference.name}`;
|
|
12249
|
+
}
|
|
12250
|
+
function readByAPack(module, options) {
|
|
12251
|
+
return options.packs.some(
|
|
12252
|
+
(pack) => pack.discovery.some((pattern) => pattern.importModule.includes(module))
|
|
12253
|
+
);
|
|
12254
|
+
}
|
|
12255
|
+
function decoratorCallee(decorator) {
|
|
12256
|
+
const written = decorator.namedChild(0);
|
|
12257
|
+
if (written === null) {
|
|
12258
|
+
return null;
|
|
12259
|
+
}
|
|
12260
|
+
return written.type === "call" ? field(written, "function") : written;
|
|
12261
|
+
}
|
|
12262
|
+
function sameRange(a, b) {
|
|
12263
|
+
return a.start === b.start && a.end === b.end;
|
|
12264
|
+
}
|
|
12265
|
+
function parameterNamesOf(definition) {
|
|
12266
|
+
return children(field(definition, "parameters")).flatMap((parameter) => {
|
|
12267
|
+
const named = parameterNameAndType(parameter);
|
|
12268
|
+
return named === null ? [] : [named.name];
|
|
12269
|
+
});
|
|
12270
|
+
}
|
|
12271
|
+
function declaresSourcedParameter(definition, sources) {
|
|
12272
|
+
return children(field(definition, "parameters")).some((parameter) => {
|
|
12273
|
+
const value = field(parameter, "value");
|
|
12274
|
+
const callee = value?.type === "call" ? field(value, "function") : null;
|
|
12275
|
+
const name = callee?.type === "attribute" ? field(callee, "attribute")?.text : callee?.text;
|
|
12276
|
+
return name !== void 0 && sources.includes(name);
|
|
12277
|
+
});
|
|
12278
|
+
}
|
|
11270
12279
|
function isThrowForm(form) {
|
|
11271
12280
|
return form.type === "decoratedWrapper" && form.throwParam !== void 0;
|
|
11272
12281
|
}
|
|
@@ -11313,8 +12322,8 @@ function registerFrom(file, declared, index) {
|
|
|
11313
12322
|
}
|
|
11314
12323
|
function registerConstructorDependencies(file, declared, form, index) {
|
|
11315
12324
|
const scope = file.module.moduleScope;
|
|
11316
|
-
for (const stmt of file.root
|
|
11317
|
-
const assignment2 = stmt?.type === "expression_statement" ? stmt.
|
|
12325
|
+
for (const stmt of children(file.root)) {
|
|
12326
|
+
const assignment2 = stmt?.type === "expression_statement" ? children(stmt).find((child) => child?.type === "assignment") : void 0;
|
|
11318
12327
|
const left = assignment2 === void 0 || assignment2 === null ? null : field(assignment2, "left");
|
|
11319
12328
|
if (left?.type !== "identifier") {
|
|
11320
12329
|
continue;
|
|
@@ -11329,6 +12338,9 @@ function registerConstructorDependencies(file, declared, form, index) {
|
|
|
11329
12338
|
if (match === null) {
|
|
11330
12339
|
continue;
|
|
11331
12340
|
}
|
|
12341
|
+
if (match.registrar.covers === "everyRoute") {
|
|
12342
|
+
index.recordApp(declared.pack.name, match.call, file.file);
|
|
12343
|
+
}
|
|
11332
12344
|
const { keywordArgs } = readCallArguments(field(match.call, "arguments"));
|
|
11333
12345
|
const listed = keywordArgs[form.keyword];
|
|
11334
12346
|
if (listed === void 0) {
|
|
@@ -11346,7 +12358,7 @@ function coverageOf(match, pack) {
|
|
|
11346
12358
|
return match.registrar.covers === "everyRoute" ? { kind: "everyRoute", pack: pack.name } : { kind: "ownRoutes", key: match.key };
|
|
11347
12359
|
}
|
|
11348
12360
|
function registerDecorated(file, declared, form, index) {
|
|
11349
|
-
walkDescendants7(file.root, file.module.moduleScope, {
|
|
12361
|
+
walkDescendants7(file.root, file.module.moduleScope, children, {
|
|
11350
12362
|
at: (node, scope) => {
|
|
11351
12363
|
if (node.type !== "decorated_definition") {
|
|
11352
12364
|
return;
|
|
@@ -11382,7 +12394,7 @@ function registerDecorated(file, declared, form, index) {
|
|
|
11382
12394
|
});
|
|
11383
12395
|
}
|
|
11384
12396
|
function dependencyNamesIn(node, form) {
|
|
11385
|
-
const calls = node.type === "list" ? node
|
|
12397
|
+
const calls = node.type === "list" ? children(node) : [node];
|
|
11386
12398
|
const names = [];
|
|
11387
12399
|
for (const call of calls) {
|
|
11388
12400
|
const name = call === null ? null : dependencyNameOf(call, form);
|
|
@@ -11401,7 +12413,7 @@ function dependencyNameOf(node, form) {
|
|
|
11401
12413
|
if (calleeName3 === null || !form.callees.includes(calleeName3)) {
|
|
11402
12414
|
return null;
|
|
11403
12415
|
}
|
|
11404
|
-
const first = field(node, "arguments")?.
|
|
12416
|
+
const first = field(node, "arguments")?.namedChild(0);
|
|
11405
12417
|
return first?.type === "identifier" ? first.text : null;
|
|
11406
12418
|
}
|
|
11407
12419
|
function decoratorDependencies(classification, form) {
|
|
@@ -11419,7 +12431,7 @@ function parameterDependencies(definitionNode, form) {
|
|
|
11419
12431
|
if (direct !== null) {
|
|
11420
12432
|
return direct;
|
|
11421
12433
|
}
|
|
11422
|
-
for (const child of node
|
|
12434
|
+
for (const child of children(node)) {
|
|
11423
12435
|
const found = findIn(child, depth + 1);
|
|
11424
12436
|
if (found !== null) {
|
|
11425
12437
|
return found;
|
|
@@ -11427,10 +12439,7 @@ function parameterDependencies(definitionNode, form) {
|
|
|
11427
12439
|
}
|
|
11428
12440
|
return null;
|
|
11429
12441
|
};
|
|
11430
|
-
for (const param of field(definitionNode, "parameters")
|
|
11431
|
-
if (param === null) {
|
|
11432
|
-
continue;
|
|
11433
|
-
}
|
|
12442
|
+
for (const param of children(field(definitionNode, "parameters"))) {
|
|
11434
12443
|
const inDefault = field(param, "value");
|
|
11435
12444
|
const found = inDefault === null ? findIn(field(param, "type"), 0) : dependencyNameOf(inDefault, form);
|
|
11436
12445
|
if (found !== null) {
|
|
@@ -11440,15 +12449,42 @@ function parameterDependencies(definitionNode, form) {
|
|
|
11440
12449
|
return names;
|
|
11441
12450
|
}
|
|
11442
12451
|
function wrapperUnit(target, declared, options) {
|
|
12452
|
+
return unitAround(
|
|
12453
|
+
target,
|
|
12454
|
+
declared.pattern,
|
|
12455
|
+
{
|
|
12456
|
+
continuations: continuationStatements(target.node, declared.form),
|
|
12457
|
+
continuationName: null,
|
|
12458
|
+
form: declared.form,
|
|
12459
|
+
nameKind: "binding"
|
|
12460
|
+
},
|
|
12461
|
+
options
|
|
12462
|
+
);
|
|
12463
|
+
}
|
|
12464
|
+
function closureUnit(target, closure, options) {
|
|
12465
|
+
return unitAround(
|
|
12466
|
+
target,
|
|
12467
|
+
closure.pattern,
|
|
12468
|
+
{
|
|
12469
|
+
continuations: callsThrough(target.node, closure.continuation),
|
|
12470
|
+
continuationName: closure.continuation,
|
|
12471
|
+
form: null,
|
|
12472
|
+
nameKind: "label"
|
|
12473
|
+
},
|
|
12474
|
+
options
|
|
12475
|
+
);
|
|
12476
|
+
}
|
|
12477
|
+
function unitAround(target, pattern, reading, options) {
|
|
11443
12478
|
const { file, node, name, exportPath } = target;
|
|
11444
12479
|
const body = field(node, "body");
|
|
11445
12480
|
const range = rangeOf(node);
|
|
11446
12481
|
const raised = raisedResponses(body, {
|
|
11447
|
-
calls:
|
|
12482
|
+
calls: pattern.responseStatusCalls ?? [],
|
|
11448
12483
|
module: file.module,
|
|
11449
|
-
facts: options.facts
|
|
12484
|
+
facts: options.facts,
|
|
12485
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
11450
12486
|
});
|
|
11451
|
-
const continuations =
|
|
12487
|
+
const continuations = reading.continuations;
|
|
11452
12488
|
const terminals = bodyTerminals(body, raised, continuations);
|
|
11453
12489
|
const effects = invocationEffects(node, options.facts);
|
|
11454
12490
|
const extra = recognizedBodyEffects(
|
|
@@ -11457,7 +12493,7 @@ function wrapperUnit(target, declared, options) {
|
|
|
11457
12493
|
options.storageFor(file),
|
|
11458
12494
|
options.facts
|
|
11459
12495
|
);
|
|
11460
|
-
const delegate = (at) => ({
|
|
12496
|
+
const delegate = (at, to = null) => ({
|
|
11461
12497
|
terminal: {
|
|
11462
12498
|
kind: "delegate",
|
|
11463
12499
|
statusCode: null,
|
|
@@ -11466,18 +12502,18 @@ function wrapperUnit(target, declared, options) {
|
|
|
11466
12502
|
message: null,
|
|
11467
12503
|
component: null,
|
|
11468
12504
|
renderTree: null,
|
|
11469
|
-
delegateTarget:
|
|
12505
|
+
delegateTarget: to,
|
|
11470
12506
|
emitEvent: null,
|
|
11471
12507
|
location: rangeOf(at)
|
|
11472
12508
|
},
|
|
11473
12509
|
location: rangeOf(at)
|
|
11474
12510
|
});
|
|
11475
12511
|
const respond = (statement) => returnBranch(statement, {
|
|
11476
|
-
pattern
|
|
12512
|
+
pattern,
|
|
11477
12513
|
responseShape: { reading: absentReading2 },
|
|
11478
12514
|
declaredStatus: {
|
|
11479
12515
|
reading: absentReading2,
|
|
11480
|
-
...
|
|
12516
|
+
...pattern.defaultStatusCode !== void 0 ? { libraryDefault: pattern.defaultStatusCode } : {}
|
|
11481
12517
|
},
|
|
11482
12518
|
module: file.module,
|
|
11483
12519
|
facts: options.facts
|
|
@@ -11489,7 +12525,10 @@ function wrapperUnit(target, declared, options) {
|
|
|
11489
12525
|
location: rangeOf(terminal.statement)
|
|
11490
12526
|
};
|
|
11491
12527
|
}
|
|
11492
|
-
if (terminal.type === "continuation"
|
|
12528
|
+
if (terminal.type === "continuation") {
|
|
12529
|
+
return delegate(terminal.statement, reading.continuationName);
|
|
12530
|
+
}
|
|
12531
|
+
if (reading.form !== null && returnHandsOn(terminal.statement, reading.form)) {
|
|
11493
12532
|
return delegate(terminal.statement);
|
|
11494
12533
|
}
|
|
11495
12534
|
return respond(terminal.statement);
|
|
@@ -11506,7 +12545,7 @@ function wrapperUnit(target, declared, options) {
|
|
|
11506
12545
|
return {
|
|
11507
12546
|
identity: {
|
|
11508
12547
|
name,
|
|
11509
|
-
nameKind:
|
|
12548
|
+
nameKind: reading.nameKind,
|
|
11510
12549
|
kind: "middleware",
|
|
11511
12550
|
file: file.displayPath,
|
|
11512
12551
|
range,
|
|
@@ -11530,7 +12569,7 @@ function returnHandsOn(statement, form) {
|
|
|
11530
12569
|
return false;
|
|
11531
12570
|
}
|
|
11532
12571
|
if (form.returnedValueResponds === true) {
|
|
11533
|
-
const returned = statement.
|
|
12572
|
+
const returned = statement.namedChild(0);
|
|
11534
12573
|
return returned === void 0 || returned === null || returned.type === "none";
|
|
11535
12574
|
}
|
|
11536
12575
|
return true;
|
|
@@ -11539,28 +12578,48 @@ function continuationStatements(node, form) {
|
|
|
11539
12578
|
if (form.type !== "decoratedWrapper" || form.continuationParam === void 0) {
|
|
11540
12579
|
return [];
|
|
11541
12580
|
}
|
|
11542
|
-
const params = (field(node, "parameters")
|
|
11543
|
-
(param2) => param2 !== null
|
|
11544
|
-
);
|
|
12581
|
+
const params = children(field(node, "parameters"));
|
|
11545
12582
|
const param = params[form.continuationParam];
|
|
11546
12583
|
const continuation = param === void 0 ? null : field(param, "name")?.text ?? (param.type === "identifier" ? param.text : null);
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
12584
|
+
return continuation === null ? [] : callsThrough(node, continuation);
|
|
12585
|
+
}
|
|
12586
|
+
function callsThrough(node, callee) {
|
|
11550
12587
|
const body = field(node, "body");
|
|
11551
12588
|
if (body === null) {
|
|
11552
12589
|
return [];
|
|
11553
12590
|
}
|
|
11554
12591
|
const found = [];
|
|
11555
12592
|
for (const call of bodyCalls(body)) {
|
|
11556
|
-
const
|
|
11557
|
-
const statement =
|
|
12593
|
+
const called = field(call, "function");
|
|
12594
|
+
const statement = called?.type === "identifier" && called.text === callee ? enclosingStatement(call, body) : null;
|
|
11558
12595
|
if (statement !== null) {
|
|
11559
12596
|
found.push(statement);
|
|
11560
12597
|
}
|
|
11561
12598
|
}
|
|
11562
12599
|
return found;
|
|
11563
12600
|
}
|
|
12601
|
+
function returnsCallTo(statement, callee) {
|
|
12602
|
+
if (statement.type !== "return_statement") {
|
|
12603
|
+
return false;
|
|
12604
|
+
}
|
|
12605
|
+
const value = statement.namedChild(0);
|
|
12606
|
+
const call = value?.type === "await" ? value.namedChild(0) : value;
|
|
12607
|
+
return call?.type === "call" && field(call, "function")?.text === callee;
|
|
12608
|
+
}
|
|
12609
|
+
function closureReturnedBy(decorator) {
|
|
12610
|
+
const statements = children(field(decorator, "body"));
|
|
12611
|
+
const returned = statements.find((statement) => statement.type === "return_statement")?.namedChild(0);
|
|
12612
|
+
if (returned?.type !== "identifier") {
|
|
12613
|
+
return null;
|
|
12614
|
+
}
|
|
12615
|
+
for (const statement of statements) {
|
|
12616
|
+
const { definition } = stripDecorators(statement);
|
|
12617
|
+
if (definition.type === "function_definition" && field(definition, "name")?.text === returned.text) {
|
|
12618
|
+
return definition;
|
|
12619
|
+
}
|
|
12620
|
+
}
|
|
12621
|
+
return null;
|
|
12622
|
+
}
|
|
11564
12623
|
|
|
11565
12624
|
// src/project.ts
|
|
11566
12625
|
function keptPythonParses() {
|
|
@@ -11655,7 +12714,7 @@ async function extractPythonProject(options) {
|
|
|
11655
12714
|
const { roots, unreadManifests } = rootsOfRun(options);
|
|
11656
12715
|
const timer = options.onTiming !== void 0 ? createTimer() : noopTimer();
|
|
11657
12716
|
const cacheDir = adapterStamp.declineWhenRunFromSource(
|
|
11658
|
-
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ?
|
|
12717
|
+
options.cacheDir === null ? null : options.cacheDir ?? (options.projectRoot !== void 0 ? extractionCacheDirFor(options.projectRoot) : null)
|
|
11659
12718
|
);
|
|
11660
12719
|
const layer = createCacheLayer(cacheDir);
|
|
11661
12720
|
const packsDigest = `${adapterStamp.packsDigest(
|
|
@@ -11678,11 +12737,14 @@ async function extractPythonProject(options) {
|
|
|
11678
12737
|
"cache.lookup",
|
|
11679
12738
|
() => layer.lookup(input)
|
|
11680
12739
|
);
|
|
12740
|
+
const composed = (stored) => composeWrappers(stored, {
|
|
12741
|
+
gapHandling: options.gapHandling ?? "permissive"
|
|
12742
|
+
});
|
|
11681
12743
|
if (lookup.kind === "hit") {
|
|
11682
12744
|
options.onCacheDiagnostic?.(lookup.diagnostic);
|
|
11683
12745
|
options.onTiming?.(timer.report());
|
|
11684
12746
|
return {
|
|
11685
|
-
summaries: lookup.summaries,
|
|
12747
|
+
summaries: composed(lookup.summaries),
|
|
11686
12748
|
facts: new Database2(),
|
|
11687
12749
|
roots,
|
|
11688
12750
|
unreadManifests
|
|
@@ -11697,7 +12759,7 @@ async function extractPythonProject(options) {
|
|
|
11697
12759
|
options.onCacheDiagnostic?.({ kind: "hit" });
|
|
11698
12760
|
options.onTiming?.(timer.report());
|
|
11699
12761
|
return {
|
|
11700
|
-
summaries: plan.allSummaries(),
|
|
12762
|
+
summaries: composed(plan.allSummaries()),
|
|
11701
12763
|
facts: new Database2(),
|
|
11702
12764
|
roots,
|
|
11703
12765
|
unreadManifests
|
|
@@ -11842,7 +12904,8 @@ async function runPython(options, roots, cache, previous) {
|
|
|
11842
12904
|
roots,
|
|
11843
12905
|
facts: needsValues ? db : void 0,
|
|
11844
12906
|
definitions,
|
|
11845
|
-
storageFor
|
|
12907
|
+
storageFor,
|
|
12908
|
+
routers: plainRouterIndex
|
|
11846
12909
|
})
|
|
11847
12910
|
);
|
|
11848
12911
|
const importedDefinition2 = importedDefinitionLookup(db, bound);
|
|
@@ -11878,15 +12941,10 @@ async function runPython(options, roots, cache, previous) {
|
|
|
11878
12941
|
});
|
|
11879
12942
|
let registering = null;
|
|
11880
12943
|
if (ledger !== null) {
|
|
11881
|
-
wrapperIndex.onRegistered = (target,
|
|
11882
|
-
const
|
|
11883
|
-
if (registering !== null &&
|
|
11884
|
-
registering.push(
|
|
11885
|
-
key: nodeId(target.file.file, target.node),
|
|
11886
|
-
name: target.name,
|
|
11887
|
-
exportPath: target.exportPath,
|
|
11888
|
-
form
|
|
11889
|
-
});
|
|
12944
|
+
wrapperIndex.onRegistered = (target, how) => {
|
|
12945
|
+
const stored = storedRegistration(target, how, positions);
|
|
12946
|
+
if (registering !== null && stored !== null) {
|
|
12947
|
+
registering.push(stored);
|
|
11890
12948
|
}
|
|
11891
12949
|
};
|
|
11892
12950
|
}
|
|
@@ -11899,12 +12957,11 @@ async function runPython(options, roots, cache, previous) {
|
|
|
11899
12957
|
if (record !== void 0) {
|
|
11900
12958
|
discoveries.set(file, record);
|
|
11901
12959
|
for (const registration of record.registrations) {
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
}
|
|
11907
|
-
wrapperIndex.registered(target, declared);
|
|
12960
|
+
registerAgain(registration, {
|
|
12961
|
+
positions,
|
|
12962
|
+
wrapperIndex,
|
|
12963
|
+
target: storedFunction(registration, definitions, filesByPath)
|
|
12964
|
+
});
|
|
11908
12965
|
}
|
|
11909
12966
|
continue;
|
|
11910
12967
|
}
|
|
@@ -12073,6 +13130,7 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12073
13130
|
}
|
|
12074
13131
|
placeCalls2(summary, reached.targetsByKey.get(key));
|
|
12075
13132
|
placeArgTargets2(summary, reached.argTargetsByKey.get(key));
|
|
13133
|
+
placePossibleCalls2(summary, reached.possibleTargetsByKey.get(key));
|
|
12076
13134
|
placeCalleeParameters2(summary, reached.parameterCallsByKey.get(key));
|
|
12077
13135
|
};
|
|
12078
13136
|
for (const [key, owners] of summariesBySeed) {
|
|
@@ -12162,16 +13220,20 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12162
13220
|
markExitCodeFunctions(summaries, exits, db, options.workspaceRoot);
|
|
12163
13221
|
return composeWrappers(summaries, { gapHandling });
|
|
12164
13222
|
});
|
|
13223
|
+
const walkedFiles = new Map(
|
|
13224
|
+
bound.map(({ file, displayPath }) => [displayPath, file])
|
|
13225
|
+
);
|
|
12165
13226
|
await timer.timeAsync("cache.write", async () => {
|
|
12166
|
-
if (cacheDir === null ||
|
|
13227
|
+
if (cacheDir === null || summaries.length === 0) {
|
|
12167
13228
|
return;
|
|
12168
13229
|
}
|
|
12169
13230
|
try {
|
|
12170
13231
|
await cache.layer.write(
|
|
12171
13232
|
cache.input,
|
|
12172
|
-
|
|
13233
|
+
summaries,
|
|
12173
13234
|
log === null || ledger === null || overBudget ? void 0 : pythonAttribution({
|
|
12174
|
-
|
|
13235
|
+
summaries,
|
|
13236
|
+
walkedFileOf: (locationFile) => walkedFiles.get(locationFile),
|
|
12175
13237
|
discoveries,
|
|
12176
13238
|
charges,
|
|
12177
13239
|
unitDrafts,
|
|
@@ -12226,6 +13288,39 @@ async function runPython(options, roots, cache, previous) {
|
|
|
12226
13288
|
options.onTiming?.(timer.report());
|
|
12227
13289
|
return { summaries: composed, facts: db };
|
|
12228
13290
|
}
|
|
13291
|
+
function storedRegistration(target, how, positions) {
|
|
13292
|
+
const at = {
|
|
13293
|
+
key: nodeId(target.file.file, target.node),
|
|
13294
|
+
name: target.name,
|
|
13295
|
+
exportPath: target.exportPath
|
|
13296
|
+
};
|
|
13297
|
+
if ("continuation" in how) {
|
|
13298
|
+
const pattern = positions.idOf(how.pattern);
|
|
13299
|
+
return pattern === void 0 ? null : { ...at, pattern, continuation: how.continuation };
|
|
13300
|
+
}
|
|
13301
|
+
const form = positions.positionOf(how);
|
|
13302
|
+
return form === void 0 ? null : { ...at, form };
|
|
13303
|
+
}
|
|
13304
|
+
function registerAgain(registration, context) {
|
|
13305
|
+
const { positions, wrapperIndex, target } = context;
|
|
13306
|
+
const how = howRegistered(registration, positions);
|
|
13307
|
+
if (target === null || how === null) {
|
|
13308
|
+
throw new ReplayFailed(registration.key);
|
|
13309
|
+
}
|
|
13310
|
+
if ("continuation" in how) {
|
|
13311
|
+
wrapperIndex.registeredClosure(target, how);
|
|
13312
|
+
return;
|
|
13313
|
+
}
|
|
13314
|
+
wrapperIndex.registered(target, how);
|
|
13315
|
+
}
|
|
13316
|
+
function howRegistered(registration, positions) {
|
|
13317
|
+
if (!("continuation" in registration)) {
|
|
13318
|
+
return positions.formAt(registration.form) ?? null;
|
|
13319
|
+
}
|
|
13320
|
+
const pack = positions.packOf(registration.pattern);
|
|
13321
|
+
const pattern = positions.patternOf(registration.pattern);
|
|
13322
|
+
return pack === void 0 || pattern === void 0 ? null : { pack, pattern, continuation: registration.continuation };
|
|
13323
|
+
}
|
|
12229
13324
|
function pythonAttribution(args) {
|
|
12230
13325
|
const walkedByFile = walkRecordsByFile({
|
|
12231
13326
|
scans: args.reached.scans,
|
|
@@ -12254,7 +13349,10 @@ function pythonAttribution(args) {
|
|
|
12254
13349
|
}
|
|
12255
13350
|
};
|
|
12256
13351
|
});
|
|
12257
|
-
return {
|
|
13352
|
+
return {
|
|
13353
|
+
roots,
|
|
13354
|
+
owners: ownersWhereWritten(args.summaries, args.walkedFileOf)
|
|
13355
|
+
};
|
|
12258
13356
|
}
|
|
12259
13357
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
12260
13358
|
"__pycache__",
|
|
@@ -12285,7 +13383,7 @@ function indexDefinitions(into, file, node) {
|
|
|
12285
13383
|
if (isFunction(node)) {
|
|
12286
13384
|
into.set(nodeId(file, node), node);
|
|
12287
13385
|
}
|
|
12288
|
-
for (const child of node
|
|
13386
|
+
for (const child of children(node)) {
|
|
12289
13387
|
if (child !== null) {
|
|
12290
13388
|
indexDefinitions(into, file, child);
|
|
12291
13389
|
}
|
|
@@ -12551,7 +13649,7 @@ function importSitesIn(root) {
|
|
|
12551
13649
|
found.push({ module: entry.module, name: entry.name, line });
|
|
12552
13650
|
}
|
|
12553
13651
|
}
|
|
12554
|
-
for (const child of node
|
|
13652
|
+
for (const child of children(node)) {
|
|
12555
13653
|
if (child !== null) {
|
|
12556
13654
|
visit(child);
|
|
12557
13655
|
}
|