carrick 0.3.126 → 0.3.128
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/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/sidecar/dist/src/capture/anchors.js +5 -1
- package/sidecar/dist/src/capture/check-classify.d.ts +8 -1
- package/sidecar/dist/src/capture/check-classify.js +21 -1
- package/sidecar/dist/src/capture/check-probe.d.ts +7 -7
- package/sidecar/dist/src/capture/check-probe.js +13 -14
- package/sidecar/dist/src/capture/check.js +5 -5
- package/sidecar/dist/src/index.js +56 -4
- package/sidecar/dist/src/library-claims.d.ts +63 -3
- package/sidecar/dist/src/library-claims.js +435 -44
- package/sidecar/dist/src/retype.js +124 -8
- package/sidecar/dist/src/server-labels.d.ts +29 -0
- package/sidecar/dist/src/server-labels.js +45 -0
- package/sidecar/dist/src/stated-params.d.ts +138 -0
- package/sidecar/dist/src/stated-params.js +547 -0
- package/sidecar/dist/src/type-inferrer.d.ts +144 -8
- package/sidecar/dist/src/type-inferrer.js +635 -35
- package/sidecar/dist/src/types.d.ts +84 -3
- package/sidecar/dist/src/unwidened.d.ts +11 -2
- package/sidecar/dist/src/unwidened.js +50 -3
- package/sidecar/dist/src/validators.d.ts +228 -59
- package/sidecar/dist/src/validators.js +45 -2
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { Node, SyntaxKind, ts } from 'ts-morph';
|
|
28
28
|
import { readsResponseStatus, statusesIn, SUCCEEDED, testsOnPath, } from './failure-path.js';
|
|
29
|
+
import { statesNoBody } from './capture/index.js';
|
|
29
30
|
import { lineIndex } from './line-index.js';
|
|
30
31
|
import { typeToStringAsDeclared } from './print-type.js';
|
|
31
32
|
import { fileDiagnostics } from './unwidened.js';
|
|
@@ -469,6 +470,9 @@ function resultEscapes(call, throughCasts = false) {
|
|
|
469
470
|
(throughCasts && Node.isAsExpression(top.getParentOrThrow()))) {
|
|
470
471
|
top = top.getParentOrThrow();
|
|
471
472
|
}
|
|
473
|
+
if (returnedFromNoBodyFunction(top)) {
|
|
474
|
+
return 'the response is returned from a function that declares it returns no body, so there is no body to judge';
|
|
475
|
+
}
|
|
472
476
|
if (returnsUndeclared(top)) {
|
|
473
477
|
return 'the response is returned from a function with no declared return type, so its readers are elsewhere';
|
|
474
478
|
}
|
|
@@ -493,6 +497,38 @@ function resultEscapes(call, throughCasts = false) {
|
|
|
493
497
|
}
|
|
494
498
|
return undefined;
|
|
495
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* `top` is returned whole from a function whose declared return states no
|
|
502
|
+
* body (carrick#2743): `Promise<void>`, `Promise<undefined>`, or a reference
|
|
503
|
+
* every written type argument of which is one of those
|
|
504
|
+
* (`Promise<ClientResponse<void>>`). In source the compiler takes a client's
|
|
505
|
+
* free result parameter from that return position, so the file compiles;
|
|
506
|
+
* the retype's written type argument turns that inference off and the
|
|
507
|
+
* declared return then reports the default response object. That is a
|
|
508
|
+
* diagnostic about the written argument, not a body anyone reads.
|
|
509
|
+
*/
|
|
510
|
+
function returnedFromNoBodyFunction(top) {
|
|
511
|
+
const parent = top.getParent();
|
|
512
|
+
const fn = Node.isReturnStatement(parent)
|
|
513
|
+
? parent.getFirstAncestor((n) => Node.isFunctionDeclaration(n) ||
|
|
514
|
+
Node.isFunctionExpression(n) ||
|
|
515
|
+
Node.isArrowFunction(n) ||
|
|
516
|
+
Node.isMethodDeclaration(n))
|
|
517
|
+
: Node.isArrowFunction(parent)
|
|
518
|
+
? parent
|
|
519
|
+
: undefined;
|
|
520
|
+
let declared = Node.isReturnTyped(fn) ? fn.getReturnTypeNode() : undefined;
|
|
521
|
+
while (Node.isTypeReference(declared) &&
|
|
522
|
+
['Promise', 'PromiseLike'].includes(declared.getTypeName().getText())) {
|
|
523
|
+
declared = declared.getTypeArguments()[0];
|
|
524
|
+
}
|
|
525
|
+
if (!declared)
|
|
526
|
+
return false;
|
|
527
|
+
if (statesNoBody(declared.getType().compilerType))
|
|
528
|
+
return true;
|
|
529
|
+
const args = Node.isTypeReference(declared) ? declared.getTypeArguments() : [];
|
|
530
|
+
return args.length > 0 && args.every((arg) => statesNoBody(arg.getType().compilerType));
|
|
531
|
+
}
|
|
496
532
|
/** `node` is (part of) what a function with an inferred return type returns. */
|
|
497
533
|
function returnsUndeclared(node) {
|
|
498
534
|
for (let at = node; at; at = at.getParent()) {
|
|
@@ -548,14 +584,8 @@ function bodyReadsOf(call) {
|
|
|
548
584
|
const chained = bodyReadOn(top);
|
|
549
585
|
if (chained)
|
|
550
586
|
return checkedBodyReads([chained]);
|
|
551
|
-
const
|
|
552
|
-
if (!
|
|
553
|
-
!Node.isVariableDeclaration(declaration) ||
|
|
554
|
-
declaration.getInitializer() !== top) {
|
|
555
|
-
return [];
|
|
556
|
-
}
|
|
557
|
-
const name = declaration.getNameNode();
|
|
558
|
-
if (!Node.isIdentifier(name))
|
|
587
|
+
const name = responseBinding(top);
|
|
588
|
+
if (!name)
|
|
559
589
|
return [];
|
|
560
590
|
const reads = [];
|
|
561
591
|
let handedOn = false;
|
|
@@ -583,6 +613,92 @@ function bodyReadsOf(call) {
|
|
|
583
613
|
}
|
|
584
614
|
return checkedBodyReads(reads);
|
|
585
615
|
}
|
|
616
|
+
/**
|
|
617
|
+
* The name the located call's response is bound to, when the source binds it
|
|
618
|
+
* in one of three ways: `const res = await call`, the first parameter of a
|
|
619
|
+
* `.then` callback (`call.then((res) => res.json())`), or an element of an
|
|
620
|
+
* array destructured off `Promise.all` (`const [a, b] = await Promise.all([call, ...])`).
|
|
621
|
+
*/
|
|
622
|
+
function responseBinding(top) {
|
|
623
|
+
const declaration = top.getParent();
|
|
624
|
+
if (declaration && Node.isVariableDeclaration(declaration) && declaration.getInitializer() === top) {
|
|
625
|
+
const name = declaration.getNameNode();
|
|
626
|
+
return Node.isIdentifier(name) ? name : undefined;
|
|
627
|
+
}
|
|
628
|
+
return thenParameter(top) ?? promiseAllElement(top);
|
|
629
|
+
}
|
|
630
|
+
/** `top.then((res) => ...)`: the callback's first parameter. */
|
|
631
|
+
function thenParameter(top) {
|
|
632
|
+
const access = top.getParent();
|
|
633
|
+
if (!access || !Node.isPropertyAccessExpression(access) || access.getExpression() !== top) {
|
|
634
|
+
return undefined;
|
|
635
|
+
}
|
|
636
|
+
if (access.getName() !== 'then')
|
|
637
|
+
return undefined;
|
|
638
|
+
const then = access.getParent();
|
|
639
|
+
if (!then || !Node.isCallExpression(then) || then.getExpression() !== access)
|
|
640
|
+
return undefined;
|
|
641
|
+
const callback = then.getArguments()[0];
|
|
642
|
+
if (!callback || !(Node.isArrowFunction(callback) || Node.isFunctionExpression(callback))) {
|
|
643
|
+
return undefined;
|
|
644
|
+
}
|
|
645
|
+
const name = callback.getParameters()[0]?.getNameNode();
|
|
646
|
+
return name && Node.isIdentifier(name) ? name : undefined;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* The name `top` is destructured to, when `top` is one element of the array
|
|
650
|
+
* literal handed to the language library's `Promise.all` and the call's
|
|
651
|
+
* awaited result is destructured to names:
|
|
652
|
+
* `const [a, b] = await Promise.all([call, other])`. An element after a
|
|
653
|
+
* spread has no position the destructuring can be read against.
|
|
654
|
+
*/
|
|
655
|
+
function promiseAllElement(top) {
|
|
656
|
+
const array = top.getParent();
|
|
657
|
+
if (!array || !Node.isArrayLiteralExpression(array))
|
|
658
|
+
return undefined;
|
|
659
|
+
const elements = array.getElements();
|
|
660
|
+
const index = elements.indexOf(top);
|
|
661
|
+
if (index < 0 || elements.slice(0, index + 1).some((e) => Node.isSpreadElement(e))) {
|
|
662
|
+
return undefined;
|
|
663
|
+
}
|
|
664
|
+
const all = array.getParent();
|
|
665
|
+
if (!all ||
|
|
666
|
+
!Node.isCallExpression(all) ||
|
|
667
|
+
all.getArguments()[0] !== array ||
|
|
668
|
+
!isLibraryPromiseAll(all)) {
|
|
669
|
+
return undefined;
|
|
670
|
+
}
|
|
671
|
+
let result = all;
|
|
672
|
+
while (Node.isAwaitExpression(result.getParentOrThrow()) ||
|
|
673
|
+
Node.isParenthesizedExpression(result.getParentOrThrow())) {
|
|
674
|
+
result = result.getParentOrThrow();
|
|
675
|
+
}
|
|
676
|
+
const declaration = result.getParent();
|
|
677
|
+
if (!declaration || !Node.isVariableDeclaration(declaration) || declaration.getInitializer() !== result) {
|
|
678
|
+
return undefined;
|
|
679
|
+
}
|
|
680
|
+
const pattern = declaration.getNameNode();
|
|
681
|
+
if (!Node.isArrayBindingPattern(pattern))
|
|
682
|
+
return undefined;
|
|
683
|
+
const element = pattern.getElements()[index];
|
|
684
|
+
if (!element || !Node.isBindingElement(element) || element.getDotDotDotToken())
|
|
685
|
+
return undefined;
|
|
686
|
+
const name = element.getNameNode();
|
|
687
|
+
return Node.isIdentifier(name) ? name : undefined;
|
|
688
|
+
}
|
|
689
|
+
/** `Promise.all` as the language library declares it, not a lookalike. */
|
|
690
|
+
function isLibraryPromiseAll(call) {
|
|
691
|
+
const callee = call.getExpression();
|
|
692
|
+
if (!Node.isPropertyAccessExpression(callee) || callee.getName() !== 'all')
|
|
693
|
+
return false;
|
|
694
|
+
const declaration = resolvedDeclaration(call);
|
|
695
|
+
if (!declaration)
|
|
696
|
+
return false;
|
|
697
|
+
return call
|
|
698
|
+
.getProject()
|
|
699
|
+
.getProgram()
|
|
700
|
+
.compilerObject.isSourceFileDefaultLibrary(declaration.getSourceFile());
|
|
701
|
+
}
|
|
586
702
|
/**
|
|
587
703
|
* Why these body reads cannot be retyped, or the reads to retype.
|
|
588
704
|
*
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The members a service's server-framework labels name, for an `infer`
|
|
3
|
+
* request's route rows (carrick#2674).
|
|
4
|
+
*
|
|
5
|
+
* The labels are verified again with the library-claims verifier, which reads
|
|
6
|
+
* them through a probe file. That file is added to a program of its own (the
|
|
7
|
+
* key's `scripts` program, built by the same factory and resolution host),
|
|
8
|
+
* never to the program the inferrer reads: adding and removing it there
|
|
9
|
+
* rebuilt that program twice and threw away its warm checker. Members join
|
|
10
|
+
* across the two programs by `declarationKey`, the compiler's file name and
|
|
11
|
+
* the declaration's start.
|
|
12
|
+
*/
|
|
13
|
+
import type { Project } from 'ts-morph';
|
|
14
|
+
import { type LabelledMembers, type ModuleGraph } from './library-claims.js';
|
|
15
|
+
import type { ServerClaims } from './types.js';
|
|
16
|
+
/** What the label read needs of the project loader. */
|
|
17
|
+
export interface LabelSource extends ModuleGraph {
|
|
18
|
+
getRepoRoot(): string;
|
|
19
|
+
/** A program for `key` the caller owns and drops: never the inferrer's. */
|
|
20
|
+
scriptProjectFor(key: string): Project;
|
|
21
|
+
}
|
|
22
|
+
/** No label: the inferrer reads nothing new. */
|
|
23
|
+
export declare const NO_LABELS: LabelledMembers;
|
|
24
|
+
/**
|
|
25
|
+
* The members `claims` name in the program behind `key`. A claim the schema
|
|
26
|
+
* refuses is dropped; a read that throws answers no labels, so every item of
|
|
27
|
+
* the request is read as it would be without them.
|
|
28
|
+
*/
|
|
29
|
+
export declare function readServerLabels(source: LabelSource, key: string, claims: ServerClaims, budgetMs: number, log: (message: string) => void): LabelledMembers;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The members a service's server-framework labels name, for an `infer`
|
|
3
|
+
* request's route rows (carrick#2674).
|
|
4
|
+
*
|
|
5
|
+
* The labels are verified again with the library-claims verifier, which reads
|
|
6
|
+
* them through a probe file. That file is added to a program of its own (the
|
|
7
|
+
* key's `scripts` program, built by the same factory and resolution host),
|
|
8
|
+
* never to the program the inferrer reads: adding and removing it there
|
|
9
|
+
* rebuilt that program twice and threw away its warm checker. Members join
|
|
10
|
+
* across the two programs by `declarationKey`, the compiler's file name and
|
|
11
|
+
* the declaration's start.
|
|
12
|
+
*/
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { LibraryClaimsVerifier } from './library-claims.js';
|
|
15
|
+
import { settledServerChecks } from './validators.js';
|
|
16
|
+
/** No label: the inferrer reads nothing new. */
|
|
17
|
+
export const NO_LABELS = { sends: new Map(), bodies: new Set() };
|
|
18
|
+
/**
|
|
19
|
+
* The members `claims` name in the program behind `key`. A claim the schema
|
|
20
|
+
* refuses is dropped; a read that throws answers no labels, so every item of
|
|
21
|
+
* the request is read as it would be without them.
|
|
22
|
+
*/
|
|
23
|
+
export function readServerLabels(source, key, claims, budgetMs, log) {
|
|
24
|
+
const { checks, refused } = settledServerChecks(claims.checks);
|
|
25
|
+
if (refused > 0) {
|
|
26
|
+
log(`Dropped ${refused} server claim(s) the library-check schema refuses (a make or scope among them leaves its ops unread)`);
|
|
27
|
+
}
|
|
28
|
+
if (checks.length === 0)
|
|
29
|
+
return NO_LABELS;
|
|
30
|
+
const fromDir = path.resolve(source.getRepoRoot(), claims.from_dir);
|
|
31
|
+
try {
|
|
32
|
+
const verifier = new LibraryClaimsVerifier(source.scriptProjectFor(key), {
|
|
33
|
+
packageDirectoryOf: (file) => source.packageDirectoryOf(file),
|
|
34
|
+
resolveModule: (name, from, options) => source.resolveModule(name, from, options),
|
|
35
|
+
});
|
|
36
|
+
const labels = verifier.labelledMembers(fromDir, checks, budgetMs, claims.scan_root, claims.type_packages);
|
|
37
|
+
log(`Read ${labels.sends.size} labelled send and ${labels.bodies.size} body member(s) for handler parameters ` +
|
|
38
|
+
`from ${checks.length} claim(s) in ${fromDir}: ${JSON.stringify(labels.outcomes ?? {})}`);
|
|
39
|
+
return labels;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
log(`Reading server labels in ${fromDir} failed, so no handler parameter is read through them: ${String(error)}`);
|
|
43
|
+
return NO_LABELS;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a route handler's own parameters state about the route's bodies
|
|
3
|
+
* (carrick#2674), read through the members the service's verified
|
|
4
|
+
* server-framework labels name ({@link LabelledMembers}). A member is matched
|
|
5
|
+
* by its declaration, never by its name, so a type the repo declares itself
|
|
6
|
+
* with a member of the same name states nothing here.
|
|
7
|
+
*
|
|
8
|
+
* - The request: the member a receive op's `request.body` path ends on, read
|
|
9
|
+
* at the handler's parameter. A type the source fills is the body. A body
|
|
10
|
+
* the source leaves `never`, or leaves at the library's unfilled `unknown`
|
|
11
|
+
* while it writes a type argument for the route, is "no request body",
|
|
12
|
+
* provided nothing reads it (`bodyIsUnread`).
|
|
13
|
+
* - The reply: the payload a labelled `send` member's slot takes, read at the
|
|
14
|
+
* handler's parameter, where the library declares that payload through a
|
|
15
|
+
* type parameter of the reply type. A union of success and error bodies is
|
|
16
|
+
* cut to the variants a success-status send through the parameter carries.
|
|
17
|
+
*/
|
|
18
|
+
import { Node, type ArrowFunction, type CallExpression, type FunctionDeclaration, type FunctionExpression, type MethodDeclaration, type ParameterDeclaration, type Type } from 'ts-morph';
|
|
19
|
+
import { type LabelledMembers } from './library-claims.js';
|
|
20
|
+
/** A function a handler can be: what the inferrer follows a registration to. */
|
|
21
|
+
export type HandlerFunction = FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration;
|
|
22
|
+
/** What a handler's parameters state about the request body. */
|
|
23
|
+
export type StatedRequest = {
|
|
24
|
+
kind: 'body';
|
|
25
|
+
type: Type;
|
|
26
|
+
at: ParameterDeclaration;
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'no_body';
|
|
29
|
+
at: ParameterDeclaration;
|
|
30
|
+
detail: string;
|
|
31
|
+
};
|
|
32
|
+
/** The reply a handler's parameters state: one or more success variants. */
|
|
33
|
+
export interface StatedReply {
|
|
34
|
+
variants: Type[];
|
|
35
|
+
at: ParameterDeclaration;
|
|
36
|
+
}
|
|
37
|
+
/** The status a send's own chain states, as the inferrer reads it. */
|
|
38
|
+
export type ChainStatus = (call: CallExpression) => 'success' | 'error' | 'redirect' | 'variable' | 'undecided' | undefined;
|
|
39
|
+
export declare class StatedParams {
|
|
40
|
+
private readonly labels;
|
|
41
|
+
/** True for a file the repo declares itself (not a library's or the runtime's). */
|
|
42
|
+
private readonly isRepoFile;
|
|
43
|
+
private readonly chainStatus;
|
|
44
|
+
constructor(labels: LabelledMembers,
|
|
45
|
+
/** True for a file the repo declares itself (not a library's or the runtime's). */
|
|
46
|
+
isRepoFile: (file: Node) => boolean, chainStatus: ChainStatus);
|
|
47
|
+
/** No label names a member: every reading answers nothing. */
|
|
48
|
+
get isEmpty(): boolean;
|
|
49
|
+
/** Whether some label names a reply's send member. */
|
|
50
|
+
get readsReplies(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* The request body the handler's parameters state, the first parameter
|
|
53
|
+
* whose type has a labelled body member deciding. Undefined when no
|
|
54
|
+
* parameter has one, or the one that does states nothing decidable. A
|
|
55
|
+
* route whose `registration` hands in another function beside the handler
|
|
56
|
+
* (a middleware, which can read the body first) decides no "no body".
|
|
57
|
+
*/
|
|
58
|
+
request(handler: HandlerFunction, registration?: Node): StatedRequest | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* The route hands in a function besides the handler: a callable argument
|
|
61
|
+
* (or list of them) beside the handler on any call it is passed through
|
|
62
|
+
* up to the registration, or, where the registration names the handler by
|
|
63
|
+
* reference, a second callable argument or property there. What such a
|
|
64
|
+
* function (a middleware) does with the request is not read here.
|
|
65
|
+
*/
|
|
66
|
+
private handsInAnotherFunction;
|
|
67
|
+
/**
|
|
68
|
+
* A type argument the source writes for this route: on a call the handler
|
|
69
|
+
* is passed to (the registration, or a wrapper that makes the handler),
|
|
70
|
+
* through any calls enclosing that one as an argument, or on the
|
|
71
|
+
* parameter's own annotation.
|
|
72
|
+
*/
|
|
73
|
+
private writesTypeArgument;
|
|
74
|
+
/**
|
|
75
|
+
* Nothing reads the labelled body member off parameter `index` of
|
|
76
|
+
* `func`, nor off the request in the repo functions it is handed to, up to
|
|
77
|
+
* `REACH_DEPTH` calls deep. Every use of the request must be a member
|
|
78
|
+
* read that is not the body and is not itself called (a framework's own
|
|
79
|
+
* body reader), or a hand-off to a function the repo declares, whole and
|
|
80
|
+
* by position. Anything else (a destructured parameter, a library
|
|
81
|
+
* function, an alias, a spread) is a read this cannot rule out.
|
|
82
|
+
*/
|
|
83
|
+
private bodyIsUnread;
|
|
84
|
+
/**
|
|
85
|
+
* A read of a request member (`req.headers`, `req.headers.host`) whose
|
|
86
|
+
* value goes nowhere a body could be read from. Along its member chain, a
|
|
87
|
+
* method called on anything but a plain value (`req.raw.pipe(...)`, or a
|
|
88
|
+
* framework's own body reader `req.file()`) is a read, and so is a
|
|
89
|
+
* non-plain value handed to a function (`getRawBody(req.raw)`). A plain
|
|
90
|
+
* value (a header string) holds no body, whatever is done with it.
|
|
91
|
+
*/
|
|
92
|
+
private memberReadStaysPut;
|
|
93
|
+
/** The function a callee names, where the repo declares it; undefined otherwise. */
|
|
94
|
+
private repoFunction;
|
|
95
|
+
/**
|
|
96
|
+
* The reply the handler's parameters state, cut to its success variants.
|
|
97
|
+
* Undefined when no parameter has a labelled send member that states a
|
|
98
|
+
* payload, when two such members disagree, when the payload is `any`,
|
|
99
|
+
* `unknown` or `never`, or when a union of bodies has no variant a
|
|
100
|
+
* success send through the parameter carries.
|
|
101
|
+
*/
|
|
102
|
+
reply(handler: HandlerFunction): StatedReply | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* The payload the labelled send members the handler calls through the
|
|
105
|
+
* parameter state: `none` when it calls none, `abstain` when they state
|
|
106
|
+
* different payloads, else the one payload type. A member the handler never
|
|
107
|
+
* calls (a reply object's status-code send beside its body send) says
|
|
108
|
+
* nothing about this route.
|
|
109
|
+
*/
|
|
110
|
+
private statedPayload;
|
|
111
|
+
/** The payload slot a labelled send member takes, by any of its declarations. */
|
|
112
|
+
private sendSlotOf;
|
|
113
|
+
/**
|
|
114
|
+
* The type parameters of the type that declares the member that its
|
|
115
|
+
* payload is declared through: a slot each route fills. None for a payload
|
|
116
|
+
* declared with a fixed type (a file path), which says nothing about any
|
|
117
|
+
* one route.
|
|
118
|
+
*/
|
|
119
|
+
private payloadTypeParameters;
|
|
120
|
+
/** The type the call signature takes at the payload slot, read at `at`. */
|
|
121
|
+
private payloadAt;
|
|
122
|
+
/**
|
|
123
|
+
* The calls of a labelled send member the handler makes on `parameter`, or
|
|
124
|
+
* on a call chain rooted at it (`res.status(201).json(body)`), each with
|
|
125
|
+
* its payload slot and the keys of the member's declarations.
|
|
126
|
+
*/
|
|
127
|
+
private sendsThrough;
|
|
128
|
+
/**
|
|
129
|
+
* The payloads the sends carry whose chain states a success status or
|
|
130
|
+
* none. A value typed `any` or `unknown` is assignable to every variant, so
|
|
131
|
+
* it tells no success body from an error body and is left out.
|
|
132
|
+
*/
|
|
133
|
+
private successPayloads;
|
|
134
|
+
/** The symbol at the root of a member or call chain (`res.status(201)` is `res`). */
|
|
135
|
+
private rootSymbol;
|
|
136
|
+
/** The member of the parameter's type whose declaration a label names. */
|
|
137
|
+
private labelledMember;
|
|
138
|
+
}
|