@suss/adapter-python 0.34.0 → 0.34.1
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 +1123 -512
- package/dist/index.d.cts +83 -3
- package/dist/index.d.ts +83 -3
- package/dist/index.js +1030 -411
- 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]);
|
|
@@ -1430,10 +1529,10 @@ function emitExpressionFacts(emitter, node) {
|
|
|
1430
1529
|
});
|
|
1431
1530
|
}
|
|
1432
1531
|
function yieldedValue(node) {
|
|
1433
|
-
if (node.
|
|
1532
|
+
if (allChildren(node).some((child) => child.type === "from")) {
|
|
1434
1533
|
return null;
|
|
1435
1534
|
}
|
|
1436
|
-
return node.
|
|
1535
|
+
return children(node).find((child) => child?.type !== "comment") ?? null;
|
|
1437
1536
|
}
|
|
1438
1537
|
function emitFunctionFacts(emitter, fn, classKey) {
|
|
1439
1538
|
const funcKey = nodeId(emitter.filePath, fn);
|
|
@@ -1505,7 +1604,7 @@ function emitFunctionFacts(emitter, fn, classKey) {
|
|
|
1505
1604
|
const stores = /* @__PURE__ */ new Map();
|
|
1506
1605
|
const visit = (child, type) => {
|
|
1507
1606
|
if (type === "return_statement") {
|
|
1508
|
-
const returned = child.
|
|
1607
|
+
const returned = child.namedChild(0);
|
|
1509
1608
|
if (returned != null) {
|
|
1510
1609
|
add(inside, "returnsValue", funcKey, valueKey(inside, returned));
|
|
1511
1610
|
statesReturn = true;
|
|
@@ -2543,9 +2642,7 @@ function stringExpression(node) {
|
|
|
2543
2642
|
}
|
|
2544
2643
|
function comparisonExpression(node) {
|
|
2545
2644
|
const operands = children(node);
|
|
2546
|
-
const operators = node.
|
|
2547
|
-
(child) => child !== null && !child.isNamed
|
|
2548
|
-
);
|
|
2645
|
+
const operators = allChildren(node).filter((child) => !child.isNamed);
|
|
2549
2646
|
const operator = operators[0];
|
|
2550
2647
|
if (operands.length !== 2 || operators.length !== 1 || operator === void 0) {
|
|
2551
2648
|
return { kind: "opaque" };
|
|
@@ -2639,6 +2736,7 @@ var STATEMENT_TYPES = {
|
|
|
2639
2736
|
kind: "return",
|
|
2640
2737
|
value: children(node)[0] ?? null
|
|
2641
2738
|
}),
|
|
2739
|
+
raise_statement: (node) => caughtInSameFunction(node) ? OPAQUE : { kind: "throw" },
|
|
2642
2740
|
try_statement: (node) => ({
|
|
2643
2741
|
kind: "block",
|
|
2644
2742
|
body: [
|
|
@@ -2727,6 +2825,19 @@ function blockStatements(block) {
|
|
|
2727
2825
|
function isRoot(node) {
|
|
2728
2826
|
return ROOT_TYPES.has(node.type);
|
|
2729
2827
|
}
|
|
2828
|
+
var EXCEPT_CLAUSE_TYPES = /* @__PURE__ */ new Set(["except_clause", "except_group_clause"]);
|
|
2829
|
+
function caughtInSameFunction(node) {
|
|
2830
|
+
let child = node;
|
|
2831
|
+
let parent = node.parent;
|
|
2832
|
+
while (parent !== null && !isRoot(parent)) {
|
|
2833
|
+
if (parent.type === "try_statement" && field(parent, "body")?.id === child.id && children(parent).some((clause) => EXCEPT_CLAUSE_TYPES.has(clause.type))) {
|
|
2834
|
+
return true;
|
|
2835
|
+
}
|
|
2836
|
+
child = parent;
|
|
2837
|
+
parent = parent.parent;
|
|
2838
|
+
}
|
|
2839
|
+
return false;
|
|
2840
|
+
}
|
|
2730
2841
|
function isPathStatement(node, parent) {
|
|
2731
2842
|
return parent.type === "module" || parent.type === "block" || node.type === "elif_clause";
|
|
2732
2843
|
}
|
|
@@ -3139,6 +3250,10 @@ function writtenNodeOf(node, db) {
|
|
|
3139
3250
|
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
3140
3251
|
return bound?.context.writtenTo(node) ?? null;
|
|
3141
3252
|
}
|
|
3253
|
+
function calledDefinition(call, db) {
|
|
3254
|
+
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
3255
|
+
return bound?.context.callable(call) ?? null;
|
|
3256
|
+
}
|
|
3142
3257
|
function resolutionKeyOf(node, db) {
|
|
3143
3258
|
const bound = db === void 0 ? void 0 : projects.get(db);
|
|
3144
3259
|
return bound?.keyOf(node) ?? null;
|
|
@@ -3361,7 +3476,7 @@ function argShapeOf(node) {
|
|
|
3361
3476
|
if (node.type === "list") {
|
|
3362
3477
|
return {
|
|
3363
3478
|
kind: "list",
|
|
3364
|
-
items: node
|
|
3479
|
+
items: children(node).map(readArg)
|
|
3365
3480
|
};
|
|
3366
3481
|
}
|
|
3367
3482
|
return { kind: "other" };
|
|
@@ -3372,10 +3487,7 @@ function readCallArguments(argumentList) {
|
|
|
3372
3487
|
if (argumentList === null) {
|
|
3373
3488
|
return { args, keywordArgs };
|
|
3374
3489
|
}
|
|
3375
|
-
for (const child of argumentList
|
|
3376
|
-
if (child === null) {
|
|
3377
|
-
continue;
|
|
3378
|
-
}
|
|
3490
|
+
for (const child of children(argumentList)) {
|
|
3379
3491
|
if (child.type === "keyword_argument") {
|
|
3380
3492
|
const nameNode = field(child, "name");
|
|
3381
3493
|
const valueNode = field(child, "value");
|
|
@@ -3501,10 +3613,10 @@ function unwrapDecorator(decoratorNode, facts) {
|
|
|
3501
3613
|
}
|
|
3502
3614
|
function passesParametersThrough(def, inner) {
|
|
3503
3615
|
const params = field(def, "parameters");
|
|
3504
|
-
const names = (params
|
|
3616
|
+
const names = children(params).filter((child) => child.type === "identifier").map((child) => child.text);
|
|
3505
3617
|
const argumentList = field(inner, "arguments");
|
|
3506
|
-
const positional = (argumentList
|
|
3507
|
-
(child) => child
|
|
3618
|
+
const positional = children(argumentList).filter(
|
|
3619
|
+
(child) => child.type !== "keyword_argument"
|
|
3508
3620
|
);
|
|
3509
3621
|
return positional.length === names.length && positional.every(
|
|
3510
3622
|
(argument, at) => argument.type === "identifier" && argument.text === names[at]
|
|
@@ -3527,8 +3639,14 @@ import {
|
|
|
3527
3639
|
import { constantOf as constantOf5, literalOf as literalOf6, pathOf as pathOf2 } from "@suss/values";
|
|
3528
3640
|
|
|
3529
3641
|
// src/clientCalls.ts
|
|
3530
|
-
import {
|
|
3531
|
-
|
|
3642
|
+
import {
|
|
3643
|
+
hasNameHole,
|
|
3644
|
+
restBinding,
|
|
3645
|
+
statusMembersOf,
|
|
3646
|
+
testsStatus
|
|
3647
|
+
} from "@suss/behavioral-ir";
|
|
3648
|
+
import { redirectDeliveryWhenSet } from "@suss/extractor";
|
|
3649
|
+
import { hostOf, pathOf, scalarOf } from "@suss/values";
|
|
3532
3650
|
|
|
3533
3651
|
// src/paths/bodyBranches.ts
|
|
3534
3652
|
import { enumerateOrDegrade as enumerateOrDegrade2, guardsHoldOn } from "@suss/extractor";
|
|
@@ -3549,7 +3667,7 @@ var COMPARISONS = {
|
|
|
3549
3667
|
"<=": "lte"
|
|
3550
3668
|
};
|
|
3551
3669
|
function operatorText(node) {
|
|
3552
|
-
return node.
|
|
3670
|
+
return allChildren(node).filter((child) => !child.isNamed).map((child) => child.text).join(" ");
|
|
3553
3671
|
}
|
|
3554
3672
|
function valueRefOf(node, facts, inputs) {
|
|
3555
3673
|
const value = evaluatedValue(node, facts);
|
|
@@ -3601,7 +3719,7 @@ function nullCheckOf(subject, negated2, facts, inputs) {
|
|
|
3601
3719
|
};
|
|
3602
3720
|
}
|
|
3603
3721
|
function comparisonOf(node, facts, inputs) {
|
|
3604
|
-
const [left, right] = node.
|
|
3722
|
+
const [left, right] = children(node).filter(
|
|
3605
3723
|
(child) => child !== null
|
|
3606
3724
|
);
|
|
3607
3725
|
if (left === void 0 || right === void 0) {
|
|
@@ -3630,14 +3748,14 @@ function comparisonOf(node, facts, inputs) {
|
|
|
3630
3748
|
}
|
|
3631
3749
|
function predicateOf(node, facts, inputs) {
|
|
3632
3750
|
if (node.type === "parenthesized_expression") {
|
|
3633
|
-
const inner = node.
|
|
3751
|
+
const inner = node.namedChild(0);
|
|
3634
3752
|
return inner == null ? opaqueOf(node) : predicateOf(inner, facts, inputs);
|
|
3635
3753
|
}
|
|
3636
3754
|
if (node.type === "comparison_operator") {
|
|
3637
3755
|
return comparisonOf(node, facts, inputs);
|
|
3638
3756
|
}
|
|
3639
3757
|
if (node.type === "not_operator") {
|
|
3640
|
-
const operand2 = field(node, "argument") ?? node.
|
|
3758
|
+
const operand2 = field(node, "argument") ?? node.namedChild(0);
|
|
3641
3759
|
return operand2 == null ? opaqueOf(node) : { type: "negation", operand: predicateOf(operand2, facts, inputs) };
|
|
3642
3760
|
}
|
|
3643
3761
|
if (node.type === "identifier" || node.type === "attribute" || inputs?.has(node.id) === true) {
|
|
@@ -3652,11 +3770,11 @@ function predicateOf(node, facts, inputs) {
|
|
|
3652
3770
|
var SUBJECT_TYPES = /* @__PURE__ */ new Set(["identifier", "attribute", "subscript"]);
|
|
3653
3771
|
function operandsOf(node) {
|
|
3654
3772
|
if (node.type === "parenthesized_expression" || node.type === "not_operator") {
|
|
3655
|
-
const inner = field(node, "argument") ?? node.
|
|
3773
|
+
const inner = field(node, "argument") ?? node.namedChild(0);
|
|
3656
3774
|
return inner == null ? [] : operandsOf(inner);
|
|
3657
3775
|
}
|
|
3658
3776
|
if (node.type === "comparison_operator") {
|
|
3659
|
-
return node.
|
|
3777
|
+
return children(node).filter(
|
|
3660
3778
|
(child) => child !== null && SUBJECT_TYPES.has(child.type)
|
|
3661
3779
|
);
|
|
3662
3780
|
}
|
|
@@ -3682,7 +3800,7 @@ var NESTED_FUNCTION_TYPES = /* @__PURE__ */ new Set(["function_definition", "lam
|
|
|
3682
3800
|
function exitKindOf(node, thrown) {
|
|
3683
3801
|
let sawReturn = false;
|
|
3684
3802
|
const raises = (current) => {
|
|
3685
|
-
for (const child of current
|
|
3803
|
+
for (const child of children(current)) {
|
|
3686
3804
|
if (child === null || NESTED_FUNCTION_TYPES.has(child.type)) {
|
|
3687
3805
|
continue;
|
|
3688
3806
|
}
|
|
@@ -3710,12 +3828,10 @@ function blockStatements2(block) {
|
|
|
3710
3828
|
if (block === null) {
|
|
3711
3829
|
return [];
|
|
3712
3830
|
}
|
|
3713
|
-
return block
|
|
3831
|
+
return children(block);
|
|
3714
3832
|
}
|
|
3715
3833
|
function childBlock(node) {
|
|
3716
|
-
return node.
|
|
3717
|
-
(child) => child !== null && child.type === "block"
|
|
3718
|
-
) ?? null;
|
|
3834
|
+
return children(node).find((child) => child.type === "block") ?? null;
|
|
3719
3835
|
}
|
|
3720
3836
|
var Lowerer = class {
|
|
3721
3837
|
// tree-sitter hands back a fresh wrapper object each time a child is
|
|
@@ -3764,7 +3880,7 @@ var Lowerer = class {
|
|
|
3764
3880
|
return [nested];
|
|
3765
3881
|
}
|
|
3766
3882
|
lowerIf(node) {
|
|
3767
|
-
const clauses = node.
|
|
3883
|
+
const clauses = children(node).filter(
|
|
3768
3884
|
(child) => child !== null && (child.type === "elif_clause" || child.type === "else_clause")
|
|
3769
3885
|
);
|
|
3770
3886
|
return {
|
|
@@ -3776,10 +3892,10 @@ var Lowerer = class {
|
|
|
3776
3892
|
};
|
|
3777
3893
|
}
|
|
3778
3894
|
lowerTry(node) {
|
|
3779
|
-
const excepts = node.
|
|
3895
|
+
const excepts = children(node).filter(
|
|
3780
3896
|
(child) => child !== null && (child.type === "except_clause" || child.type === "except_group_clause")
|
|
3781
3897
|
);
|
|
3782
|
-
const finallyClause = node.
|
|
3898
|
+
const finallyClause = children(node).find(
|
|
3783
3899
|
(child) => child !== null && child.type === "finally_clause"
|
|
3784
3900
|
) ?? null;
|
|
3785
3901
|
return {
|
|
@@ -3795,7 +3911,7 @@ var Lowerer = class {
|
|
|
3795
3911
|
(child) => child.type === "case_clause"
|
|
3796
3912
|
);
|
|
3797
3913
|
const groups = cases.map((clause) => {
|
|
3798
|
-
const pattern = clause.
|
|
3914
|
+
const pattern = children(clause).find(
|
|
3799
3915
|
(child) => child !== null && child.type === "case_pattern"
|
|
3800
3916
|
) ?? null;
|
|
3801
3917
|
return {
|
|
@@ -3876,7 +3992,7 @@ function literalArgOf(node, facts) {
|
|
|
3876
3992
|
return null;
|
|
3877
3993
|
}
|
|
3878
3994
|
function bodyCalls(node, found = []) {
|
|
3879
|
-
for (const child of node
|
|
3995
|
+
for (const child of children(node)) {
|
|
3880
3996
|
if (child === null || NESTED_DEFINITION_TYPES.has(child.type)) {
|
|
3881
3997
|
continue;
|
|
3882
3998
|
}
|
|
@@ -3888,7 +4004,7 @@ function bodyCalls(node, found = []) {
|
|
|
3888
4004
|
return found;
|
|
3889
4005
|
}
|
|
3890
4006
|
function moduleLoadCalls(node, found = []) {
|
|
3891
|
-
for (const child of node
|
|
4007
|
+
for (const child of children(node)) {
|
|
3892
4008
|
if (child === null || !runsAtModuleLoad(child)) {
|
|
3893
4009
|
continue;
|
|
3894
4010
|
}
|
|
@@ -3928,7 +4044,7 @@ function argumentNodes(call) {
|
|
|
3928
4044
|
if (args === null) {
|
|
3929
4045
|
return [];
|
|
3930
4046
|
}
|
|
3931
|
-
return args
|
|
4047
|
+
return children(args).map(
|
|
3932
4048
|
(child) => child.type === "keyword_argument" ? field(child, "value") ?? child : child
|
|
3933
4049
|
);
|
|
3934
4050
|
}
|
|
@@ -3939,6 +4055,9 @@ function calleeText(call) {
|
|
|
3939
4055
|
return field(call, "function")?.text ?? call.text;
|
|
3940
4056
|
}
|
|
3941
4057
|
function invocationEffects(definitionNode, facts) {
|
|
4058
|
+
return invocationSites(definitionNode, facts).map((site) => site.effect);
|
|
4059
|
+
}
|
|
4060
|
+
function invocationSites(definitionNode, facts) {
|
|
3942
4061
|
const body = field(definitionNode, "body");
|
|
3943
4062
|
if (body === null) {
|
|
3944
4063
|
return [];
|
|
@@ -3946,14 +4065,18 @@ function invocationEffects(definitionNode, facts) {
|
|
|
3946
4065
|
return invocationEffectsIn(body, bodyCalls(body), facts);
|
|
3947
4066
|
}
|
|
3948
4067
|
function moduleLoadInvocationEffects(moduleNode, facts) {
|
|
3949
|
-
return invocationEffectsIn(
|
|
4068
|
+
return invocationEffectsIn(
|
|
4069
|
+
moduleNode,
|
|
4070
|
+
moduleLoadCalls(moduleNode),
|
|
4071
|
+
facts
|
|
4072
|
+
).map((site) => site.effect);
|
|
3950
4073
|
}
|
|
3951
4074
|
var ASKED_ABOUT_TYPES = /* @__PURE__ */ new Set(["identifier", "attribute", "call"]);
|
|
3952
4075
|
function askedNodesUnder(node, found = []) {
|
|
3953
4076
|
if (ASKED_ABOUT_TYPES.has(node.type)) {
|
|
3954
4077
|
found.push(node);
|
|
3955
4078
|
}
|
|
3956
|
-
for (const child of node
|
|
4079
|
+
for (const child of children(node)) {
|
|
3957
4080
|
if (child !== null && !NESTED_DEFINITION_TYPES.has(child.type)) {
|
|
3958
4081
|
askedNodesUnder(child, found);
|
|
3959
4082
|
}
|
|
@@ -4027,11 +4150,14 @@ function invocationEffectsIn(body, written, facts) {
|
|
|
4027
4150
|
(condition) => predicateOf(condition, facts, inputs)
|
|
4028
4151
|
);
|
|
4029
4152
|
return {
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4153
|
+
call,
|
|
4154
|
+
effect: {
|
|
4155
|
+
type: "invocation",
|
|
4156
|
+
callee: calleeText(call),
|
|
4157
|
+
args: argsOf(call, facts),
|
|
4158
|
+
async: false,
|
|
4159
|
+
...conditions.length > 0 ? { preconditions: conditions } : {}
|
|
4160
|
+
}
|
|
4035
4161
|
};
|
|
4036
4162
|
});
|
|
4037
4163
|
}
|
|
@@ -4066,7 +4192,7 @@ function statedBy(statement, name) {
|
|
|
4066
4192
|
}
|
|
4067
4193
|
if (statement.type === "as_pattern") {
|
|
4068
4194
|
const alias = field(statement, "alias");
|
|
4069
|
-
const value = statement.
|
|
4195
|
+
const value = statement.namedChild(0) ?? null;
|
|
4070
4196
|
const callee = value?.type === "call" ? field(value, "function") : null;
|
|
4071
4197
|
return alias?.text === name ? callee : null;
|
|
4072
4198
|
}
|
|
@@ -4262,7 +4388,7 @@ function importedFunctionMatch(call, options) {
|
|
|
4262
4388
|
return null;
|
|
4263
4389
|
}
|
|
4264
4390
|
const args = field(call, "arguments");
|
|
4265
|
-
const first = args
|
|
4391
|
+
const first = children(args)[0] ?? null;
|
|
4266
4392
|
const statement = first === null ? null : writtenStatement(first, void 0, options.facts);
|
|
4267
4393
|
if (statement === null) {
|
|
4268
4394
|
return null;
|
|
@@ -4626,7 +4752,7 @@ function columnComparisons(node) {
|
|
|
4626
4752
|
const args = field(node, "arguments");
|
|
4627
4753
|
return (args === null ? [] : children(args)).flatMap(columnComparisons);
|
|
4628
4754
|
}
|
|
4629
|
-
const operator = node.
|
|
4755
|
+
const operator = allChildren(node).find((child) => !child.isNamed);
|
|
4630
4756
|
const [left, right, ...rest] = children(node);
|
|
4631
4757
|
if (node.type !== "comparison_operator" || operator?.type !== "==" || left === void 0 || right === void 0 || rest.length > 0) {
|
|
4632
4758
|
return [];
|
|
@@ -4999,10 +5125,7 @@ function literalAt(key, facts) {
|
|
|
4999
5125
|
|
|
5000
5126
|
// src/paths/bodyBranches.ts
|
|
5001
5127
|
function returnStatements(node, found = []) {
|
|
5002
|
-
for (const child of node
|
|
5003
|
-
if (child === null) {
|
|
5004
|
-
continue;
|
|
5005
|
-
}
|
|
5128
|
+
for (const child of children(node)) {
|
|
5006
5129
|
if (child.type === "function_definition" || child.type === "lambda") {
|
|
5007
5130
|
continue;
|
|
5008
5131
|
}
|
|
@@ -5059,7 +5182,8 @@ function enumerateBodyBranches(options) {
|
|
|
5059
5182
|
const enumerated = enumerateOrDegrade2(
|
|
5060
5183
|
{
|
|
5061
5184
|
statements: lowered.statements,
|
|
5062
|
-
terminalsByStmt: lowered.terminalsByStmt
|
|
5185
|
+
terminalsByStmt: lowered.terminalsByStmt,
|
|
5186
|
+
...options.keepsArms === void 0 ? {} : { keepsArms: options.keepsArms }
|
|
5063
5187
|
},
|
|
5064
5188
|
statements
|
|
5065
5189
|
);
|
|
@@ -5096,6 +5220,236 @@ function enumerateBodyBranches(options) {
|
|
|
5096
5220
|
return branches;
|
|
5097
5221
|
}
|
|
5098
5222
|
|
|
5223
|
+
// src/paths/raisedResponses.ts
|
|
5224
|
+
import { constantOf as constantOf4 } from "@suss/values";
|
|
5225
|
+
function statusNumberOf(node, options) {
|
|
5226
|
+
const value = constantOf4(evaluatedValue(node, options.facts));
|
|
5227
|
+
if (typeof value === "number") {
|
|
5228
|
+
return value;
|
|
5229
|
+
}
|
|
5230
|
+
const origin = originOf(node, options.module);
|
|
5231
|
+
return origin === null ? null : options.constants?.[`${origin.module}.${origin.name}`] ?? null;
|
|
5232
|
+
}
|
|
5233
|
+
var NESTED_DEFINITION_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lambda"]);
|
|
5234
|
+
function raisedResponses(body, options) {
|
|
5235
|
+
if (options.calls.length === 0) {
|
|
5236
|
+
return [];
|
|
5237
|
+
}
|
|
5238
|
+
return raisesIn(body, options);
|
|
5239
|
+
}
|
|
5240
|
+
function raisesIn(body, options) {
|
|
5241
|
+
if (body === null) {
|
|
5242
|
+
return [];
|
|
5243
|
+
}
|
|
5244
|
+
const found = [];
|
|
5245
|
+
const walk = (node) => {
|
|
5246
|
+
for (const child of children(node)) {
|
|
5247
|
+
if (child === null || NESTED_DEFINITION_TYPES2.has(child.type)) {
|
|
5248
|
+
continue;
|
|
5249
|
+
}
|
|
5250
|
+
const response = raisedResponseOf(child, options);
|
|
5251
|
+
if (response !== null) {
|
|
5252
|
+
found.push(response);
|
|
5253
|
+
}
|
|
5254
|
+
walk(child);
|
|
5255
|
+
}
|
|
5256
|
+
};
|
|
5257
|
+
walk(body);
|
|
5258
|
+
return found;
|
|
5259
|
+
}
|
|
5260
|
+
var ENDING_EXPRESSION = {
|
|
5261
|
+
raise_statement: (statement) => statement.namedChild(0) ?? null,
|
|
5262
|
+
expression_statement: (statement) => {
|
|
5263
|
+
const only = statement.namedChild(0);
|
|
5264
|
+
return only?.type === "call" ? only : null;
|
|
5265
|
+
}
|
|
5266
|
+
};
|
|
5267
|
+
function raisedResponseOf(statement, options) {
|
|
5268
|
+
const expression = ENDING_EXPRESSION[statement.type]?.(statement) ?? null;
|
|
5269
|
+
if (expression === null) {
|
|
5270
|
+
return null;
|
|
5271
|
+
}
|
|
5272
|
+
const thrownByCall = statement.type !== "raise_statement";
|
|
5273
|
+
const prebuilt = thrownByCall ? null : prebuiltCallOf(expression, options);
|
|
5274
|
+
if (prebuilt !== null) {
|
|
5275
|
+
return {
|
|
5276
|
+
statement,
|
|
5277
|
+
thrownByCall,
|
|
5278
|
+
terminal: terminalOf(
|
|
5279
|
+
statement,
|
|
5280
|
+
calleeOf(prebuilt.call, prebuilt.call),
|
|
5281
|
+
prebuilt.call,
|
|
5282
|
+
prebuilt.declared,
|
|
5283
|
+
prebuilt.options
|
|
5284
|
+
)
|
|
5285
|
+
};
|
|
5286
|
+
}
|
|
5287
|
+
const call = expression.type === "call" ? expression : null;
|
|
5288
|
+
const callee = calleeOf(expression, call);
|
|
5289
|
+
const declared = declaredCallFor(callee, options);
|
|
5290
|
+
if (declared === void 0 && thrownByCall) {
|
|
5291
|
+
return null;
|
|
5292
|
+
}
|
|
5293
|
+
return {
|
|
5294
|
+
statement,
|
|
5295
|
+
thrownByCall,
|
|
5296
|
+
terminal: terminalOf(statement, callee, call, declared, options)
|
|
5297
|
+
};
|
|
5298
|
+
}
|
|
5299
|
+
function prebuiltCallOf(expression, options) {
|
|
5300
|
+
if (expression.type !== "identifier" && expression.type !== "attribute") {
|
|
5301
|
+
return null;
|
|
5302
|
+
}
|
|
5303
|
+
const written = writtenNodeOf(expression, options.facts);
|
|
5304
|
+
if (written === null || written.type !== "call") {
|
|
5305
|
+
return null;
|
|
5306
|
+
}
|
|
5307
|
+
const inItsFile = { ...options, module: moduleOf(written) };
|
|
5308
|
+
const declared = declaredCallFor(calleeOf(written, written), inItsFile);
|
|
5309
|
+
return declared === void 0 ? null : { call: written, declared, options: inItsFile };
|
|
5310
|
+
}
|
|
5311
|
+
function returnedResponseStatus(statement, options) {
|
|
5312
|
+
const returned = statement.namedChild(0);
|
|
5313
|
+
if (options.calls.length === 0 || returned === void 0 || returned === null || returned.type !== "call") {
|
|
5314
|
+
return null;
|
|
5315
|
+
}
|
|
5316
|
+
const callee = field(returned, "function");
|
|
5317
|
+
if (callee === null) {
|
|
5318
|
+
return null;
|
|
5319
|
+
}
|
|
5320
|
+
const declared = declaredCallFor(callee, options);
|
|
5321
|
+
return declared === void 0 ? null : statusOf(declared, returned, options);
|
|
5322
|
+
}
|
|
5323
|
+
function calleeOf(expression, call) {
|
|
5324
|
+
return call === null ? expression : field(call, "function") ?? expression;
|
|
5325
|
+
}
|
|
5326
|
+
function declaredCallFor(callee, options) {
|
|
5327
|
+
const origin = originOf(callee, options.module);
|
|
5328
|
+
if (origin === null) {
|
|
5329
|
+
return void 0;
|
|
5330
|
+
}
|
|
5331
|
+
const qualified = `${origin.module}.${origin.name}`;
|
|
5332
|
+
return options.calls.find((call) => call.callee === qualified);
|
|
5333
|
+
}
|
|
5334
|
+
function terminalOf(statement, callee, call, declared, options) {
|
|
5335
|
+
return {
|
|
5336
|
+
kind: "throw",
|
|
5337
|
+
statusCode: declared === void 0 ? null : statusOf(declared, call, options),
|
|
5338
|
+
body: null,
|
|
5339
|
+
exceptionType: lastSegmentOf(declared?.callee ?? callee.text),
|
|
5340
|
+
message: call === null ? null : writtenMessageOf(call),
|
|
5341
|
+
...declared === void 0 ? {} : { producesResponse: true },
|
|
5342
|
+
component: null,
|
|
5343
|
+
renderTree: null,
|
|
5344
|
+
delegateTarget: null,
|
|
5345
|
+
emitEvent: null,
|
|
5346
|
+
location: rangeOf(statement)
|
|
5347
|
+
};
|
|
5348
|
+
}
|
|
5349
|
+
function lastSegmentOf(dotted) {
|
|
5350
|
+
const segment = dotted.split(".").pop();
|
|
5351
|
+
return segment === void 0 || segment === "" ? null : segment;
|
|
5352
|
+
}
|
|
5353
|
+
function statusOf(declared, call, options) {
|
|
5354
|
+
const written = call === null ? null : statusArgumentOf(declared, call);
|
|
5355
|
+
if (written === null) {
|
|
5356
|
+
return declared.defaultStatusCode === void 0 ? null : { type: "literal", value: declared.defaultStatusCode };
|
|
5357
|
+
}
|
|
5358
|
+
const value = statusNumberOf(written, options);
|
|
5359
|
+
return value === null ? { type: "dynamic", sourceText: written.text } : { type: "literal", value };
|
|
5360
|
+
}
|
|
5361
|
+
function argumentsOf2(call) {
|
|
5362
|
+
return children(field(call, "arguments"));
|
|
5363
|
+
}
|
|
5364
|
+
function statusArgumentOf(declared, call) {
|
|
5365
|
+
const args = argumentsOf2(call);
|
|
5366
|
+
const keyed = args.find(
|
|
5367
|
+
(arg) => arg.type === "keyword_argument" && field(arg, "name")?.text === declared.statusKeyword
|
|
5368
|
+
);
|
|
5369
|
+
if (keyed !== void 0) {
|
|
5370
|
+
return field(keyed, "value");
|
|
5371
|
+
}
|
|
5372
|
+
if (declared.statusArgument === void 0) {
|
|
5373
|
+
return null;
|
|
5374
|
+
}
|
|
5375
|
+
const positional = args.filter((arg) => arg.type !== "keyword_argument");
|
|
5376
|
+
return positional[declared.statusArgument] ?? null;
|
|
5377
|
+
}
|
|
5378
|
+
function writtenMessageOf(call) {
|
|
5379
|
+
for (const arg of argumentsOf2(call)) {
|
|
5380
|
+
const value = arg.type === "keyword_argument" ? field(arg, "value") : arg;
|
|
5381
|
+
const literal = value === null ? null : stringLiteralValue(value);
|
|
5382
|
+
if (literal !== null) {
|
|
5383
|
+
return literal;
|
|
5384
|
+
}
|
|
5385
|
+
}
|
|
5386
|
+
return null;
|
|
5387
|
+
}
|
|
5388
|
+
|
|
5389
|
+
// src/responseHandOff.ts
|
|
5390
|
+
import { helperPathsOnVariables, splitAtHandOffs } from "@suss/extractor";
|
|
5391
|
+
function throughResponseHelpers(branches, sites, options) {
|
|
5392
|
+
const handOffs = [];
|
|
5393
|
+
for (const { call, effect } of sites) {
|
|
5394
|
+
const helper = helperBranchesAt(call, options);
|
|
5395
|
+
if (helper !== null) {
|
|
5396
|
+
handOffs.push({
|
|
5397
|
+
helper,
|
|
5398
|
+
preconditions: effect.preconditions,
|
|
5399
|
+
line: rangeOf(call).start,
|
|
5400
|
+
at: rangeOf(call)
|
|
5401
|
+
});
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
return handOffs.length === 0 ? [...branches] : branches.flatMap((branch) => splitAtHandOffs(branch, handOffs));
|
|
5405
|
+
}
|
|
5406
|
+
function helperBranchesAt(call, options) {
|
|
5407
|
+
const handed = callArguments(call).filter(
|
|
5408
|
+
(argument) => argument.node.type === "identifier" && refersToResponse(argument.node, options)
|
|
5409
|
+
);
|
|
5410
|
+
if (handed.length === 0) {
|
|
5411
|
+
return null;
|
|
5412
|
+
}
|
|
5413
|
+
const helper = calledDefinition(call, options.facts);
|
|
5414
|
+
if (helper === null || helper.type !== "function_definition") {
|
|
5415
|
+
return null;
|
|
5416
|
+
}
|
|
5417
|
+
const passed = /* @__PURE__ */ new Map();
|
|
5418
|
+
const parameters = parameterShapes(helper, isMethod(helper) ? 1 : 0);
|
|
5419
|
+
for (const argument of handed) {
|
|
5420
|
+
const parameter = parameters.find(
|
|
5421
|
+
(one) => argument.kind === "positional" ? one.position === argument.position : one.name === argument.name
|
|
5422
|
+
);
|
|
5423
|
+
if (parameter !== void 0) {
|
|
5424
|
+
passed.set(parameter.name, argument.node.text);
|
|
5425
|
+
}
|
|
5426
|
+
}
|
|
5427
|
+
return passed.size === 0 ? null : helperPathsOnVariables(options.readHelper(helper), passed);
|
|
5428
|
+
}
|
|
5429
|
+
function refersToResponse(name, options) {
|
|
5430
|
+
const written = awaited(writtenNodeOf(name, options.facts));
|
|
5431
|
+
if (written === null) {
|
|
5432
|
+
return false;
|
|
5433
|
+
}
|
|
5434
|
+
if (sameNode(written, options.request)) {
|
|
5435
|
+
return true;
|
|
5436
|
+
}
|
|
5437
|
+
const callee = written.type === "call" ? field(written, "function") : null;
|
|
5438
|
+
const method = callee === null ? null : field(callee, "attribute");
|
|
5439
|
+
const receiver = callee === null ? null : field(callee, "object");
|
|
5440
|
+
if (method === null || receiver?.type !== "identifier" || !options.bodyMethods.includes(method.text)) {
|
|
5441
|
+
return false;
|
|
5442
|
+
}
|
|
5443
|
+
const parsedFrom = awaited(writtenNodeOf(receiver, options.facts));
|
|
5444
|
+
return parsedFrom !== null && sameNode(parsedFrom, options.request);
|
|
5445
|
+
}
|
|
5446
|
+
function awaited(node) {
|
|
5447
|
+
return node?.type === "await" ? node.namedChild(0) ?? null : node;
|
|
5448
|
+
}
|
|
5449
|
+
function sameNode(a, b) {
|
|
5450
|
+
return a.startIndex === b.startIndex && a.endIndex === b.endIndex && a.tree === b.tree;
|
|
5451
|
+
}
|
|
5452
|
+
|
|
5099
5453
|
// src/clientCalls.ts
|
|
5100
5454
|
function clientCallUnits(root, module, pack, pattern, options) {
|
|
5101
5455
|
const units = [];
|
|
@@ -5155,7 +5509,7 @@ function requestCalls(call, pattern, module, options) {
|
|
|
5155
5509
|
if (stated === null) {
|
|
5156
5510
|
continue;
|
|
5157
5511
|
}
|
|
5158
|
-
const key = `${stated.method} ${stated.path}`;
|
|
5512
|
+
const key = `${stated.method} ${stated.host ?? ""} ${stated.path}`;
|
|
5159
5513
|
if (!byBoundary.has(key)) {
|
|
5160
5514
|
byBoundary.set(key, stated);
|
|
5161
5515
|
}
|
|
@@ -5166,16 +5520,33 @@ function requestCalls(call, pattern, module, options) {
|
|
|
5166
5520
|
return plain === null ? [] : [plain];
|
|
5167
5521
|
}
|
|
5168
5522
|
function requestCall(call, attribute, pattern, options, site) {
|
|
5523
|
+
const stated = methodAndPath(call, attribute, pattern, options, site);
|
|
5524
|
+
if (stated === null) {
|
|
5525
|
+
return null;
|
|
5526
|
+
}
|
|
5527
|
+
const redirectDelivery = redirectDeliveryAt(call, pattern, options, site);
|
|
5528
|
+
return redirectDelivery === void 0 ? stated : { ...stated, redirectDelivery };
|
|
5529
|
+
}
|
|
5530
|
+
function redirectDeliveryAt(call, pattern, options, site) {
|
|
5531
|
+
const option = pattern.response?.redirectOption;
|
|
5532
|
+
const argument = option === void 0 ? null : argumentAt(call, null, option.name);
|
|
5533
|
+
if (option === void 0 || argument === null) {
|
|
5534
|
+
return void 0;
|
|
5535
|
+
}
|
|
5536
|
+
const value = scalarOf(evaluatedValue(argument, options.facts, site));
|
|
5537
|
+
return value === null ? void 0 : redirectDeliveryWhenSet(option, value);
|
|
5538
|
+
}
|
|
5539
|
+
function methodAndPath(call, attribute, pattern, options, site) {
|
|
5169
5540
|
const verb = pattern.verbAttributeNames[attribute];
|
|
5170
5541
|
if (verb !== void 0) {
|
|
5171
|
-
const
|
|
5542
|
+
const target2 = urlAt(
|
|
5172
5543
|
call,
|
|
5173
5544
|
pattern.url.position,
|
|
5174
5545
|
pattern.url.keyword,
|
|
5175
5546
|
options,
|
|
5176
5547
|
site
|
|
5177
5548
|
);
|
|
5178
|
-
return
|
|
5549
|
+
return target2 === null ? null : { method: verb, ...target2, range: rangeOf(call), node: call };
|
|
5179
5550
|
}
|
|
5180
5551
|
const methodCall = pattern.methodCall;
|
|
5181
5552
|
if (methodCall === void 0 || methodCall.attribute !== attribute) {
|
|
@@ -5190,14 +5561,19 @@ function requestCall(call, attribute, pattern, options, site) {
|
|
|
5190
5561
|
if (method === null) {
|
|
5191
5562
|
return null;
|
|
5192
5563
|
}
|
|
5193
|
-
const
|
|
5564
|
+
const target = urlAt(
|
|
5194
5565
|
call,
|
|
5195
5566
|
methodCall.urlPosition,
|
|
5196
5567
|
pattern.url.keyword,
|
|
5197
5568
|
options,
|
|
5198
5569
|
site
|
|
5199
5570
|
);
|
|
5200
|
-
return
|
|
5571
|
+
return target === null ? null : {
|
|
5572
|
+
method: method.toUpperCase(),
|
|
5573
|
+
...target,
|
|
5574
|
+
range: rangeOf(call),
|
|
5575
|
+
node: call
|
|
5576
|
+
};
|
|
5201
5577
|
}
|
|
5202
5578
|
function calledAttribute(callee, pattern, module, facts) {
|
|
5203
5579
|
const origin = originOf(callee, module);
|
|
@@ -5230,7 +5606,9 @@ function urlAt(call, position, keyword, options, site) {
|
|
|
5230
5606
|
if (argument === null) {
|
|
5231
5607
|
return null;
|
|
5232
5608
|
}
|
|
5233
|
-
|
|
5609
|
+
const value = evaluatedValue(argument, options.facts, site);
|
|
5610
|
+
const path8 = pathOf(value);
|
|
5611
|
+
return path8 === void 0 ? null : { path: path8, host: hostOf(value) };
|
|
5234
5612
|
}
|
|
5235
5613
|
function argumentAt(call, position, keyword) {
|
|
5236
5614
|
const args = field(call, "arguments");
|
|
@@ -5248,25 +5626,33 @@ function argumentAt(call, position, keyword) {
|
|
|
5248
5626
|
}
|
|
5249
5627
|
positional.push(child);
|
|
5250
5628
|
}
|
|
5251
|
-
return positional[position] ?? null;
|
|
5629
|
+
return position === null ? null : positional[position] ?? null;
|
|
5252
5630
|
}
|
|
5253
|
-
function callerBranches(definition,
|
|
5631
|
+
function callerBranches(definition, reading) {
|
|
5632
|
+
const range = rangeOf(definition);
|
|
5254
5633
|
const body = field(definition, "body");
|
|
5255
|
-
const
|
|
5256
|
-
const
|
|
5257
|
-
if (body === null
|
|
5634
|
+
const sites = invocationSites(definition, reading.facts);
|
|
5635
|
+
const effects = sites.map((site) => site.effect);
|
|
5636
|
+
if (body === null) {
|
|
5258
5637
|
return [handsBack(range, effects)];
|
|
5259
5638
|
}
|
|
5639
|
+
const raised = raisesIn(body, {
|
|
5640
|
+
calls: [],
|
|
5641
|
+
module: moduleOf(definition),
|
|
5642
|
+
facts: reading.facts
|
|
5643
|
+
});
|
|
5260
5644
|
const branches = enumerateBodyBranches({
|
|
5261
5645
|
body,
|
|
5262
|
-
terminals,
|
|
5263
|
-
raised
|
|
5646
|
+
terminals: bodyTerminals(body, raised),
|
|
5647
|
+
raised,
|
|
5264
5648
|
effects,
|
|
5265
|
-
branchOf: (
|
|
5649
|
+
branchOf: (found2) => found2.type === "raise" ? { terminal: found2.terminal, location: rangeOf(found2.statement) } : handsBackAt(rangeOf(found2.statement)),
|
|
5266
5650
|
fallthrough: handsBackAt(range),
|
|
5267
|
-
facts
|
|
5651
|
+
facts: reading.facts,
|
|
5652
|
+
keepsArms: (condition) => testsStatus(predicateOf(condition, reading.facts), reading.statusMembers)
|
|
5268
5653
|
});
|
|
5269
|
-
|
|
5654
|
+
const found = branches.length === 0 ? [handsBack(range, effects)] : branches;
|
|
5655
|
+
return reading.handOff === void 0 ? found : throughResponseHelpers(found, sites, reading.handOff);
|
|
5270
5656
|
}
|
|
5271
5657
|
function handsBackAt(range) {
|
|
5272
5658
|
return {
|
|
@@ -5302,11 +5688,24 @@ function responseAccessors(pattern) {
|
|
|
5302
5688
|
...response.body === void 0 ? {} : { bodyAccessors: response.body },
|
|
5303
5689
|
...response.statusCode === void 0 ? {} : { statusAccessors: response.statusCode },
|
|
5304
5690
|
...response.success === void 0 ? {} : { successAccessors: response.success },
|
|
5305
|
-
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery }
|
|
5691
|
+
...response.failureDelivery === void 0 ? {} : { failureDelivery: response.failureDelivery },
|
|
5692
|
+
...response.redirectDelivery === void 0 ? {} : { redirectDelivery: response.redirectDelivery }
|
|
5306
5693
|
};
|
|
5307
5694
|
}
|
|
5308
5695
|
function clientUnit(definition, name, request, pattern, pack, options) {
|
|
5309
5696
|
const range = rangeOf(definition);
|
|
5697
|
+
const accessors = responseAccessors(pattern);
|
|
5698
|
+
const statusMembers = statusMembersOf(accessors);
|
|
5699
|
+
const reading = {
|
|
5700
|
+
facts: options.facts,
|
|
5701
|
+
statusMembers,
|
|
5702
|
+
handOff: {
|
|
5703
|
+
request: request.node,
|
|
5704
|
+
bodyMethods: accessors.bodyAccessors ?? [],
|
|
5705
|
+
facts: options.facts,
|
|
5706
|
+
readHelper: (helper) => callerBranches(helper, { facts: options.facts, statusMembers })
|
|
5707
|
+
}
|
|
5708
|
+
};
|
|
5310
5709
|
return {
|
|
5311
5710
|
identity: {
|
|
5312
5711
|
name,
|
|
@@ -5322,11 +5721,13 @@ function clientUnit(definition, name, request, pattern, pack, options) {
|
|
|
5322
5721
|
transport: pack.protocol,
|
|
5323
5722
|
method: request.method,
|
|
5324
5723
|
path: request.path,
|
|
5724
|
+
host: request.host,
|
|
5325
5725
|
recognition: pack.name
|
|
5326
5726
|
}),
|
|
5327
5727
|
parameters: [],
|
|
5328
|
-
branches: callerBranches(definition,
|
|
5329
|
-
...
|
|
5728
|
+
branches: callerBranches(definition, reading),
|
|
5729
|
+
...accessors,
|
|
5730
|
+
...request.redirectDelivery === void 0 ? {} : { redirectDelivery: request.redirectDelivery },
|
|
5330
5731
|
bodyContent: "statements",
|
|
5331
5732
|
dependencyCalls: [],
|
|
5332
5733
|
declaredContract: null
|
|
@@ -5549,7 +5950,7 @@ function isTestedAt(parent, child, subject, seen) {
|
|
|
5549
5950
|
}
|
|
5550
5951
|
function conditionOf(node) {
|
|
5551
5952
|
if (node.type === "conditional_expression") {
|
|
5552
|
-
return node.
|
|
5953
|
+
return node.namedChild(1) ?? null;
|
|
5553
5954
|
}
|
|
5554
5955
|
return CONDITIONED_TYPES.has(node.type) ? field(node, "condition") : null;
|
|
5555
5956
|
}
|
|
@@ -5572,7 +5973,7 @@ function isPresentAt(node, subject) {
|
|
|
5572
5973
|
}
|
|
5573
5974
|
function isBranchWherePresent(parent, child, subject) {
|
|
5574
5975
|
if (parent.type === "conditional_expression") {
|
|
5575
|
-
const [whenTrue, test2, whenFalse] = parent
|
|
5976
|
+
const [whenTrue, test2, whenFalse] = children(parent);
|
|
5576
5977
|
return test2 !== void 0 && test2 !== null && (whenTrue?.id === child.id && isPresentWhen(test2, true, subject) || whenFalse?.id === child.id && isPresentWhen(test2, false, subject));
|
|
5577
5978
|
}
|
|
5578
5979
|
if (parent.type === "boolean_operator") {
|
|
@@ -5610,7 +6011,7 @@ function followsExitWhenAbsent(parent, child, subject) {
|
|
|
5610
6011
|
if (parent.type !== "block" && parent.type !== "module") {
|
|
5611
6012
|
return false;
|
|
5612
6013
|
}
|
|
5613
|
-
const statements = parent
|
|
6014
|
+
const statements = children(parent);
|
|
5614
6015
|
const at = statements.findIndex((statement) => statement?.id === child.id);
|
|
5615
6016
|
return statements.slice(0, at).some(
|
|
5616
6017
|
(statement) => statement !== null && leavesWhenAbsent(statement, subject)
|
|
@@ -5654,7 +6055,7 @@ function continuationRaises(from) {
|
|
|
5654
6055
|
let parent = current.parent;
|
|
5655
6056
|
while (parent !== null) {
|
|
5656
6057
|
if (parent.type === "block" || parent.type === "module") {
|
|
5657
|
-
const statements = parent
|
|
6058
|
+
const statements = children(parent);
|
|
5658
6059
|
const at = statements.findIndex((one) => one?.id === current.id);
|
|
5659
6060
|
const exit = firstExit(statements.slice(at + 1));
|
|
5660
6061
|
if (exit !== null) {
|
|
@@ -5698,7 +6099,7 @@ function exitOf(statement) {
|
|
|
5698
6099
|
if (LEAVING_TYPES.has(statement.type)) {
|
|
5699
6100
|
return "leave";
|
|
5700
6101
|
}
|
|
5701
|
-
return statement.type === "block" ? firstExit(statement
|
|
6102
|
+
return statement.type === "block" ? firstExit(children(statement)) : null;
|
|
5702
6103
|
}
|
|
5703
6104
|
function isPresentWhen(test, outcome, subject) {
|
|
5704
6105
|
const expression = peelParens(test);
|
|
@@ -5738,7 +6139,7 @@ function isPresentAfterComparison(comparison, outcome, subject) {
|
|
|
5738
6139
|
}
|
|
5739
6140
|
function comparisonParts(comparison) {
|
|
5740
6141
|
const operators = fields(comparison, "operators");
|
|
5741
|
-
const operands = comparison.
|
|
6142
|
+
const operands = children(comparison).filter(
|
|
5742
6143
|
(child) => child !== null && !operators.some((one) => one.id === child.id)
|
|
5743
6144
|
);
|
|
5744
6145
|
const [left, right] = operands;
|
|
@@ -5761,7 +6162,7 @@ function comparedWithNone(comparison) {
|
|
|
5761
6162
|
}
|
|
5762
6163
|
var NONE_OPERATORS = /* @__PURE__ */ new Set(["is", "is not", "==", "!="]);
|
|
5763
6164
|
function peelParens(node) {
|
|
5764
|
-
const inner = node.type === "parenthesized_expression" ? node.
|
|
6165
|
+
const inner = node.type === "parenthesized_expression" ? node.namedChild(0) : null;
|
|
5765
6166
|
return inner === null || inner === void 0 ? node : peelParens(inner);
|
|
5766
6167
|
}
|
|
5767
6168
|
function climbParens(node) {
|
|
@@ -5819,7 +6220,7 @@ function envReadEffects(root, module, facts) {
|
|
|
5819
6220
|
const slots = [];
|
|
5820
6221
|
const readsHelpers = facts !== void 0 && sitesByDb.has(facts);
|
|
5821
6222
|
const startScope = module.scopeFor.get(root.id) ?? module.moduleScope;
|
|
5822
|
-
walkDescendants(root, startScope, {
|
|
6223
|
+
walkDescendants(root, startScope, children, {
|
|
5823
6224
|
at: (node, scope) => {
|
|
5824
6225
|
const syntax = envReadSyntaxAt(node, scope);
|
|
5825
6226
|
if (syntax !== null) {
|
|
@@ -5878,7 +6279,7 @@ function hasFallback(node, spelling, scope) {
|
|
|
5878
6279
|
}
|
|
5879
6280
|
function envFactsIn(filePath, root, module) {
|
|
5880
6281
|
const found = { sites: [], objects: [] };
|
|
5881
|
-
walkDescendants(root, module.moduleScope, {
|
|
6282
|
+
walkDescendants(root, module.moduleScope, children, {
|
|
5882
6283
|
at: (node, scope) => {
|
|
5883
6284
|
if (isEnviron(node, scope) && handsOnward(node)) {
|
|
5884
6285
|
found.objects.push(keyOf(filePath, node));
|
|
@@ -6033,198 +6434,67 @@ function helperReadsByCall(calls, db) {
|
|
|
6033
6434
|
found.set(call.id, reads);
|
|
6034
6435
|
}
|
|
6035
6436
|
}
|
|
6036
|
-
return found;
|
|
6037
|
-
}
|
|
6038
|
-
function argumentsByParameter(db, call, calleeKey2) {
|
|
6039
|
-
const written = callArguments(call);
|
|
6040
|
-
if (written.length === 0) {
|
|
6041
|
-
return /* @__PURE__ */ new Map();
|
|
6042
|
-
}
|
|
6043
|
-
const positional = /* @__PURE__ */ new Map();
|
|
6044
|
-
const byName = /* @__PURE__ */ new Map();
|
|
6045
|
-
for (const argument of written) {
|
|
6046
|
-
if (argument.kind === "keyword") {
|
|
6047
|
-
byName.set(argument.name, argument.node);
|
|
6048
|
-
continue;
|
|
6049
|
-
}
|
|
6050
|
-
positional.set(String(argument.position), argument.node);
|
|
6051
|
-
}
|
|
6052
|
-
const argumentAt2 = /* @__PURE__ */ new Map();
|
|
6053
|
-
for (const callee of resolvedFunctions(db, calleeKey2)) {
|
|
6054
|
-
for (const row of db.lookup("paramOf", 0, callee)) {
|
|
6055
|
-
const at = positional.get(String(row[1]));
|
|
6056
|
-
if (at !== void 0) {
|
|
6057
|
-
argumentAt2.set(String(row[2]), at);
|
|
6058
|
-
}
|
|
6059
|
-
}
|
|
6060
|
-
for (const row of db.lookup("paramNamed", 0, callee)) {
|
|
6061
|
-
const at = byName.get(String(row[1]));
|
|
6062
|
-
if (at !== void 0) {
|
|
6063
|
-
argumentAt2.set(String(row[2]), at);
|
|
6064
|
-
}
|
|
6065
|
-
}
|
|
6066
|
-
}
|
|
6067
|
-
return argumentAt2;
|
|
6068
|
-
}
|
|
6069
|
-
function readsThroughHelper(db, call, argumentAt2, siteById, named) {
|
|
6070
|
-
const reads = /* @__PURE__ */ new Map();
|
|
6071
|
-
for (const [parameter, argument] of argumentAt2) {
|
|
6072
|
-
const sites = named.get(parameter);
|
|
6073
|
-
noteLookup(
|
|
6074
|
-
db,
|
|
6075
|
-
`${NAMED_PARAMETER}${parameter}`,
|
|
6076
|
-
describeSites(sites, siteById)
|
|
6077
|
-
);
|
|
6078
|
-
if (sites === void 0) {
|
|
6079
|
-
continue;
|
|
6080
|
-
}
|
|
6081
|
-
const name = stringLiteralValue(argument) ?? stringValueOf(argument, db);
|
|
6082
|
-
if (name === null) {
|
|
6083
|
-
continue;
|
|
6084
|
-
}
|
|
6085
|
-
for (const id of sites) {
|
|
6086
|
-
const defaulted = siteById.get(id)?.defaulted ?? false;
|
|
6087
|
-
reads.set(name, (reads.get(name) ?? true) && defaulted);
|
|
6088
|
-
}
|
|
6089
|
-
}
|
|
6090
|
-
if (reads.size === 0) {
|
|
6091
|
-
return [];
|
|
6092
|
-
}
|
|
6093
|
-
const defaultedAtCall = isDefaultedAt(call);
|
|
6094
|
-
return [...reads].map(
|
|
6095
|
-
([name, defaulted]) => configReadEffect({ name, defaulted: defaulted || defaultedAtCall })
|
|
6096
|
-
);
|
|
6097
|
-
}
|
|
6098
|
-
|
|
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;
|
|
6437
|
+
return found;
|
|
6438
|
+
}
|
|
6439
|
+
function argumentsByParameter(db, call, calleeKey2) {
|
|
6440
|
+
const written = callArguments(call);
|
|
6441
|
+
if (written.length === 0) {
|
|
6442
|
+
return /* @__PURE__ */ new Map();
|
|
6215
6443
|
}
|
|
6216
|
-
const positional =
|
|
6217
|
-
|
|
6444
|
+
const positional = /* @__PURE__ */ new Map();
|
|
6445
|
+
const byName = /* @__PURE__ */ new Map();
|
|
6446
|
+
for (const argument of written) {
|
|
6447
|
+
if (argument.kind === "keyword") {
|
|
6448
|
+
byName.set(argument.name, argument.node);
|
|
6449
|
+
continue;
|
|
6450
|
+
}
|
|
6451
|
+
positional.set(String(argument.position), argument.node);
|
|
6452
|
+
}
|
|
6453
|
+
const argumentAt2 = /* @__PURE__ */ new Map();
|
|
6454
|
+
for (const callee of resolvedFunctions(db, calleeKey2)) {
|
|
6455
|
+
for (const row of db.lookup("paramOf", 0, callee)) {
|
|
6456
|
+
const at = positional.get(String(row[1]));
|
|
6457
|
+
if (at !== void 0) {
|
|
6458
|
+
argumentAt2.set(String(row[2]), at);
|
|
6459
|
+
}
|
|
6460
|
+
}
|
|
6461
|
+
for (const row of db.lookup("paramNamed", 0, callee)) {
|
|
6462
|
+
const at = byName.get(String(row[1]));
|
|
6463
|
+
if (at !== void 0) {
|
|
6464
|
+
argumentAt2.set(String(row[2]), at);
|
|
6465
|
+
}
|
|
6466
|
+
}
|
|
6467
|
+
}
|
|
6468
|
+
return argumentAt2;
|
|
6218
6469
|
}
|
|
6219
|
-
function
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
const
|
|
6223
|
-
|
|
6224
|
-
|
|
6470
|
+
function readsThroughHelper(db, call, argumentAt2, siteById, named) {
|
|
6471
|
+
const reads = /* @__PURE__ */ new Map();
|
|
6472
|
+
for (const [parameter, argument] of argumentAt2) {
|
|
6473
|
+
const sites = named.get(parameter);
|
|
6474
|
+
noteLookup(
|
|
6475
|
+
db,
|
|
6476
|
+
`${NAMED_PARAMETER}${parameter}`,
|
|
6477
|
+
describeSites(sites, siteById)
|
|
6478
|
+
);
|
|
6479
|
+
if (sites === void 0) {
|
|
6480
|
+
continue;
|
|
6481
|
+
}
|
|
6482
|
+
const name = stringLiteralValue(argument) ?? stringValueOf(argument, db);
|
|
6483
|
+
if (name === null) {
|
|
6484
|
+
continue;
|
|
6485
|
+
}
|
|
6486
|
+
for (const id of sites) {
|
|
6487
|
+
const defaulted = siteById.get(id)?.defaulted ?? false;
|
|
6488
|
+
reads.set(name, (reads.get(name) ?? true) && defaulted);
|
|
6225
6489
|
}
|
|
6226
6490
|
}
|
|
6227
|
-
|
|
6491
|
+
if (reads.size === 0) {
|
|
6492
|
+
return [];
|
|
6493
|
+
}
|
|
6494
|
+
const defaultedAtCall = isDefaultedAt(call);
|
|
6495
|
+
return [...reads].map(
|
|
6496
|
+
([name, defaulted]) => configReadEffect({ name, defaulted: defaulted || defaultedAtCall })
|
|
6497
|
+
);
|
|
6228
6498
|
}
|
|
6229
6499
|
|
|
6230
6500
|
// src/paths/returnedShape.ts
|
|
@@ -6286,7 +6556,7 @@ function shapeOfReturned(node, depth = 0) {
|
|
|
6286
6556
|
return { type: "unknown" };
|
|
6287
6557
|
}
|
|
6288
6558
|
function returnedBodyShape(statement) {
|
|
6289
|
-
const returned = statement.
|
|
6559
|
+
const returned = statement.namedChild(0);
|
|
6290
6560
|
if (returned == null) {
|
|
6291
6561
|
return null;
|
|
6292
6562
|
}
|
|
@@ -6332,7 +6602,7 @@ var DEFERRED_BODY_TYPES2 = /* @__PURE__ */ new Set(["function_definition", "lamb
|
|
|
6332
6602
|
function streamWriteEffects(root, module) {
|
|
6333
6603
|
const found = [];
|
|
6334
6604
|
const startScope = module.scopeFor.get(root.id) ?? module.moduleScope;
|
|
6335
|
-
walkDescendants2(root, startScope, {
|
|
6605
|
+
walkDescendants2(root, startScope, children, {
|
|
6336
6606
|
at: (node, scope) => {
|
|
6337
6607
|
if (node.type !== "call") {
|
|
6338
6608
|
return;
|
|
@@ -6419,7 +6689,7 @@ function jsonDumped(node, scope) {
|
|
|
6419
6689
|
// src/discovery.ts
|
|
6420
6690
|
function decoratedNodes(root) {
|
|
6421
6691
|
const found = [];
|
|
6422
|
-
walkDescendants3(root, null, {
|
|
6692
|
+
walkDescendants3(root, null, children, {
|
|
6423
6693
|
at: (node) => {
|
|
6424
6694
|
if (node.type !== "decorated_definition") {
|
|
6425
6695
|
return;
|
|
@@ -6802,7 +7072,7 @@ function readRouterPrefix(pattern, classification, module, options, range) {
|
|
|
6802
7072
|
}
|
|
6803
7073
|
return absentReading;
|
|
6804
7074
|
}
|
|
6805
|
-
function readStatusCode(pattern, classification) {
|
|
7075
|
+
function readStatusCode(pattern, classification, options) {
|
|
6806
7076
|
if (pattern.statusCodeKeyword === void 0) {
|
|
6807
7077
|
return absentReading;
|
|
6808
7078
|
}
|
|
@@ -6810,11 +7080,15 @@ function readStatusCode(pattern, classification) {
|
|
|
6810
7080
|
if (arg === void 0) {
|
|
6811
7081
|
return absentReading;
|
|
6812
7082
|
}
|
|
6813
|
-
|
|
6814
|
-
|
|
7083
|
+
const status = statusNumberOf(arg.node, {
|
|
7084
|
+
...options,
|
|
7085
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
7086
|
+
});
|
|
7087
|
+
if (status !== null) {
|
|
7088
|
+
return writtenReading(status, classification.range);
|
|
6815
7089
|
}
|
|
6816
7090
|
return unreadableReading(
|
|
6817
|
-
"The status this route's decorator states
|
|
7091
|
+
"The status this route's decorator states does not come to a number here, so the response claims no status",
|
|
6818
7092
|
classification.range
|
|
6819
7093
|
);
|
|
6820
7094
|
}
|
|
@@ -6835,11 +7109,14 @@ function statusFromReturnedValue(node, facts) {
|
|
|
6835
7109
|
return digits === null ? null : Number.parseInt(digits[1], 10);
|
|
6836
7110
|
}
|
|
6837
7111
|
function statusOfReturn(statement, facts) {
|
|
6838
|
-
const returned = statement.
|
|
7112
|
+
const returned = statement.namedChild(0);
|
|
6839
7113
|
if (returned?.type !== "expression_list") {
|
|
6840
7114
|
return { kind: "none" };
|
|
6841
7115
|
}
|
|
6842
|
-
const status = statusFromReturnedValue(
|
|
7116
|
+
const status = statusFromReturnedValue(
|
|
7117
|
+
returned.namedChild(1) ?? void 0,
|
|
7118
|
+
facts
|
|
7119
|
+
);
|
|
6843
7120
|
return status === null ? { kind: "unreadable" } : { kind: "status", value: status };
|
|
6844
7121
|
}
|
|
6845
7122
|
function returnStatusReading(statement, ctx) {
|
|
@@ -6859,6 +7136,22 @@ function returnStatusReading(statement, ctx) {
|
|
|
6859
7136
|
function returnBranch(statement, ctx) {
|
|
6860
7137
|
const range = rangeOf(statement);
|
|
6861
7138
|
const writtenBody = returnedBodyShape(statement);
|
|
7139
|
+
return responseBranchAt(
|
|
7140
|
+
range,
|
|
7141
|
+
returnStatusReading(statement, ctx),
|
|
7142
|
+
writtenBody === null ? ctx.responseShape.reading : writtenReading(writtenBody, range),
|
|
7143
|
+
ctx
|
|
7144
|
+
);
|
|
7145
|
+
}
|
|
7146
|
+
function fallthroughBranch(definitionNode, ctx) {
|
|
7147
|
+
return responseBranchAt(
|
|
7148
|
+
rangeOf(definitionNode),
|
|
7149
|
+
ctx.pattern.statusFromReturnedTuple === true ? absentReading : ctx.declaredStatus.reading,
|
|
7150
|
+
ctx.responseShape.reading,
|
|
7151
|
+
ctx
|
|
7152
|
+
);
|
|
7153
|
+
}
|
|
7154
|
+
function responseBranchAt(range, status, body, ctx) {
|
|
6862
7155
|
return {
|
|
6863
7156
|
terminal: {
|
|
6864
7157
|
kind: "response",
|
|
@@ -6875,12 +7168,10 @@ function returnBranch(statement, ctx) {
|
|
|
6875
7168
|
location: range
|
|
6876
7169
|
},
|
|
6877
7170
|
statusCodeReading: {
|
|
6878
|
-
reading:
|
|
7171
|
+
reading: status,
|
|
6879
7172
|
...ctx.declaredStatus.libraryDefault !== void 0 ? { libraryDefault: ctx.declaredStatus.libraryDefault } : {}
|
|
6880
7173
|
},
|
|
6881
|
-
bodyShapeReading: {
|
|
6882
|
-
reading: writtenBody === null ? ctx.responseShape.reading : writtenReading(writtenBody, range)
|
|
6883
|
-
},
|
|
7174
|
+
bodyShapeReading: { reading: body },
|
|
6884
7175
|
location: range
|
|
6885
7176
|
};
|
|
6886
7177
|
}
|
|
@@ -6901,11 +7192,12 @@ function branchesPerTerminal(options) {
|
|
|
6901
7192
|
const raised = raisedResponses(body, {
|
|
6902
7193
|
calls: options.responseStatusCalls,
|
|
6903
7194
|
module: options.ctx.module,
|
|
6904
|
-
facts: options.ctx.facts
|
|
7195
|
+
facts: options.ctx.facts,
|
|
7196
|
+
constants: options.ctx.pattern.statusCodeConstants ?? {}
|
|
6905
7197
|
});
|
|
6906
7198
|
const terminals = bodyTerminals(body, raised);
|
|
6907
7199
|
const soleReturnWritesBody = terminals.length === 1 && terminals[0]?.type === "return" && returnedBodyShape(terminals[0].statement) !== null;
|
|
6908
|
-
if (terminals.length
|
|
7200
|
+
if (terminals.length === 0) {
|
|
6909
7201
|
return null;
|
|
6910
7202
|
}
|
|
6911
7203
|
const branches = enumerateBodyBranches({
|
|
@@ -6914,6 +7206,7 @@ function branchesPerTerminal(options) {
|
|
|
6914
7206
|
raised,
|
|
6915
7207
|
effects: options.effects,
|
|
6916
7208
|
branchOf: (found) => terminalBranchOf(found, options.ctx),
|
|
7209
|
+
fallthrough: fallthroughBranch(options.definitionNode, options.ctx),
|
|
6917
7210
|
facts: options.ctx.facts
|
|
6918
7211
|
});
|
|
6919
7212
|
return branches.length > 1 || soleReturnWritesBody ? branches : null;
|
|
@@ -6922,7 +7215,8 @@ function statusOfReturnIn(statement, pattern, options) {
|
|
|
6922
7215
|
const constructed = returnedResponseStatus(statement, {
|
|
6923
7216
|
calls: pattern.responseConstructors ?? [],
|
|
6924
7217
|
module: options.module,
|
|
6925
|
-
facts: options.facts
|
|
7218
|
+
facts: options.facts,
|
|
7219
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
6926
7220
|
});
|
|
6927
7221
|
if (constructed !== null) {
|
|
6928
7222
|
return constructed.type === "literal" ? { kind: "status", value: constructed.value } : { kind: "unreadable" };
|
|
@@ -7016,6 +7310,25 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7016
7310
|
module.scopeFor,
|
|
7017
7311
|
options.importedDefinition ?? null
|
|
7018
7312
|
);
|
|
7313
|
+
const wrappers = wrappersAround(
|
|
7314
|
+
pattern,
|
|
7315
|
+
pack,
|
|
7316
|
+
classification,
|
|
7317
|
+
functionNode,
|
|
7318
|
+
module,
|
|
7319
|
+
options
|
|
7320
|
+
);
|
|
7321
|
+
const dependencyParameters = options.wrappers?.dependencyParameters(
|
|
7322
|
+
wrappers
|
|
7323
|
+
) ?? { names: /* @__PURE__ */ new Set(), declaresSource: false };
|
|
7324
|
+
const declaredStatuses = declaredStatusesOf(
|
|
7325
|
+
pattern,
|
|
7326
|
+
pack,
|
|
7327
|
+
classification,
|
|
7328
|
+
functionNode,
|
|
7329
|
+
module,
|
|
7330
|
+
options
|
|
7331
|
+
);
|
|
7019
7332
|
return readRoutePaths(
|
|
7020
7333
|
pattern,
|
|
7021
7334
|
readPathArgument(classification, options),
|
|
@@ -7028,6 +7341,8 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7028
7341
|
pack,
|
|
7029
7342
|
name: functionName,
|
|
7030
7343
|
exportPath: [functionName],
|
|
7344
|
+
dependencyParameters,
|
|
7345
|
+
declaredStatuses,
|
|
7031
7346
|
method: verb,
|
|
7032
7347
|
routePath: entry.routePath,
|
|
7033
7348
|
...entry.mount !== void 0 ? { mount: entry.mount } : {},
|
|
@@ -7044,7 +7359,10 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7044
7359
|
responseShape: readResponseModel(pattern, classification, module, ctx),
|
|
7045
7360
|
statusCode: defaultedStatus(
|
|
7046
7361
|
declaredOrReturnedStatus(
|
|
7047
|
-
readStatusCode(pattern, classification
|
|
7362
|
+
readStatusCode(pattern, classification, {
|
|
7363
|
+
module,
|
|
7364
|
+
facts: options.facts
|
|
7365
|
+
}),
|
|
7048
7366
|
readReturnedStatus(pattern, functionNode, {
|
|
7049
7367
|
module,
|
|
7050
7368
|
facts: options.facts
|
|
@@ -7055,14 +7373,7 @@ function functionRouteUnits(pattern, pack, verb, classification, functionNode, m
|
|
|
7055
7373
|
definitionsCtx: ctx,
|
|
7056
7374
|
storage: options.storage,
|
|
7057
7375
|
importedDefinition: options.importedDefinition,
|
|
7058
|
-
wrappers
|
|
7059
|
-
pattern,
|
|
7060
|
-
pack,
|
|
7061
|
-
classification,
|
|
7062
|
-
functionNode,
|
|
7063
|
-
module,
|
|
7064
|
-
options
|
|
7065
|
-
)
|
|
7376
|
+
wrappers
|
|
7066
7377
|
},
|
|
7067
7378
|
options
|
|
7068
7379
|
)
|
|
@@ -7081,6 +7392,38 @@ function wrappersAround(pattern, pack, classification, definitionNode, module, o
|
|
|
7081
7392
|
definitionNode
|
|
7082
7393
|
});
|
|
7083
7394
|
}
|
|
7395
|
+
function declaredStatusesOf(pattern, pack, classification, definitionNode, module, options) {
|
|
7396
|
+
const keyword = pattern.responsesKeyword;
|
|
7397
|
+
if (keyword === void 0) {
|
|
7398
|
+
return [];
|
|
7399
|
+
}
|
|
7400
|
+
const above = options.wrappers?.callsAbove({
|
|
7401
|
+
pack,
|
|
7402
|
+
pattern,
|
|
7403
|
+
file: options.absoluteFile ?? options.filePath,
|
|
7404
|
+
module,
|
|
7405
|
+
classification,
|
|
7406
|
+
definitionNode
|
|
7407
|
+
}) ?? [];
|
|
7408
|
+
const dictionaries = [
|
|
7409
|
+
classification.keywordArgs[keyword]?.node,
|
|
7410
|
+
...above.map(
|
|
7411
|
+
(call) => readCallArguments(field(call, "arguments")).keywordArgs[keyword]?.node
|
|
7412
|
+
)
|
|
7413
|
+
].filter((node) => node?.type === "dictionary");
|
|
7414
|
+
const statuses = dictionaries.flatMap(
|
|
7415
|
+
(dictionary) => children(dictionary).flatMap((pair) => {
|
|
7416
|
+
const key = pair?.type === "pair" ? field(pair, "key") : null;
|
|
7417
|
+
const status = key === null ? null : statusNumberOf(key, {
|
|
7418
|
+
module: moduleOf(key),
|
|
7419
|
+
facts: options.facts,
|
|
7420
|
+
constants: pattern.statusCodeConstants ?? {}
|
|
7421
|
+
});
|
|
7422
|
+
return status === null ? [] : [status];
|
|
7423
|
+
})
|
|
7424
|
+
);
|
|
7425
|
+
return [...new Set(statuses)].sort((a, b) => a - b);
|
|
7426
|
+
}
|
|
7084
7427
|
function readResponseShape(declared, readAnnotation) {
|
|
7085
7428
|
if (declared.kind === "written") {
|
|
7086
7429
|
return { reading: declared, passedOver: [] };
|
|
@@ -7164,6 +7507,8 @@ function buildRouteUnit(options) {
|
|
|
7164
7507
|
pathParamNames: template?.paramNames ?? null,
|
|
7165
7508
|
requestBodyFromAnnotatedClass,
|
|
7166
7509
|
injectedCallees,
|
|
7510
|
+
injectedTypes: new Set(pattern.injectedParameterTypes ?? []),
|
|
7511
|
+
module,
|
|
7167
7512
|
sources: pattern.parameterSources ?? {},
|
|
7168
7513
|
aliasKeyword: pattern.parameterAliasKeyword
|
|
7169
7514
|
},
|
|
@@ -7220,6 +7565,22 @@ function buildRouteUnit(options) {
|
|
|
7220
7565
|
};
|
|
7221
7566
|
branches.push(withBodyEffects(bare, extra));
|
|
7222
7567
|
}
|
|
7568
|
+
if (branches.length > 0) {
|
|
7569
|
+
branches.push(
|
|
7570
|
+
...validationFailureBranches(
|
|
7571
|
+
pattern,
|
|
7572
|
+
readsTheRequest(
|
|
7573
|
+
parameters,
|
|
7574
|
+
template,
|
|
7575
|
+
options.dependencyParameters ?? {
|
|
7576
|
+
names: /* @__PURE__ */ new Set(),
|
|
7577
|
+
declaresSource: false
|
|
7578
|
+
}
|
|
7579
|
+
),
|
|
7580
|
+
rangeOf(definitionNode)
|
|
7581
|
+
)
|
|
7582
|
+
);
|
|
7583
|
+
}
|
|
7223
7584
|
const bodyNode = field(definitionNode, "body");
|
|
7224
7585
|
return {
|
|
7225
7586
|
identity: {
|
|
@@ -7251,9 +7612,51 @@ function buildRouteUnit(options) {
|
|
|
7251
7612
|
...collectedDefinitions(ctx) !== null ? { definitions: collectedDefinitions(ctx) } : {},
|
|
7252
7613
|
...options.mount !== void 0 ? { mount: options.mount } : {},
|
|
7253
7614
|
...options.wrappers !== void 0 && options.wrappers.length > 0 ? { wrappers: options.wrappers } : {},
|
|
7254
|
-
...pack.requestSpelling === void 0 ? {} : { requestSpelling: pack.requestSpelling }
|
|
7615
|
+
...pack.requestSpelling === void 0 ? {} : { requestSpelling: pack.requestSpelling },
|
|
7616
|
+
...options.declaredStatuses !== void 0 && options.declaredStatuses.length > 0 ? { declaredStatuses: options.declaredStatuses } : {}
|
|
7255
7617
|
};
|
|
7256
7618
|
}
|
|
7619
|
+
function readsTheRequest(parameters, template, dependencies) {
|
|
7620
|
+
if (dependencies.declaresSource || parameters.some((parameter) => parameter.role !== null)) {
|
|
7621
|
+
return true;
|
|
7622
|
+
}
|
|
7623
|
+
return [...template?.paramNames ?? []].some(
|
|
7624
|
+
(name) => dependencies.names.has(name)
|
|
7625
|
+
);
|
|
7626
|
+
}
|
|
7627
|
+
function validationFailureBranches(pattern, readsRequest, range) {
|
|
7628
|
+
const status = pattern.validationFailureStatus;
|
|
7629
|
+
if (status === void 0 || !readsRequest) {
|
|
7630
|
+
return [];
|
|
7631
|
+
}
|
|
7632
|
+
return [
|
|
7633
|
+
{
|
|
7634
|
+
conditions: [
|
|
7635
|
+
{
|
|
7636
|
+
sourceText: "request input fails validation",
|
|
7637
|
+
structured: null,
|
|
7638
|
+
polarity: "positive",
|
|
7639
|
+
source: "earlyThrow"
|
|
7640
|
+
}
|
|
7641
|
+
],
|
|
7642
|
+
terminal: {
|
|
7643
|
+
kind: "response",
|
|
7644
|
+
statusCode: { type: "literal", value: status },
|
|
7645
|
+
body: null,
|
|
7646
|
+
exceptionType: null,
|
|
7647
|
+
message: null,
|
|
7648
|
+
component: null,
|
|
7649
|
+
renderTree: null,
|
|
7650
|
+
delegateTarget: null,
|
|
7651
|
+
emitEvent: null,
|
|
7652
|
+
location: range
|
|
7653
|
+
},
|
|
7654
|
+
effects: [],
|
|
7655
|
+
location: range,
|
|
7656
|
+
isDefault: false
|
|
7657
|
+
}
|
|
7658
|
+
];
|
|
7659
|
+
}
|
|
7257
7660
|
function unreadRoleReadings(parameters, range) {
|
|
7258
7661
|
if (!parameters.some((parameter) => parameter.role === null)) {
|
|
7259
7662
|
return [];
|
|
@@ -7320,10 +7723,7 @@ function readParameters(definitionNode, reading, skipReceiverParam) {
|
|
|
7320
7723
|
}
|
|
7321
7724
|
const out = [];
|
|
7322
7725
|
let position = 0;
|
|
7323
|
-
for (const param of parametersNode
|
|
7324
|
-
if (param === null) {
|
|
7325
|
-
continue;
|
|
7326
|
-
}
|
|
7726
|
+
for (const param of children(parametersNode)) {
|
|
7327
7727
|
if (skipReceiverParam && position === 0 && isReceiverParam(param)) {
|
|
7328
7728
|
position += 1;
|
|
7329
7729
|
continue;
|
|
@@ -7347,7 +7747,7 @@ function readParameter(param, reading, position) {
|
|
|
7347
7747
|
const { name, typeNode } = info;
|
|
7348
7748
|
const shape = typeNode !== null ? annotationToShape(typeNode, reading.scope, reading.ctx) : null;
|
|
7349
7749
|
const typeText = typeNode !== null ? typeNode.text : null;
|
|
7350
|
-
if (isInjectedParameter(param, reading)) {
|
|
7750
|
+
if (isInjectedParameter(param, reading) || isInjectedType(typeNode, reading)) {
|
|
7351
7751
|
return { name, position, role: null, typeText };
|
|
7352
7752
|
}
|
|
7353
7753
|
const declared = declaringCall(
|
|
@@ -7427,6 +7827,14 @@ function calleeName2(call) {
|
|
|
7427
7827
|
function isInjectedParameter(param, reading) {
|
|
7428
7828
|
return declaringCall(param, reading.injectedCallees, reading) !== null;
|
|
7429
7829
|
}
|
|
7830
|
+
function isInjectedType(typeNode, reading) {
|
|
7831
|
+
if (typeNode === null || reading.injectedTypes.size === 0) {
|
|
7832
|
+
return false;
|
|
7833
|
+
}
|
|
7834
|
+
const written = typeNode.type === "type" ? typeNode.namedChild(0) ?? null : typeNode;
|
|
7835
|
+
const origin = written === null ? null : originOf(written, reading.module);
|
|
7836
|
+
return origin !== null && reading.injectedTypes.has(`${origin.module}.${origin.name}`);
|
|
7837
|
+
}
|
|
7430
7838
|
function declaringCall(param, callees, reading) {
|
|
7431
7839
|
if (callees.size === 0) {
|
|
7432
7840
|
return null;
|
|
@@ -7724,7 +8132,7 @@ var DEFERRED_BODY_TYPES3 = /* @__PURE__ */ new Set(["function_definition", "lamb
|
|
|
7724
8132
|
function exitSites(root, module) {
|
|
7725
8133
|
const found = [];
|
|
7726
8134
|
const startScope = module.scopeFor.get(root.id) ?? module.moduleScope;
|
|
7727
|
-
walkDescendants4(root, startScope, {
|
|
8135
|
+
walkDescendants4(root, startScope, children, {
|
|
7728
8136
|
at: (node, scope) => {
|
|
7729
8137
|
const site = exitSiteAt(node, scope);
|
|
7730
8138
|
if (site !== null) {
|
|
@@ -7741,7 +8149,7 @@ function exitSites(root, module) {
|
|
|
7741
8149
|
return found;
|
|
7742
8150
|
}
|
|
7743
8151
|
function exitSiteAt(statement, scope) {
|
|
7744
|
-
const expression = statement.
|
|
8152
|
+
const expression = statement.namedChild(0) ?? null;
|
|
7745
8153
|
if (expression === null) {
|
|
7746
8154
|
return null;
|
|
7747
8155
|
}
|
|
@@ -7922,6 +8330,7 @@ import {
|
|
|
7922
8330
|
placeCalleeParameters,
|
|
7923
8331
|
placeCalls,
|
|
7924
8332
|
recordParameterGaps,
|
|
8333
|
+
StopList,
|
|
7925
8334
|
TargetPlacements,
|
|
7926
8335
|
unfollowedCallGap,
|
|
7927
8336
|
worthRecording
|
|
@@ -7944,7 +8353,7 @@ function argparseFlagReads(definition, module, parameterNames2) {
|
|
|
7944
8353
|
const parsers = /* @__PURE__ */ new Map();
|
|
7945
8354
|
const handedTo = /* @__PURE__ */ new Map();
|
|
7946
8355
|
const startScope = module.scopeFor.get(definition.id) ?? module.moduleScope;
|
|
7947
|
-
walkDescendants5(definition, startScope, {
|
|
8356
|
+
walkDescendants5(definition, startScope, children, {
|
|
7948
8357
|
at: (node, scope) => {
|
|
7949
8358
|
noteParser(node, scope, parsers);
|
|
7950
8359
|
noteArgument(node, parsers);
|
|
@@ -8021,6 +8430,7 @@ import {
|
|
|
8021
8430
|
calleeOutcomeOf,
|
|
8022
8431
|
calleeOutcomes,
|
|
8023
8432
|
noteKeyRead as noteKeyRead3,
|
|
8433
|
+
RECEIVER_STORE_NAME as RECEIVER_STORE_NAME2,
|
|
8024
8434
|
writtenSourcesOf
|
|
8025
8435
|
} from "@suss/resolution";
|
|
8026
8436
|
var STOP_FOR = {
|
|
@@ -8051,8 +8461,40 @@ function resolveCallee2(call, site, ctx, read) {
|
|
|
8051
8461
|
return spelling;
|
|
8052
8462
|
}
|
|
8053
8463
|
const outcome = read?.outcomes.get(spelling.key) ?? calleeOutcomeOf(ctx.facts, spelling.key);
|
|
8464
|
+
if (selfCallInMixin(call, outcome, site, ctx)) {
|
|
8465
|
+
return { kind: "stopped", reason: "selfCallInMixin" };
|
|
8466
|
+
}
|
|
8054
8467
|
return asCallee(outcome, site.owner, ctx);
|
|
8055
8468
|
}
|
|
8469
|
+
function selfCallInMixin(call, outcome, site, ctx) {
|
|
8470
|
+
if (outcome.kind !== "callerSupplied" || !outcome.key.startsWith(`${site.owner}#`)) {
|
|
8471
|
+
return false;
|
|
8472
|
+
}
|
|
8473
|
+
const callee = readThrough(field(call, "function"));
|
|
8474
|
+
const receiver = callee?.type === "attribute" ? field(callee, "object") : null;
|
|
8475
|
+
const name = callee === null ? null : field(callee, "attribute")?.text;
|
|
8476
|
+
if (receiver?.type !== "identifier" || name === void 0 || name === null) {
|
|
8477
|
+
return false;
|
|
8478
|
+
}
|
|
8479
|
+
if (outcome.key !== `${site.owner}#${receiver.text}`) {
|
|
8480
|
+
return false;
|
|
8481
|
+
}
|
|
8482
|
+
return ctx.facts.lookup("instanceOf", 0, outcome.key).some((row) => {
|
|
8483
|
+
const classKey = String(row[1]);
|
|
8484
|
+
return ctx.facts.has("plainClass", [classKey]) && !instancesHaveAttribute(ctx.facts, classKey, name);
|
|
8485
|
+
});
|
|
8486
|
+
}
|
|
8487
|
+
var FALLBACK_ATTRIBUTE = "__getattr__";
|
|
8488
|
+
function instancesHaveAttribute(facts, classKey, name) {
|
|
8489
|
+
return facts.lookup("holdsProperty", 0, classKey).some((member) => {
|
|
8490
|
+
if (String(member[1]) === FALLBACK_ATTRIBUTE) {
|
|
8491
|
+
return true;
|
|
8492
|
+
}
|
|
8493
|
+
return facts.lookup("storesProperty", 0, String(member[2])).some(
|
|
8494
|
+
(store) => String(store[1]) === name && store[3] === RECEIVER_STORE_NAME2
|
|
8495
|
+
);
|
|
8496
|
+
});
|
|
8497
|
+
}
|
|
8056
8498
|
function namedOutcomes(keys, ctx) {
|
|
8057
8499
|
return calleeOutcomes(ctx.facts, [...new Set(keys)]);
|
|
8058
8500
|
}
|
|
@@ -8602,14 +9044,14 @@ function passedNameKeys(file, call) {
|
|
|
8602
9044
|
if (args === null) {
|
|
8603
9045
|
return [];
|
|
8604
9046
|
}
|
|
8605
|
-
return args.
|
|
9047
|
+
return children(args).flatMap((arg) => {
|
|
8606
9048
|
const key = passedNameKeyOf(file, arg);
|
|
8607
9049
|
return key === null ? [] : [key];
|
|
8608
9050
|
});
|
|
8609
9051
|
}
|
|
8610
9052
|
function scanBody(source, ctx, recognized, read, implied) {
|
|
8611
9053
|
const followed = [];
|
|
8612
|
-
const stops =
|
|
9054
|
+
const stops = new StopList();
|
|
8613
9055
|
const placements = new TargetPlacements();
|
|
8614
9056
|
const parameterCalls = [];
|
|
8615
9057
|
const passedPositions = /* @__PURE__ */ new Set();
|
|
@@ -8626,7 +9068,7 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8626
9068
|
if (args === null) {
|
|
8627
9069
|
return;
|
|
8628
9070
|
}
|
|
8629
|
-
args.
|
|
9071
|
+
children(args).forEach((arg, position) => {
|
|
8630
9072
|
const nameKey2 = passedNameKeyOf(file, arg);
|
|
8631
9073
|
if (nameKey2 === null) {
|
|
8632
9074
|
return;
|
|
@@ -8659,10 +9101,12 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8659
9101
|
outcome.kind === "followed" ? keyOf2(outcome.target) : null
|
|
8660
9102
|
);
|
|
8661
9103
|
if (outcome.kind === "stopped") {
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
9104
|
+
if (!recognized.has(call.id) && worthRecording(outcome.reason)) {
|
|
9105
|
+
stops.add({
|
|
9106
|
+
callee,
|
|
9107
|
+
reason: outcome.reason,
|
|
9108
|
+
...resultUsedAsValue(call) ? { usedAsValue: true } : {}
|
|
9109
|
+
});
|
|
8666
9110
|
}
|
|
8667
9111
|
if (outcome.reason === "callerSupplied" && !parameterCallsSeen.has(callee)) {
|
|
8668
9112
|
const parameterIndex = ownParameters.indexOf(callee);
|
|
@@ -8695,7 +9139,7 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8695
9139
|
}
|
|
8696
9140
|
return {
|
|
8697
9141
|
followed,
|
|
8698
|
-
stops,
|
|
9142
|
+
stops: stops.stops,
|
|
8699
9143
|
targets: placements.targets,
|
|
8700
9144
|
argTargets: placements.argTargets,
|
|
8701
9145
|
parameterCalls,
|
|
@@ -8704,7 +9148,7 @@ function scanBody(source, ctx, recognized, read, implied) {
|
|
|
8704
9148
|
}
|
|
8705
9149
|
function callsWritten(file, body, outer, owner, limit) {
|
|
8706
9150
|
const found = [];
|
|
8707
|
-
walkDescendants6(body, outer, {
|
|
9151
|
+
walkDescendants6(body, outer, children, {
|
|
8708
9152
|
at: (child, scope) => {
|
|
8709
9153
|
if (child.type === "call") {
|
|
8710
9154
|
found.push({ call: child, site: { file, scope, owner } });
|
|
@@ -8730,7 +9174,7 @@ function identifiersUnder(node, found = []) {
|
|
|
8730
9174
|
found.push(node.text);
|
|
8731
9175
|
return found;
|
|
8732
9176
|
}
|
|
8733
|
-
for (const child of node
|
|
9177
|
+
for (const child of children(node)) {
|
|
8734
9178
|
if (child !== null && child.type !== "attribute" && child.type !== "subscript") {
|
|
8735
9179
|
identifiersUnder(child, found);
|
|
8736
9180
|
}
|
|
@@ -8831,10 +9275,7 @@ function positionalParameters(node, isMethod2) {
|
|
|
8831
9275
|
}
|
|
8832
9276
|
const out = [];
|
|
8833
9277
|
let position = 0;
|
|
8834
|
-
for (const param of parameters
|
|
8835
|
-
if (param === null) {
|
|
8836
|
-
continue;
|
|
8837
|
-
}
|
|
9278
|
+
for (const param of children(parameters)) {
|
|
8838
9279
|
const name = parameterName2(param);
|
|
8839
9280
|
if (name === null) {
|
|
8840
9281
|
continue;
|
|
@@ -8854,10 +9295,7 @@ function callParameterNames(node, isMethod2) {
|
|
|
8854
9295
|
return [];
|
|
8855
9296
|
}
|
|
8856
9297
|
const names = [];
|
|
8857
|
-
for (const param of parameters
|
|
8858
|
-
if (param === null) {
|
|
8859
|
-
continue;
|
|
8860
|
-
}
|
|
9298
|
+
for (const param of children(parameters)) {
|
|
8861
9299
|
const name = parameterName2(param);
|
|
8862
9300
|
if (name === null) {
|
|
8863
9301
|
continue;
|
|
@@ -8954,7 +9392,7 @@ function exportsOf(file, node, exportName) {
|
|
|
8954
9392
|
if (node.type !== "class_definition" || body === null) {
|
|
8955
9393
|
return [];
|
|
8956
9394
|
}
|
|
8957
|
-
return body.
|
|
9395
|
+
return children(body).flatMap((child) => {
|
|
8958
9396
|
if (child === null) {
|
|
8959
9397
|
return [];
|
|
8960
9398
|
}
|
|
@@ -9077,6 +9515,11 @@ function watchRouterIndex(index, db, positions, fileOfModule) {
|
|
|
9077
9515
|
found
|
|
9078
9516
|
);
|
|
9079
9517
|
return found;
|
|
9518
|
+
},
|
|
9519
|
+
// The wrapper index notes what it reads through the mounts, in terms
|
|
9520
|
+
// it can look up again.
|
|
9521
|
+
mountsAbove(pattern, constructionKey) {
|
|
9522
|
+
return index.mountsAbove(pattern, constructionKey);
|
|
9080
9523
|
}
|
|
9081
9524
|
};
|
|
9082
9525
|
}
|
|
@@ -9181,9 +9624,33 @@ function buildRouterIndex(files, packs, resolverOptions) {
|
|
|
9181
9624
|
};
|
|
9182
9625
|
}
|
|
9183
9626
|
return NOT_ROUTER;
|
|
9627
|
+
},
|
|
9628
|
+
mountsAbove(pattern, constructionKey) {
|
|
9629
|
+
const index = byPattern.get(pattern);
|
|
9630
|
+
return index === void 0 ? null : hopsAbove(index, constructionKey);
|
|
9184
9631
|
}
|
|
9185
9632
|
};
|
|
9186
9633
|
}
|
|
9634
|
+
function hopsAbove(index, key) {
|
|
9635
|
+
const hops = [];
|
|
9636
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9637
|
+
let current = key;
|
|
9638
|
+
while (current !== null) {
|
|
9639
|
+
const construction = index.byValueKey.get(current);
|
|
9640
|
+
if (construction === void 0 || seen.has(current)) {
|
|
9641
|
+
return null;
|
|
9642
|
+
}
|
|
9643
|
+
seen.add(current);
|
|
9644
|
+
const states = index.mounts.get(construction) ?? [];
|
|
9645
|
+
const only = states.length === 1 ? states[0] : void 0;
|
|
9646
|
+
if (only?.kind !== "mounted" || only.written === void 0) {
|
|
9647
|
+
return null;
|
|
9648
|
+
}
|
|
9649
|
+
hops.push({ ...only.written, parentKey: only.parentValueKey });
|
|
9650
|
+
current = only.parentValueKey;
|
|
9651
|
+
}
|
|
9652
|
+
return hops;
|
|
9653
|
+
}
|
|
9187
9654
|
function composedPrefixOf(index, construction, routerPath) {
|
|
9188
9655
|
const ownPrefix = composedOwnPrefix(construction.prefix, index.composition);
|
|
9189
9656
|
if (ownPrefix.kind === "abstain") {
|
|
@@ -9466,8 +9933,8 @@ function constructionStatement(stmt, module, importModule) {
|
|
|
9466
9933
|
if (stmt.type !== "expression_statement") {
|
|
9467
9934
|
return null;
|
|
9468
9935
|
}
|
|
9469
|
-
const assignment2 = stmt.
|
|
9470
|
-
(child) => child
|
|
9936
|
+
const assignment2 = children(stmt).find(
|
|
9937
|
+
(child) => child.type === "assignment"
|
|
9471
9938
|
);
|
|
9472
9939
|
if (assignment2 === void 0) {
|
|
9473
9940
|
return null;
|
|
@@ -9541,7 +10008,7 @@ function collectReturnedConstructions(bound, importModule, composition, index) {
|
|
|
9541
10008
|
if (inner.type !== "return_statement") {
|
|
9542
10009
|
continue;
|
|
9543
10010
|
}
|
|
9544
|
-
const returned = inner.
|
|
10011
|
+
const returned = inner.namedChild(0);
|
|
9545
10012
|
if (returned?.type !== "call") {
|
|
9546
10013
|
continue;
|
|
9547
10014
|
}
|
|
@@ -9721,7 +10188,7 @@ function sequenceElementNames(node) {
|
|
|
9721
10188
|
return null;
|
|
9722
10189
|
}
|
|
9723
10190
|
const names = [];
|
|
9724
|
-
for (const child of node
|
|
10191
|
+
for (const child of children(node)) {
|
|
9725
10192
|
if (child?.type !== "identifier") {
|
|
9726
10193
|
return null;
|
|
9727
10194
|
}
|
|
@@ -9934,8 +10401,9 @@ function recordMountStatement(stmt, position, scan) {
|
|
|
9934
10401
|
scan.index.facts
|
|
9935
10402
|
);
|
|
9936
10403
|
const mounted = args[0] ?? (scan.composition.routerKeyword === void 0 ? void 0 : keywordArgs[scan.composition.routerKeyword]);
|
|
10404
|
+
const recorded = state.kind === "mounted" ? { ...state, written: { call: mountCall.call, file: scan.bound.file } } : state;
|
|
9937
10405
|
for (const target of mountedConstructions(mounted, position, scan)) {
|
|
9938
|
-
recordMount(scan.index, target,
|
|
10406
|
+
recordMount(scan.index, target, recorded);
|
|
9939
10407
|
}
|
|
9940
10408
|
}
|
|
9941
10409
|
function mountStateOf(includerConstructorName, includer, keywordArgs, objectPrefix, composition, site, facts) {
|
|
@@ -11047,6 +11515,8 @@ import { absentReading as absentReading2, walkDescendants as walkDescendants7 }
|
|
|
11047
11515
|
import { noteKeyRead as noteKeyRead6, noteLookup as noteLookup3 } from "@suss/resolution";
|
|
11048
11516
|
var EVERY_ROUTE = "wrapEvery ";
|
|
11049
11517
|
var OWN_ROUTES = "wrapOwn ";
|
|
11518
|
+
var MOUNTED = "wrapMounted ";
|
|
11519
|
+
var MOUNTED_SEPARATOR = "\0";
|
|
11050
11520
|
function describeRegistered(found) {
|
|
11051
11521
|
return (found ?? []).map(
|
|
11052
11522
|
({ reference }) => `${reference.file}:${reference.name}:${reference.onThrow === true}`
|
|
@@ -11084,6 +11554,10 @@ var PythonWrapperIndex = class {
|
|
|
11084
11554
|
/** By construction key: what a router or a blueprint registered. */
|
|
11085
11555
|
ownRoutes = /* @__PURE__ */ new Map();
|
|
11086
11556
|
unitsByKey = /* @__PURE__ */ new Map();
|
|
11557
|
+
/** By pack name: the app constructions its routes run under. */
|
|
11558
|
+
appCalls = /* @__PURE__ */ new Map();
|
|
11559
|
+
/** By wrapper reference: the parameters a dependency function declares, and its file. */
|
|
11560
|
+
dependencyParameterTable = /* @__PURE__ */ new Map();
|
|
11087
11561
|
unitsByFile = /* @__PURE__ */ new Map();
|
|
11088
11562
|
/** Told about every registration, so a cache can repeat the ones a file's discovery made. */
|
|
11089
11563
|
onRegistered = null;
|
|
@@ -11102,6 +11576,12 @@ var PythonWrapperIndex = class {
|
|
|
11102
11576
|
this.ownRoutes.get(id.slice(OWN_ROUTES.length))
|
|
11103
11577
|
);
|
|
11104
11578
|
}
|
|
11579
|
+
if (id.startsWith(MOUNTED)) {
|
|
11580
|
+
const [packName, position, key] = id.slice(MOUNTED.length).split(MOUNTED_SEPARATOR);
|
|
11581
|
+
const pack = this.options.packs.find((one) => one.name === packName);
|
|
11582
|
+
const pattern = pack?.discovery[Number(position)];
|
|
11583
|
+
return pack === void 0 || pattern === void 0 || key === void 0 ? describeRegistered([]) : describeRegistered(this.registeredAbove(pack, pattern, key));
|
|
11584
|
+
}
|
|
11105
11585
|
return null;
|
|
11106
11586
|
}
|
|
11107
11587
|
noted(kind, key, found) {
|
|
@@ -11143,14 +11623,46 @@ var PythonWrapperIndex = class {
|
|
|
11143
11623
|
inFile.push(unit);
|
|
11144
11624
|
this.unitsByFile.set(target.file.file, inFile);
|
|
11145
11625
|
}
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
...isThrowForm(declared.form) ? { onThrow: true } : {}
|
|
11151
|
-
},
|
|
11152
|
-
form: declared.form
|
|
11626
|
+
const reference = {
|
|
11627
|
+
file: target.file.displayPath,
|
|
11628
|
+
name: target.name,
|
|
11629
|
+
...isThrowForm(declared.form) ? { onThrow: true } : {}
|
|
11153
11630
|
};
|
|
11631
|
+
if (declared.form.type === "dependency") {
|
|
11632
|
+
this.dependencyParameterTable.set(referenceKey(reference), {
|
|
11633
|
+
file: target.file.file,
|
|
11634
|
+
names: parameterNamesOf(target.node),
|
|
11635
|
+
declaresSource: declaresSourcedParameter(
|
|
11636
|
+
target.node,
|
|
11637
|
+
Object.keys(declared.pattern.parameterSources ?? {})
|
|
11638
|
+
)
|
|
11639
|
+
});
|
|
11640
|
+
}
|
|
11641
|
+
return { reference, form: declared.form };
|
|
11642
|
+
}
|
|
11643
|
+
/**
|
|
11644
|
+
* The parameters the dependencies among these wrappers declare, and
|
|
11645
|
+
* whether one is declared through a parameter source such as `Query()`.
|
|
11646
|
+
* The library fills those from the request and validates them, the same
|
|
11647
|
+
* as parameters the route declares.
|
|
11648
|
+
*/
|
|
11649
|
+
dependencyParameters(references) {
|
|
11650
|
+
const names = /* @__PURE__ */ new Set();
|
|
11651
|
+
let declaresSource = false;
|
|
11652
|
+
for (const reference of references) {
|
|
11653
|
+
const found = this.dependencyParameterTable.get(referenceKey(reference));
|
|
11654
|
+
if (found === void 0) {
|
|
11655
|
+
continue;
|
|
11656
|
+
}
|
|
11657
|
+
if (this.options.facts !== void 0) {
|
|
11658
|
+
noteKeyRead6(this.options.facts, found.file);
|
|
11659
|
+
}
|
|
11660
|
+
for (const name of found.names) {
|
|
11661
|
+
names.add(name);
|
|
11662
|
+
}
|
|
11663
|
+
declaresSource ||= found.declaresSource;
|
|
11664
|
+
}
|
|
11665
|
+
return { names, declaresSource };
|
|
11154
11666
|
}
|
|
11155
11667
|
wrappersFor(query) {
|
|
11156
11668
|
const file = this.filesByPath.get(query.file);
|
|
@@ -11162,13 +11674,15 @@ var PythonWrapperIndex = class {
|
|
|
11162
11674
|
if (file === void 0 || forms.length === 0) {
|
|
11163
11675
|
return [];
|
|
11164
11676
|
}
|
|
11677
|
+
const own = this.ownRoutesOf(query);
|
|
11165
11678
|
const found = [
|
|
11166
11679
|
...this.noted(
|
|
11167
11680
|
EVERY_ROUTE,
|
|
11168
11681
|
query.pack.name,
|
|
11169
11682
|
this.everyRoute.get(query.pack.name)
|
|
11170
11683
|
),
|
|
11171
|
-
...this.
|
|
11684
|
+
...own === null ? [] : this.mountedAbove(query, own.key),
|
|
11685
|
+
...own?.registered ?? []
|
|
11172
11686
|
];
|
|
11173
11687
|
for (const declared of forms) {
|
|
11174
11688
|
if (declared.form.type !== "dependency") {
|
|
@@ -11199,11 +11713,65 @@ var PythonWrapperIndex = class {
|
|
|
11199
11713
|
}
|
|
11200
11714
|
return ordered;
|
|
11201
11715
|
}
|
|
11716
|
+
/**
|
|
11717
|
+
* What the mounts above the route's router register on the way down:
|
|
11718
|
+
* the dependencies an `include_router` call lists, and those of each
|
|
11719
|
+
* router it is mounted onto, outermost first, the order they run in.
|
|
11720
|
+
*/
|
|
11721
|
+
mountedAbove(query, key) {
|
|
11722
|
+
const position = query.pack.discovery.indexOf(query.pattern);
|
|
11723
|
+
return [
|
|
11724
|
+
...this.noted(
|
|
11725
|
+
MOUNTED,
|
|
11726
|
+
[query.pack.name, position, key].join(MOUNTED_SEPARATOR),
|
|
11727
|
+
this.registeredAbove(query.pack, query.pattern, key)
|
|
11728
|
+
)
|
|
11729
|
+
];
|
|
11730
|
+
}
|
|
11731
|
+
registeredAbove(pack, pattern, key) {
|
|
11732
|
+
const hops = this.options.routers?.mountsAbove(pattern, key) ?? null;
|
|
11733
|
+
if (hops === null) {
|
|
11734
|
+
return [];
|
|
11735
|
+
}
|
|
11736
|
+
const forms = (pattern.wrappers ?? []).flatMap(
|
|
11737
|
+
(form) => form.type === "dependency" ? [{ pack, pattern, form }] : []
|
|
11738
|
+
);
|
|
11739
|
+
const found = [];
|
|
11740
|
+
for (const hop of [...hops].reverse()) {
|
|
11741
|
+
found.push(
|
|
11742
|
+
...hop.parentKey === null ? [] : this.ownRoutes.get(hop.parentKey) ?? []
|
|
11743
|
+
);
|
|
11744
|
+
const { keywordArgs } = readCallArguments(field(hop.call, "arguments"));
|
|
11745
|
+
for (const declared of forms) {
|
|
11746
|
+
const listed = keywordArgs[declared.form.keyword];
|
|
11747
|
+
const names = listed === void 0 ? [] : dependencyNamesIn(listed.node, declared.form);
|
|
11748
|
+
for (const name of names) {
|
|
11749
|
+
const target = this.functionCalled(hop.file, name);
|
|
11750
|
+
if (target !== null) {
|
|
11751
|
+
found.push(this.registered(target, declared));
|
|
11752
|
+
}
|
|
11753
|
+
}
|
|
11754
|
+
}
|
|
11755
|
+
}
|
|
11756
|
+
return found;
|
|
11757
|
+
}
|
|
11202
11758
|
ownRoutesOf(query) {
|
|
11759
|
+
const match = this.ownRouterOf(query);
|
|
11760
|
+
return match === null ? null : {
|
|
11761
|
+
key: match.key,
|
|
11762
|
+
registered: this.noted(
|
|
11763
|
+
OWN_ROUTES,
|
|
11764
|
+
match.key,
|
|
11765
|
+
this.ownRoutes.get(match.key)
|
|
11766
|
+
)
|
|
11767
|
+
};
|
|
11768
|
+
}
|
|
11769
|
+
/** The construction call of the router a route is decorated on, when a registrar reads it. */
|
|
11770
|
+
ownRouterOf(query) {
|
|
11203
11771
|
const site = this.objectSiteOf(query);
|
|
11204
11772
|
const bound = site === null ? void 0 : this.filesByPath.get(site.file);
|
|
11205
11773
|
if (site === null || bound === void 0) {
|
|
11206
|
-
return
|
|
11774
|
+
return null;
|
|
11207
11775
|
}
|
|
11208
11776
|
if (this.options.facts !== void 0) {
|
|
11209
11777
|
noteKeyRead6(this.options.facts, site.file);
|
|
@@ -11217,12 +11785,46 @@ var PythonWrapperIndex = class {
|
|
|
11217
11785
|
{ pack: query.pack, pattern: query.pattern, form }
|
|
11218
11786
|
);
|
|
11219
11787
|
if (match !== null && match.registrar.covers === "ownRoutes") {
|
|
11220
|
-
return
|
|
11221
|
-
...this.noted(OWN_ROUTES, match.key, this.ownRoutes.get(match.key))
|
|
11222
|
-
];
|
|
11788
|
+
return match;
|
|
11223
11789
|
}
|
|
11224
11790
|
}
|
|
11225
|
-
return
|
|
11791
|
+
return null;
|
|
11792
|
+
}
|
|
11793
|
+
/** Records the app a pack's routes run under, for the keywords written on its construction. */
|
|
11794
|
+
recordApp(pack, call, file) {
|
|
11795
|
+
const calls = this.appCalls.get(pack) ?? [];
|
|
11796
|
+
if (!calls.some((one) => one.call === call)) {
|
|
11797
|
+
calls.push({ call, file });
|
|
11798
|
+
}
|
|
11799
|
+
this.appCalls.set(pack, calls);
|
|
11800
|
+
}
|
|
11801
|
+
/**
|
|
11802
|
+
* Every call that registers something for a route on the way to it:
|
|
11803
|
+
* the app's construction, the mount calls and the routers they mount
|
|
11804
|
+
* onto, and the route's own router. A caller reads a keyword off each.
|
|
11805
|
+
*/
|
|
11806
|
+
callsAbove(query) {
|
|
11807
|
+
const own = this.ownRouterOf(query);
|
|
11808
|
+
const hops = own === null ? [] : this.options.routers?.mountsAbove(query.pattern, own.key) ?? [];
|
|
11809
|
+
const parents = hops.flatMap((hop) => {
|
|
11810
|
+
const node = hop.parentKey === null ? null : nodeOfResolutionKey(hop.parentKey, this.options.facts);
|
|
11811
|
+
return node === null ? [] : [node];
|
|
11812
|
+
});
|
|
11813
|
+
const files = [
|
|
11814
|
+
...(this.appCalls.get(query.pack.name) ?? []).map((one) => one.file),
|
|
11815
|
+
...hops.map((hop) => hop.file)
|
|
11816
|
+
];
|
|
11817
|
+
if (this.options.facts !== void 0) {
|
|
11818
|
+
for (const file of files) {
|
|
11819
|
+
noteKeyRead6(this.options.facts, file);
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
return [
|
|
11823
|
+
...(this.appCalls.get(query.pack.name) ?? []).map((one) => one.call),
|
|
11824
|
+
...hops.map((hop) => hop.call),
|
|
11825
|
+
...parents,
|
|
11826
|
+
...own === null ? [] : [own.call]
|
|
11827
|
+
];
|
|
11226
11828
|
}
|
|
11227
11829
|
/**
|
|
11228
11830
|
* Where the decorator's object was built: the route's own file, the file
|
|
@@ -11267,6 +11869,23 @@ var PythonWrapperIndex = class {
|
|
|
11267
11869
|
return this.unitsByFile.get(file) ?? [];
|
|
11268
11870
|
}
|
|
11269
11871
|
};
|
|
11872
|
+
function referenceKey(reference) {
|
|
11873
|
+
return `${reference.file}::${reference.name}`;
|
|
11874
|
+
}
|
|
11875
|
+
function parameterNamesOf(definition) {
|
|
11876
|
+
return children(field(definition, "parameters")).flatMap((parameter) => {
|
|
11877
|
+
const named = parameterNameAndType(parameter);
|
|
11878
|
+
return named === null ? [] : [named.name];
|
|
11879
|
+
});
|
|
11880
|
+
}
|
|
11881
|
+
function declaresSourcedParameter(definition, sources) {
|
|
11882
|
+
return children(field(definition, "parameters")).some((parameter) => {
|
|
11883
|
+
const value = field(parameter, "value");
|
|
11884
|
+
const callee = value?.type === "call" ? field(value, "function") : null;
|
|
11885
|
+
const name = callee?.type === "attribute" ? field(callee, "attribute")?.text : callee?.text;
|
|
11886
|
+
return name !== void 0 && sources.includes(name);
|
|
11887
|
+
});
|
|
11888
|
+
}
|
|
11270
11889
|
function isThrowForm(form) {
|
|
11271
11890
|
return form.type === "decoratedWrapper" && form.throwParam !== void 0;
|
|
11272
11891
|
}
|
|
@@ -11313,8 +11932,8 @@ function registerFrom(file, declared, index) {
|
|
|
11313
11932
|
}
|
|
11314
11933
|
function registerConstructorDependencies(file, declared, form, index) {
|
|
11315
11934
|
const scope = file.module.moduleScope;
|
|
11316
|
-
for (const stmt of file.root
|
|
11317
|
-
const assignment2 = stmt?.type === "expression_statement" ? stmt.
|
|
11935
|
+
for (const stmt of children(file.root)) {
|
|
11936
|
+
const assignment2 = stmt?.type === "expression_statement" ? children(stmt).find((child) => child?.type === "assignment") : void 0;
|
|
11318
11937
|
const left = assignment2 === void 0 || assignment2 === null ? null : field(assignment2, "left");
|
|
11319
11938
|
if (left?.type !== "identifier") {
|
|
11320
11939
|
continue;
|
|
@@ -11329,6 +11948,9 @@ function registerConstructorDependencies(file, declared, form, index) {
|
|
|
11329
11948
|
if (match === null) {
|
|
11330
11949
|
continue;
|
|
11331
11950
|
}
|
|
11951
|
+
if (match.registrar.covers === "everyRoute") {
|
|
11952
|
+
index.recordApp(declared.pack.name, match.call, file.file);
|
|
11953
|
+
}
|
|
11332
11954
|
const { keywordArgs } = readCallArguments(field(match.call, "arguments"));
|
|
11333
11955
|
const listed = keywordArgs[form.keyword];
|
|
11334
11956
|
if (listed === void 0) {
|
|
@@ -11346,7 +11968,7 @@ function coverageOf(match, pack) {
|
|
|
11346
11968
|
return match.registrar.covers === "everyRoute" ? { kind: "everyRoute", pack: pack.name } : { kind: "ownRoutes", key: match.key };
|
|
11347
11969
|
}
|
|
11348
11970
|
function registerDecorated(file, declared, form, index) {
|
|
11349
|
-
walkDescendants7(file.root, file.module.moduleScope, {
|
|
11971
|
+
walkDescendants7(file.root, file.module.moduleScope, children, {
|
|
11350
11972
|
at: (node, scope) => {
|
|
11351
11973
|
if (node.type !== "decorated_definition") {
|
|
11352
11974
|
return;
|
|
@@ -11382,7 +12004,7 @@ function registerDecorated(file, declared, form, index) {
|
|
|
11382
12004
|
});
|
|
11383
12005
|
}
|
|
11384
12006
|
function dependencyNamesIn(node, form) {
|
|
11385
|
-
const calls = node.type === "list" ? node
|
|
12007
|
+
const calls = node.type === "list" ? children(node) : [node];
|
|
11386
12008
|
const names = [];
|
|
11387
12009
|
for (const call of calls) {
|
|
11388
12010
|
const name = call === null ? null : dependencyNameOf(call, form);
|
|
@@ -11401,7 +12023,7 @@ function dependencyNameOf(node, form) {
|
|
|
11401
12023
|
if (calleeName3 === null || !form.callees.includes(calleeName3)) {
|
|
11402
12024
|
return null;
|
|
11403
12025
|
}
|
|
11404
|
-
const first = field(node, "arguments")?.
|
|
12026
|
+
const first = field(node, "arguments")?.namedChild(0);
|
|
11405
12027
|
return first?.type === "identifier" ? first.text : null;
|
|
11406
12028
|
}
|
|
11407
12029
|
function decoratorDependencies(classification, form) {
|
|
@@ -11419,7 +12041,7 @@ function parameterDependencies(definitionNode, form) {
|
|
|
11419
12041
|
if (direct !== null) {
|
|
11420
12042
|
return direct;
|
|
11421
12043
|
}
|
|
11422
|
-
for (const child of node
|
|
12044
|
+
for (const child of children(node)) {
|
|
11423
12045
|
const found = findIn(child, depth + 1);
|
|
11424
12046
|
if (found !== null) {
|
|
11425
12047
|
return found;
|
|
@@ -11427,10 +12049,7 @@ function parameterDependencies(definitionNode, form) {
|
|
|
11427
12049
|
}
|
|
11428
12050
|
return null;
|
|
11429
12051
|
};
|
|
11430
|
-
for (const param of field(definitionNode, "parameters")
|
|
11431
|
-
if (param === null) {
|
|
11432
|
-
continue;
|
|
11433
|
-
}
|
|
12052
|
+
for (const param of children(field(definitionNode, "parameters"))) {
|
|
11434
12053
|
const inDefault = field(param, "value");
|
|
11435
12054
|
const found = inDefault === null ? findIn(field(param, "type"), 0) : dependencyNameOf(inDefault, form);
|
|
11436
12055
|
if (found !== null) {
|
|
@@ -11446,7 +12065,8 @@ function wrapperUnit(target, declared, options) {
|
|
|
11446
12065
|
const raised = raisedResponses(body, {
|
|
11447
12066
|
calls: declared.pattern.responseStatusCalls ?? [],
|
|
11448
12067
|
module: file.module,
|
|
11449
|
-
facts: options.facts
|
|
12068
|
+
facts: options.facts,
|
|
12069
|
+
constants: declared.pattern.statusCodeConstants ?? {}
|
|
11450
12070
|
});
|
|
11451
12071
|
const continuations = continuationStatements(node, declared.form);
|
|
11452
12072
|
const terminals = bodyTerminals(body, raised, continuations);
|
|
@@ -11530,7 +12150,7 @@ function returnHandsOn(statement, form) {
|
|
|
11530
12150
|
return false;
|
|
11531
12151
|
}
|
|
11532
12152
|
if (form.returnedValueResponds === true) {
|
|
11533
|
-
const returned = statement.
|
|
12153
|
+
const returned = statement.namedChild(0);
|
|
11534
12154
|
return returned === void 0 || returned === null || returned.type === "none";
|
|
11535
12155
|
}
|
|
11536
12156
|
return true;
|
|
@@ -11539,9 +12159,7 @@ function continuationStatements(node, form) {
|
|
|
11539
12159
|
if (form.type !== "decoratedWrapper" || form.continuationParam === void 0) {
|
|
11540
12160
|
return [];
|
|
11541
12161
|
}
|
|
11542
|
-
const params = (field(node, "parameters")
|
|
11543
|
-
(param2) => param2 !== null
|
|
11544
|
-
);
|
|
12162
|
+
const params = children(field(node, "parameters"));
|
|
11545
12163
|
const param = params[form.continuationParam];
|
|
11546
12164
|
const continuation = param === void 0 ? null : field(param, "name")?.text ?? (param.type === "identifier" ? param.text : null);
|
|
11547
12165
|
if (continuation === null) {
|
|
@@ -11842,7 +12460,8 @@ async function runPython(options, roots, cache, previous) {
|
|
|
11842
12460
|
roots,
|
|
11843
12461
|
facts: needsValues ? db : void 0,
|
|
11844
12462
|
definitions,
|
|
11845
|
-
storageFor
|
|
12463
|
+
storageFor,
|
|
12464
|
+
routers: plainRouterIndex
|
|
11846
12465
|
})
|
|
11847
12466
|
);
|
|
11848
12467
|
const importedDefinition2 = importedDefinitionLookup(db, bound);
|
|
@@ -12285,7 +12904,7 @@ function indexDefinitions(into, file, node) {
|
|
|
12285
12904
|
if (isFunction(node)) {
|
|
12286
12905
|
into.set(nodeId(file, node), node);
|
|
12287
12906
|
}
|
|
12288
|
-
for (const child of node
|
|
12907
|
+
for (const child of children(node)) {
|
|
12289
12908
|
if (child !== null) {
|
|
12290
12909
|
indexDefinitions(into, file, child);
|
|
12291
12910
|
}
|
|
@@ -12551,7 +13170,7 @@ function importSitesIn(root) {
|
|
|
12551
13170
|
found.push({ module: entry.module, name: entry.name, line });
|
|
12552
13171
|
}
|
|
12553
13172
|
}
|
|
12554
|
-
for (const child of node
|
|
13173
|
+
for (const child of children(node)) {
|
|
12555
13174
|
if (child !== null) {
|
|
12556
13175
|
visit(child);
|
|
12557
13176
|
}
|