carrick 0.3.133 → 0.3.134
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/contract.d.ts +6 -0
- package/dist/contract.js.map +1 -1
- package/dist/hook/post-edit.d.ts +10 -5
- package/dist/hook/post-edit.js +80 -23
- package/dist/hook/post-edit.js.map +1 -1
- package/dist/hook/refresh.d.ts +23 -3
- package/dist/hook/refresh.js +48 -6
- package/dist/hook/refresh.js.map +1 -1
- package/dist/hook/reuse.d.ts +7 -21
- package/dist/hook/reuse.js +23 -36
- package/dist/hook/reuse.js.map +1 -1
- package/dist/hook/session-start.js +15 -2
- package/dist/hook/session-start.js.map +1 -1
- package/dist/hook/stop.js.map +1 -1
- package/dist/init/agents-section.js +1 -1
- package/dist/init/agents-section.js.map +1 -1
- package/dist/init/doctor.js +4 -0
- package/dist/init/doctor.js.map +1 -1
- package/dist/init/hosted.d.ts +1 -0
- package/dist/init/hosted.js +4 -1
- package/dist/init/hosted.js.map +1 -1
- package/dist/init/remove.js +7 -1
- package/dist/init/remove.js.map +1 -1
- package/dist/init/repo-copies.js +3 -1
- package/dist/init/repo-copies.js.map +1 -1
- package/dist/init/run.d.ts +1 -1
- package/dist/init/run.js +10 -2
- package/dist/init/run.js.map +1 -1
- package/dist/init/task-skills.d.ts +22 -1
- package/dist/init/task-skills.js +65 -1
- package/dist/init/task-skills.js.map +1 -1
- package/dist/render.d.ts +41 -16
- package/dist/render.js +91 -102
- package/dist/render.js.map +1 -1
- package/package.json +10 -9
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/sidecar/dist/src/capture/anchors.js +18 -1
- package/sidecar/dist/src/capture/api.d.ts +17 -4
- package/sidecar/dist/src/capture/check-workspace.js +1 -1
- package/sidecar/dist/src/capture/check.d.ts +44 -0
- package/sidecar/dist/src/capture/check.js +112 -10
- package/sidecar/dist/src/capture/installed-package.d.ts +5 -0
- package/sidecar/dist/src/capture/installed-package.js +64 -6
- package/sidecar/dist/src/capture/paths-rewrite.js +3 -3
- package/sidecar/dist/src/capture/result-label.d.ts +42 -0
- package/sidecar/dist/src/capture/result-label.js +91 -0
- package/sidecar/dist/src/capture/self-check.js +13 -2
- package/sidecar/dist/src/index.js +116 -4
- package/sidecar/dist/src/infer-cache.d.ts +125 -0
- package/sidecar/dist/src/infer-cache.js +244 -0
- package/sidecar/dist/src/library-claims.js +42 -4
- package/sidecar/dist/src/node-index.d.ts +53 -0
- package/sidecar/dist/src/node-index.js +100 -0
- package/sidecar/dist/src/project-loader.d.ts +11 -0
- package/sidecar/dist/src/project-loader.js +15 -0
- package/sidecar/dist/src/result-candidates.d.ts +28 -0
- package/sidecar/dist/src/result-candidates.js +209 -0
- package/sidecar/dist/src/type-inferrer.d.ts +27 -0
- package/sidecar/dist/src/type-inferrer.js +175 -43
- package/sidecar/dist/src/types.d.ts +52 -0
- package/sidecar/dist/src/unwidened.js +10 -1
- package/sidecar/dist/src/validators.d.ts +919 -197
- package/sidecar/dist/src/validators.js +32 -0
- package/templates/skills/carrick-reuse.md +11 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every node of a source file, walked once per file (carrick#1935).
|
|
3
|
+
*
|
|
4
|
+
* The inferrer locates each item by a line, a text near a line, or a span.
|
|
5
|
+
* Each of those lookups used to call `sourceFile.getDescendants()`, which
|
|
6
|
+
* walks and wraps every node of the file, once per item: on a generated
|
|
7
|
+
* client of 8,000+ lines that was 71% of an infer request's time. Here the
|
|
8
|
+
* file is walked once, the positions are read once, and a lookup wraps only
|
|
9
|
+
* the nodes it returns.
|
|
10
|
+
*
|
|
11
|
+
* The walk is ts-morph's own (`getDescendants()` iterates the same compiler
|
|
12
|
+
* nodes in the same order, tokens, syntax lists and its comment nodes
|
|
13
|
+
* included), and a node is wrapped through the project's own factory, so a
|
|
14
|
+
* lookup returns the very wrapper the walk returned.
|
|
15
|
+
*
|
|
16
|
+
* The index belongs to the compiler's source file node, not to the file's
|
|
17
|
+
* name: replacing a file's text gives it a new node, so a file rewritten for
|
|
18
|
+
* one reading and then restored is indexed again each time.
|
|
19
|
+
*/
|
|
20
|
+
import { SyntaxKind } from 'ts-morph';
|
|
21
|
+
import { lineIndex } from './line-index.js';
|
|
22
|
+
const internals = (sourceFile) => sourceFile;
|
|
23
|
+
const indexes = new WeakMap();
|
|
24
|
+
let builds = 0;
|
|
25
|
+
/** How many file indexes have been built: tests read it to prove reuse. */
|
|
26
|
+
export function nodeIndexBuilds() {
|
|
27
|
+
return builds;
|
|
28
|
+
}
|
|
29
|
+
function indexOf(sourceFile) {
|
|
30
|
+
const key = sourceFile.compilerNode;
|
|
31
|
+
let index = indexes.get(key);
|
|
32
|
+
if (!index) {
|
|
33
|
+
index = buildIndex(sourceFile);
|
|
34
|
+
indexes.set(key, index);
|
|
35
|
+
}
|
|
36
|
+
return index;
|
|
37
|
+
}
|
|
38
|
+
function buildIndex(sourceFile) {
|
|
39
|
+
builds += 1;
|
|
40
|
+
const file = sourceFile.compilerNode;
|
|
41
|
+
const lineAt = lineIndex(file.text);
|
|
42
|
+
const all = [];
|
|
43
|
+
const calls = [];
|
|
44
|
+
const byLine = new Map();
|
|
45
|
+
for (const node of internals(sourceFile)._getCompilerDescendantsIterator()) {
|
|
46
|
+
const start = node.getStart(file);
|
|
47
|
+
const entry = {
|
|
48
|
+
node,
|
|
49
|
+
kind: node.kind,
|
|
50
|
+
start,
|
|
51
|
+
end: node.end,
|
|
52
|
+
line: lineAt(start),
|
|
53
|
+
order: all.length,
|
|
54
|
+
};
|
|
55
|
+
all.push(entry);
|
|
56
|
+
if (entry.kind === SyntaxKind.CallExpression)
|
|
57
|
+
calls.push(entry);
|
|
58
|
+
const onLine = byLine.get(entry.line);
|
|
59
|
+
if (onLine)
|
|
60
|
+
onLine.push(entry);
|
|
61
|
+
else
|
|
62
|
+
byLine.set(entry.line, [entry]);
|
|
63
|
+
}
|
|
64
|
+
return { all, calls, byLine };
|
|
65
|
+
}
|
|
66
|
+
/** The ts-morph node for an indexed one. */
|
|
67
|
+
export function wrap(sourceFile, entry) {
|
|
68
|
+
return internals(sourceFile)._getNodeFromCompilerNode(entry.node);
|
|
69
|
+
}
|
|
70
|
+
/** Every descendant, in `getDescendants()` order. */
|
|
71
|
+
export function descendantsOf(sourceFile) {
|
|
72
|
+
return indexOf(sourceFile).all;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The call expressions, in `getDescendantsOfKind(SyntaxKind.CallExpression)`
|
|
76
|
+
* order.
|
|
77
|
+
*/
|
|
78
|
+
export function callsOf(sourceFile) {
|
|
79
|
+
return indexOf(sourceFile).calls;
|
|
80
|
+
}
|
|
81
|
+
/** The descendants that start on `line`, in walk order. */
|
|
82
|
+
export function descendantsOnLine(sourceFile, line) {
|
|
83
|
+
return indexOf(sourceFile).byLine.get(line) ?? [];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The descendants that start on a line from `first` to `last`, in walk
|
|
87
|
+
* order. Walk order is not line order (a doc comment starts before the node
|
|
88
|
+
* that owns it but follows it in the walk), so the lines' lists are merged
|
|
89
|
+
* back into walk order.
|
|
90
|
+
*/
|
|
91
|
+
export function descendantsOnLines(sourceFile, first, last) {
|
|
92
|
+
const { byLine } = indexOf(sourceFile);
|
|
93
|
+
const found = [];
|
|
94
|
+
for (let line = Math.ceil(first); line <= last; line++) {
|
|
95
|
+
const onLine = byLine.get(line);
|
|
96
|
+
if (onLine)
|
|
97
|
+
found.push(...onLine);
|
|
98
|
+
}
|
|
99
|
+
return found.sort((a, b) => a.order - b.order);
|
|
100
|
+
}
|
|
@@ -171,6 +171,17 @@ export declare class ProjectLoader {
|
|
|
171
171
|
* @throws Error if load() has not succeeded, or if the build fails
|
|
172
172
|
*/
|
|
173
173
|
getProject(): Project;
|
|
174
|
+
/**
|
|
175
|
+
* Whether the project behind a key from `projectKeyFor` has been built,
|
|
176
|
+
* without building it (carrick#2843).
|
|
177
|
+
*/
|
|
178
|
+
isBuilt(key: string): boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Whether the project resolves through a module graph read outside the
|
|
181
|
+
* compiler (Deno, carrick#1260). What such a program reads is not all in
|
|
182
|
+
* its source files (carrick#2843).
|
|
183
|
+
*/
|
|
184
|
+
resolvesThroughModuleGraph(): boolean;
|
|
174
185
|
/**
|
|
175
186
|
* The default project when a request has built it, and `undefined` before
|
|
176
187
|
* that, without building it (carrick#2027).
|
|
@@ -487,6 +487,21 @@ export class ProjectLoader {
|
|
|
487
487
|
}
|
|
488
488
|
return this.project;
|
|
489
489
|
}
|
|
490
|
+
/**
|
|
491
|
+
* Whether the project behind a key from `projectKeyFor` has been built,
|
|
492
|
+
* without building it (carrick#2843).
|
|
493
|
+
*/
|
|
494
|
+
isBuilt(key) {
|
|
495
|
+
return key === '' ? this.project !== null : this.ownerProjects.has(key);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Whether the project resolves through a module graph read outside the
|
|
499
|
+
* compiler (Deno, carrick#1260). What such a program reads is not all in
|
|
500
|
+
* its source files (carrick#2843).
|
|
501
|
+
*/
|
|
502
|
+
resolvesThroughModuleGraph() {
|
|
503
|
+
return this.denoProject !== undefined;
|
|
504
|
+
}
|
|
490
505
|
/**
|
|
491
506
|
* The default project when a request has built it, and `undefined` before
|
|
492
507
|
* that, without building it (carrick#2027).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which parts of a call's return could hold the response body the call
|
|
3
|
+
* resolves to (carrick#2817). The compiler decides one case, that the
|
|
4
|
+
* caller supplies the whole return as a type argument (`whole_decided`); for
|
|
5
|
+
* every other return it only lists the candidates: the members that carry a
|
|
6
|
+
* type parameter of the signature, and the parse methods. Choosing among them
|
|
7
|
+
* is the store picker's job, and `holdsResult` judges the choice.
|
|
8
|
+
*
|
|
9
|
+
* Rule R, per signature `S` with type parameters `P`:
|
|
10
|
+
* 1. `A` is the awaited return of `S`. While `A` is a type parameter of `S`
|
|
11
|
+
* whose default is not `unknown` or `any`, take the default (awaited), at
|
|
12
|
+
* most four hops: a default of `unknown`/`any` is the caller-supplies-it
|
|
13
|
+
* case.
|
|
14
|
+
* 2. `whole_decided`: `A` is a type parameter of `S` with no constraint.
|
|
15
|
+
* 3. `members`: across the branches of `A` (a conditional's true and false
|
|
16
|
+
* types, a union's constituents without `undefined`/`null`/`void`; depth at
|
|
17
|
+
* most four), every property with no call signature whose declared type
|
|
18
|
+
* mentions a type parameter in `P`.
|
|
19
|
+
* 4. `parse`: properties of `S`'s raw return or of a branch of `A` that can
|
|
20
|
+
* be called with no required argument and whose awaited return is a bare,
|
|
21
|
+
* unconstrained type parameter of that method's own signature.
|
|
22
|
+
* A signature that returns nothing (void, undefined, never) has no candidates.
|
|
23
|
+
*/
|
|
24
|
+
import { ts } from 'ts-morph';
|
|
25
|
+
import type { ResultShape, SurfaceResultCandidates } from './types.js';
|
|
26
|
+
export declare function resultCandidatesOf(checker: ts.TypeChecker, signature: ts.Signature): SurfaceResultCandidates | undefined;
|
|
27
|
+
/** Whether `shape` names one of `candidates`. `whole` is always one; a decided whole is the only one. */
|
|
28
|
+
export declare function holdsResult(candidates: SurfaceResultCandidates, shape: ResultShape): boolean;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which parts of a call's return could hold the response body the call
|
|
3
|
+
* resolves to (carrick#2817). The compiler decides one case, that the
|
|
4
|
+
* caller supplies the whole return as a type argument (`whole_decided`); for
|
|
5
|
+
* every other return it only lists the candidates: the members that carry a
|
|
6
|
+
* type parameter of the signature, and the parse methods. Choosing among them
|
|
7
|
+
* is the store picker's job, and `holdsResult` judges the choice.
|
|
8
|
+
*
|
|
9
|
+
* Rule R, per signature `S` with type parameters `P`:
|
|
10
|
+
* 1. `A` is the awaited return of `S`. While `A` is a type parameter of `S`
|
|
11
|
+
* whose default is not `unknown` or `any`, take the default (awaited), at
|
|
12
|
+
* most four hops: a default of `unknown`/`any` is the caller-supplies-it
|
|
13
|
+
* case.
|
|
14
|
+
* 2. `whole_decided`: `A` is a type parameter of `S` with no constraint.
|
|
15
|
+
* 3. `members`: across the branches of `A` (a conditional's true and false
|
|
16
|
+
* types, a union's constituents without `undefined`/`null`/`void`; depth at
|
|
17
|
+
* most four), every property with no call signature whose declared type
|
|
18
|
+
* mentions a type parameter in `P`.
|
|
19
|
+
* 4. `parse`: properties of `S`'s raw return or of a branch of `A` that can
|
|
20
|
+
* be called with no required argument and whose awaited return is a bare,
|
|
21
|
+
* unconstrained type parameter of that method's own signature.
|
|
22
|
+
* A signature that returns nothing (void, undefined, never) has no candidates.
|
|
23
|
+
*/
|
|
24
|
+
import { ts } from 'ts-morph';
|
|
25
|
+
const MAX_DEPTH = 4;
|
|
26
|
+
const NOTHING = ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.Never;
|
|
27
|
+
const NULLISH = ts.TypeFlags.Undefined | ts.TypeFlags.Null | ts.TypeFlags.Void;
|
|
28
|
+
const OPEN = ts.TypeFlags.Any | ts.TypeFlags.Unknown;
|
|
29
|
+
const isTypeParameter = (type) => (type.flags & ts.TypeFlags.TypeParameter) !== 0;
|
|
30
|
+
const byCodeUnit = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
31
|
+
export function resultCandidatesOf(checker, signature) {
|
|
32
|
+
const reader = new ResultReader(checker);
|
|
33
|
+
return reader.candidates(signature);
|
|
34
|
+
}
|
|
35
|
+
/** Whether `shape` names one of `candidates`. `whole` is always one; a decided whole is the only one. */
|
|
36
|
+
export function holdsResult(candidates, shape) {
|
|
37
|
+
if ('whole' in shape)
|
|
38
|
+
return true;
|
|
39
|
+
if (candidates.whole_decided)
|
|
40
|
+
return false;
|
|
41
|
+
if ('member' in shape)
|
|
42
|
+
return candidates.members.includes(shape.member[0]);
|
|
43
|
+
return candidates.parse.includes(shape.parse);
|
|
44
|
+
}
|
|
45
|
+
class ResultReader {
|
|
46
|
+
checker;
|
|
47
|
+
constructor(checker) {
|
|
48
|
+
this.checker = checker;
|
|
49
|
+
}
|
|
50
|
+
candidates(signature) {
|
|
51
|
+
const raw = this.checker.getReturnTypeOfSignature(signature);
|
|
52
|
+
if (raw.flags & NOTHING)
|
|
53
|
+
return undefined;
|
|
54
|
+
const params = new Set(signature.getTypeParameters() ?? []);
|
|
55
|
+
let awaited = this.awaited(raw);
|
|
56
|
+
for (let hop = 0; hop < MAX_DEPTH && isTypeParameter(awaited) && params.has(awaited); hop++) {
|
|
57
|
+
const fallback = this.checker.getDefaultFromTypeParameter(awaited);
|
|
58
|
+
if (fallback === undefined || fallback.flags & OPEN)
|
|
59
|
+
break;
|
|
60
|
+
awaited = this.awaited(fallback);
|
|
61
|
+
}
|
|
62
|
+
if (awaited.flags & NOTHING)
|
|
63
|
+
return undefined;
|
|
64
|
+
if (isTypeParameter(awaited) && params.has(awaited) && this.unconstrained(awaited)) {
|
|
65
|
+
return { whole_decided: true, members: [], parse: [] };
|
|
66
|
+
}
|
|
67
|
+
const leaves = [];
|
|
68
|
+
this.leavesOf(awaited, params, 0, leaves);
|
|
69
|
+
const members = new Set();
|
|
70
|
+
for (const leaf of leaves) {
|
|
71
|
+
if (!(leaf.type.flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection)))
|
|
72
|
+
continue;
|
|
73
|
+
for (const property of this.checker.getPropertiesOfType(leaf.type)) {
|
|
74
|
+
const type = this.checker.getTypeOfSymbol(property);
|
|
75
|
+
if (this.checker.getNonNullableType(type).getCallSignatures().length > 0)
|
|
76
|
+
continue;
|
|
77
|
+
if (this.mentions(type, leaf.params, 0, new Set()))
|
|
78
|
+
members.add(property.getName());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const parse = new Set();
|
|
82
|
+
for (const holder of [raw, ...leaves.map(leaf => leaf.type)]) {
|
|
83
|
+
if (!(holder.flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection)))
|
|
84
|
+
continue;
|
|
85
|
+
for (const property of this.checker.getPropertiesOfType(holder)) {
|
|
86
|
+
const type = this.checker.getNonNullableType(this.checker.getTypeOfSymbol(property));
|
|
87
|
+
if (type.getCallSignatures().some(method => this.parses(method)))
|
|
88
|
+
parse.add(property.getName());
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { whole_decided: false, members: [...members].sort(byCodeUnit), parse: [...parse].sort(byCodeUnit) };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* `type` with a promise unwrapped. The checker spells an open parameter's
|
|
95
|
+
* awaited type `Awaited<T>`; that is read as `T`. A union and a conditional
|
|
96
|
+
* are left to `leavesOf`, which awaits each arm.
|
|
97
|
+
*/
|
|
98
|
+
awaited(type, depth = 0) {
|
|
99
|
+
if (depth > MAX_DEPTH)
|
|
100
|
+
return type;
|
|
101
|
+
if (type.aliasSymbol?.getName() === 'Awaited' && type.aliasTypeArguments?.length === 1) {
|
|
102
|
+
return this.awaited(type.aliasTypeArguments[0], depth + 1);
|
|
103
|
+
}
|
|
104
|
+
if (type.flags & (ts.TypeFlags.TypeParameter | ts.TypeFlags.Union | ts.TypeFlags.Conditional))
|
|
105
|
+
return type;
|
|
106
|
+
const unwrapped = this.checker.getAwaitedType(type);
|
|
107
|
+
return unwrapped === undefined || unwrapped === type ? type : this.awaited(unwrapped, depth + 1);
|
|
108
|
+
}
|
|
109
|
+
unconstrained(parameter) {
|
|
110
|
+
const constraint = this.checker.getBaseConstraintOfType(parameter);
|
|
111
|
+
return constraint === undefined || (constraint.flags & OPEN) !== 0;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The branches of `type`: a union's parts without nullish ones, a
|
|
115
|
+
* conditional's two arms, each awaited. `params` are the type parameters a
|
|
116
|
+
* branch counts as carrying a value of: an arm of a generic alias is written
|
|
117
|
+
* in the alias's own parameters, so the alias parameters applied to
|
|
118
|
+
* something that mentions `params` join `params` for that arm.
|
|
119
|
+
*/
|
|
120
|
+
leavesOf(type, params, depth, into) {
|
|
121
|
+
if (depth > MAX_DEPTH)
|
|
122
|
+
return;
|
|
123
|
+
const current = this.awaited(type);
|
|
124
|
+
if (current.flags & ts.TypeFlags.Union) {
|
|
125
|
+
for (const part of current.types) {
|
|
126
|
+
if (!(part.flags & NULLISH))
|
|
127
|
+
this.leavesOf(part, params, depth + 1, into);
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (current.flags & ts.TypeFlags.Conditional) {
|
|
132
|
+
const node = current.root.node;
|
|
133
|
+
const armParams = this.aliasParams(current, params);
|
|
134
|
+
for (const arm of [node.trueType, node.falseType]) {
|
|
135
|
+
this.leavesOf(this.checker.getTypeFromTypeNode(arm), armParams, depth + 1, into);
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (current.flags & NOTHING)
|
|
140
|
+
return;
|
|
141
|
+
into.push({ type: current, params });
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* `params`, plus each type parameter of the alias `type` is an application
|
|
145
|
+
* of whose argument mentions one of `params`. The arms of a conditional
|
|
146
|
+
* written in an alias name those parameters, not the arguments.
|
|
147
|
+
*/
|
|
148
|
+
aliasParams(type, params) {
|
|
149
|
+
const declaration = type.aliasSymbol?.declarations?.find(ts.isTypeAliasDeclaration);
|
|
150
|
+
const args = type.aliasTypeArguments;
|
|
151
|
+
if (declaration === undefined || args === undefined)
|
|
152
|
+
return params;
|
|
153
|
+
const joined = new Set(params);
|
|
154
|
+
(declaration.typeParameters ?? []).forEach((node, index) => {
|
|
155
|
+
if (index < args.length && this.mentions(args[index], params, 0, new Set())) {
|
|
156
|
+
joined.add(this.checker.getTypeAtLocation(node));
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
return joined;
|
|
160
|
+
}
|
|
161
|
+
/** A parse method: no required argument, and it returns a bare unconstrained parameter of its own. */
|
|
162
|
+
parses(method) {
|
|
163
|
+
const own = method.getTypeParameters() ?? [];
|
|
164
|
+
if (own.length === 0)
|
|
165
|
+
return false;
|
|
166
|
+
const required = method.getParameters().some(parameter => {
|
|
167
|
+
const declaration = parameter.valueDeclaration;
|
|
168
|
+
if (declaration === undefined || !ts.isParameter(declaration))
|
|
169
|
+
return true;
|
|
170
|
+
return declaration.questionToken === undefined && declaration.initializer === undefined && declaration.dotDotDotToken === undefined;
|
|
171
|
+
});
|
|
172
|
+
if (required)
|
|
173
|
+
return false;
|
|
174
|
+
const returned = this.awaited(this.checker.getReturnTypeOfSignature(method));
|
|
175
|
+
return isTypeParameter(returned) && own.includes(returned) && this.unconstrained(returned);
|
|
176
|
+
}
|
|
177
|
+
/** Whether `type` names one of `params` anywhere a value of it could be read through. */
|
|
178
|
+
mentions(type, params, depth, seen) {
|
|
179
|
+
if (params.has(type))
|
|
180
|
+
return true;
|
|
181
|
+
if (depth > MAX_DEPTH || seen.has(type))
|
|
182
|
+
return false;
|
|
183
|
+
seen.add(type);
|
|
184
|
+
const next = (part) => this.mentions(part, params, depth + 1, seen);
|
|
185
|
+
if (type.aliasTypeArguments?.some(next))
|
|
186
|
+
return true;
|
|
187
|
+
if (type.isUnionOrIntersection())
|
|
188
|
+
return type.types.some(next);
|
|
189
|
+
if (type.flags & ts.TypeFlags.IndexedAccess) {
|
|
190
|
+
const access = type;
|
|
191
|
+
return next(access.objectType) || next(access.indexType);
|
|
192
|
+
}
|
|
193
|
+
if (type.flags & ts.TypeFlags.Index)
|
|
194
|
+
return next(type.type);
|
|
195
|
+
if (type.flags & ts.TypeFlags.Conditional) {
|
|
196
|
+
const conditional = type;
|
|
197
|
+
return next(conditional.checkType) || next(conditional.extendsType);
|
|
198
|
+
}
|
|
199
|
+
if (!(type.flags & ts.TypeFlags.Object))
|
|
200
|
+
return false;
|
|
201
|
+
const object = type;
|
|
202
|
+
if (object.objectFlags & ts.ObjectFlags.Reference && this.checker.getTypeArguments(object).some(next)) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
if (this.checker.isArrayType(type) || this.checker.isTupleType(type))
|
|
206
|
+
return false;
|
|
207
|
+
return this.checker.getPropertiesOfType(type).some(property => next(this.checker.getTypeOfSymbol(property)));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -208,6 +208,18 @@ export declare class TypeInferrer {
|
|
|
208
208
|
* Get or add a source file to the project
|
|
209
209
|
*/
|
|
210
210
|
private getSourceFile;
|
|
211
|
+
/**
|
|
212
|
+
* carrick#2824: a located response expression that sits in ANOTHER route's
|
|
213
|
+
* handler is not this row's. A model can locate `response` at a line that
|
|
214
|
+
* belongs to the next registration in the same module; reading that node
|
|
215
|
+
* publishes the other route's reply. Returns the request with its locator
|
|
216
|
+
* dropped, so it is answered by the registration on its own line, when:
|
|
217
|
+
* 1. a registration R sits on the request's line;
|
|
218
|
+
* 2. the located node is outside R and outside R's handler;
|
|
219
|
+
* 3. some ancestor of the node is a registration whose handler contains it.
|
|
220
|
+
* Anything else is returned unchanged. Matches on node shape, no names.
|
|
221
|
+
*/
|
|
222
|
+
private withoutForeignLocator;
|
|
211
223
|
private inferFunctionReturn;
|
|
212
224
|
/**
|
|
213
225
|
* Build a `function_return` inferred type from an already-resolved function
|
|
@@ -446,6 +458,15 @@ export declare class TypeInferrer {
|
|
|
446
458
|
* returns is a better statement of that body than the read (carrick#1382).
|
|
447
459
|
*/
|
|
448
460
|
private receivingCallOf;
|
|
461
|
+
/**
|
|
462
|
+
* A call's result read through the library store's label (carrick#2818):
|
|
463
|
+
* `whole` is the awaited type, `member` is that member of every non-nullish
|
|
464
|
+
* constituent of it, and `parse` is the awaited return of that method as the
|
|
465
|
+
* call returns it (a thenable's own `json()` is not on what it resolves to).
|
|
466
|
+
* A part the type lacks is a decided abstain, so the capture's own re-read
|
|
467
|
+
* of the raw call does not publish the envelope in its place.
|
|
468
|
+
*/
|
|
469
|
+
private labelledCallResult;
|
|
449
470
|
private inferCallResult;
|
|
450
471
|
/**
|
|
451
472
|
* The terminal of a call's def-use walk is a zero-argument `.text()` read of
|
|
@@ -970,6 +991,12 @@ export declare class TypeInferrer {
|
|
|
970
991
|
* arguments are what a rule naming `Task`, `Reply` or `Outcome` describes.
|
|
971
992
|
*/
|
|
972
993
|
private wrapperReadings;
|
|
994
|
+
/**
|
|
995
|
+
* The type of `type`'s member `name` at `node`, or `undefined` when the type
|
|
996
|
+
* has no such member. The one property read the payload-property rules and
|
|
997
|
+
* the library store's result label (carrick#2818) share.
|
|
998
|
+
*/
|
|
999
|
+
private readMemberType;
|
|
973
1000
|
/**
|
|
974
1001
|
* Extract the payload type from a matched wrapper. Returns null when the
|
|
975
1002
|
* rule matched the wrapper but no payload is recoverable from generics or
|