carrick 0.3.125 → 0.3.127
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/api.d.ts +5 -1
- package/sidecar/dist/src/capture/deno-project.d.ts +7 -0
- package/sidecar/dist/src/capture/deno-project.js +7 -0
- package/sidecar/dist/src/declaration-attribution.d.ts +11 -0
- package/sidecar/dist/src/declaration-attribution.js +16 -0
- package/sidecar/dist/src/implementations.d.ts +43 -0
- package/sidecar/dist/src/implementations.js +224 -0
- package/sidecar/dist/src/index.js +48 -1
- package/sidecar/dist/src/library-claims.d.ts +17 -2
- package/sidecar/dist/src/library-claims.js +297 -52
- package/sidecar/dist/src/position-rows.d.ts +119 -1
- package/sidecar/dist/src/position-rows.js +163 -9
- package/sidecar/dist/src/project-loader.d.ts +15 -0
- package/sidecar/dist/src/project-loader.js +16 -0
- package/sidecar/dist/src/retype.js +88 -8
- package/sidecar/dist/src/type-inferrer.d.ts +149 -8
- package/sidecar/dist/src/type-inferrer.js +569 -64
- package/sidecar/dist/src/types.d.ts +54 -2
- package/sidecar/dist/src/validators.d.ts +73 -0
- package/sidecar/dist/src/validators.js +10 -0
|
@@ -71,6 +71,17 @@ export declare const FLAG_TOO_MANY = 16;
|
|
|
71
71
|
export declare const FLAG_PUBLISHED = 32;
|
|
72
72
|
/** The declaration is what its module exports as `export =` or `default` (carrick#2508). */
|
|
73
73
|
export declare const FLAG_MODULE_DEFAULT = 64;
|
|
74
|
+
/**
|
|
75
|
+
* A `call` row only: the call's declared return is the result of the
|
|
76
|
+
* function it is handed (`ReturnType<F>`, a bare type parameter the handed
|
|
77
|
+
* function returns, or an awaitable of one), so the library runs it and
|
|
78
|
+
* hands its result back (carrick#2634). Set when the call passes at least
|
|
79
|
+
* one argument at a function-typed parameter and every such parameter
|
|
80
|
+
* meets that return. The last free bit of the `u8`: the next flag widens
|
|
81
|
+
* the field and bumps the format. Pinned to `FLAG_RUNS_HANDED` in
|
|
82
|
+
* `src/position_rows.rs` by `position-rows-runs-handed.test.ts`.
|
|
83
|
+
*/
|
|
84
|
+
export declare const FLAG_RUNS_HANDED = 128;
|
|
74
85
|
/** The most `decl` rows one position lists. */
|
|
75
86
|
export declare const DECL_CAP = 16;
|
|
76
87
|
/** The kinds {@link kindOf} gives a node; `decl` and `jsx` rows are written beside them. */
|
|
@@ -109,14 +120,26 @@ export interface PositionRowsOptions {
|
|
|
109
120
|
export declare function writePositionRows(options: PositionRowsOptions): PositionRowsCounts;
|
|
110
121
|
/** What a declaration's file is written as in a row's `decl_file`: `lib:<name>` for the default library, else `PathNames`'. */
|
|
111
122
|
export declare function declaringFileName(program: ts.Program, paths: PathNames, file: ts.SourceFile): string | null;
|
|
123
|
+
/** The installed package directory a resolved file lies in, and its name, as the module graph places it. */
|
|
124
|
+
export type PackageDirectoryOf = (fileName: string) => {
|
|
125
|
+
directory: string;
|
|
126
|
+
name: string;
|
|
127
|
+
} | undefined;
|
|
112
128
|
/**
|
|
113
129
|
* Names for the files rows point at, never an absolute path: relative to the
|
|
114
130
|
* scanned repo's root when inside it (its real path too, so a root reached
|
|
115
131
|
* through a link still contains its files), `lib:<name>` for the compiler's
|
|
116
132
|
* default library, `pkg:<name>/<path>` for an installed package outside the
|
|
117
133
|
* root, and nothing otherwise.
|
|
134
|
+
*
|
|
135
|
+
* An installed package outside the root is found by its path's last
|
|
136
|
+
* `node_modules` segment, else by `packageDirectoryOf`: the module graph's
|
|
137
|
+
* answer where the resolver serves a package from a cache whose path has no
|
|
138
|
+
* `node_modules` segment (carrick#2599). Either way the directory must hold a
|
|
139
|
+
* package.json.
|
|
118
140
|
*/
|
|
119
141
|
export declare class PathNames {
|
|
142
|
+
private readonly packageDirectoryOf;
|
|
120
143
|
private readonly roots;
|
|
121
144
|
private readonly packageNames;
|
|
122
145
|
/**
|
|
@@ -126,7 +149,7 @@ export declare class PathNames {
|
|
|
126
149
|
*/
|
|
127
150
|
private readonly declaringFiles;
|
|
128
151
|
private readonly declaringPackages;
|
|
129
|
-
constructor(scanRoot: string);
|
|
152
|
+
constructor(scanRoot: string, packageDirectoryOf?: PackageDirectoryOf);
|
|
130
153
|
/** The root `file` lies under, and its path from there; `undefined` outside every root. */
|
|
131
154
|
private inside;
|
|
132
155
|
/** A request file's name: relative to the root, which every file the scanner sends is inside. */
|
|
@@ -151,5 +174,100 @@ export declare class PathNames {
|
|
|
151
174
|
*/
|
|
152
175
|
scrubType(text: string): string;
|
|
153
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* The rows of one program's files. The `implementations` action
|
|
179
|
+
* (`implementations.ts`, carrick#2432) reads a call's symbol and names its
|
|
180
|
+
* answers through the same walker, so they join as the rows do.
|
|
181
|
+
*/
|
|
182
|
+
export declare class PositionWalker {
|
|
183
|
+
private readonly program;
|
|
184
|
+
private readonly paths;
|
|
185
|
+
private readonly loader;
|
|
186
|
+
private readonly checker;
|
|
187
|
+
/** Each module's exports by name, and its `export =` and `default` targets, aliases followed. */
|
|
188
|
+
private readonly moduleExports;
|
|
189
|
+
constructor(program: ts.Program, paths: PathNames, loader: ProjectLoader);
|
|
190
|
+
rowsOf(sourceFile: ts.SourceFile): PositionRow[];
|
|
191
|
+
private row;
|
|
192
|
+
/**
|
|
193
|
+
* Whether a call's declared return is the result of the function it is
|
|
194
|
+
* handed (carrick#2634), read from the declared signature through public
|
|
195
|
+
* checker calls. See {@link FLAG_RUNS_HANDED}.
|
|
196
|
+
*/
|
|
197
|
+
private runsHanded;
|
|
198
|
+
/** The call signatures of a parameter's type, a type parameter read through its constraint, `null` and `undefined` skipped. */
|
|
199
|
+
private callSignaturesOf;
|
|
200
|
+
/** The compiler's own awaited type differs from the type: `Promise<R>`, `PromiseLike<R>`. */
|
|
201
|
+
private isAwaitable;
|
|
202
|
+
/**
|
|
203
|
+
* An intrinsic element's type: the attributes `JSX.IntrinsicElements`
|
|
204
|
+
* gives its tag. The compiler types an intrinsic tag name itself as the
|
|
205
|
+
* error type, though the name resolves. A tag is intrinsic when it is an
|
|
206
|
+
* identifier that starts with a lowercase letter or holds a `-`, as the
|
|
207
|
+
* language reads it.
|
|
208
|
+
*/
|
|
209
|
+
private intrinsicProps;
|
|
210
|
+
/** How rows name a position in a program file: its file, 1-based line and package. */
|
|
211
|
+
located(declaringFile: ts.SourceFile, position: number): {
|
|
212
|
+
declFile: string | null;
|
|
213
|
+
declLine: number;
|
|
214
|
+
declPackage: string | null;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* The declaration a member with none is attributed to (carrick#2448): the
|
|
218
|
+
* mapped type node, or the alias naming it, of the receiver's type. A
|
|
219
|
+
* mapped type's members are made by the checker and have no declaration of
|
|
220
|
+
* their own. This is the owner `memberTypeWithoutDeclaration` reads such a
|
|
221
|
+
* member at (type-structural-expander.ts): the type's symbol, else its
|
|
222
|
+
* alias symbol. A union or intersection receiver contributes the one
|
|
223
|
+
* constituent that has the property; with several the row is left as it is.
|
|
224
|
+
*/
|
|
225
|
+
private ownerDeclaration;
|
|
226
|
+
/** The declaration of a type's symbol, else of its alias symbol: a mapped type node, or the alias naming it. */
|
|
227
|
+
private typeDeclaration;
|
|
228
|
+
/**
|
|
229
|
+
* How `declaration`'s module publishes `symbol`: {@link FLAG_PUBLISHED}
|
|
230
|
+
* when under the symbol's own name (or as a global), and
|
|
231
|
+
* {@link FLAG_MODULE_DEFAULT} when as the module's `export =` or `default`.
|
|
232
|
+
* The module is the nearest ambient `declare module "…"` or the file.
|
|
233
|
+
*/
|
|
234
|
+
private publication;
|
|
235
|
+
/** A namespace member, found among the exports of the module it sits in. */
|
|
236
|
+
private publishedByExports;
|
|
237
|
+
private publishedIn;
|
|
238
|
+
/** The type of the object a `member` or `call` row's name is read on, if the name is read on one. */
|
|
239
|
+
private receiverOf;
|
|
240
|
+
/**
|
|
241
|
+
* The `decl` rows of a `call` or `member` row (spans unset): one per
|
|
242
|
+
* declaration the receiver's union constituents give the member, when they
|
|
243
|
+
* give more than one (carrick#2448). A constituent's declaration is its
|
|
244
|
+
* member's ({@link attributedDeclaration}), or, for a member with none, the
|
|
245
|
+
* constituent type's own ({@link typeDeclaration}). Two instantiations of
|
|
246
|
+
* one generic class, or one class and `undefined`, give one, and no row.
|
|
247
|
+
* A throw writes one row flagged {@link FLAG_CHECKER_THREW}.
|
|
248
|
+
*/
|
|
249
|
+
private declRows;
|
|
250
|
+
/** The row's symbol, following aliases to a target that has a declaration. */
|
|
251
|
+
symbolOf(kind: PositionKind, node: ts.Node): ts.Symbol | undefined;
|
|
252
|
+
/**
|
|
253
|
+
* In a TypeScript file `const { a } = require("m")` binds `a` as `any` with
|
|
254
|
+
* the binding as its only declaration (TypeScript resolves `require` itself
|
|
255
|
+
* only in JavaScript files), so a trace stops there. Name the export the
|
|
256
|
+
* call resolves to instead (carrick#2454): for the binding itself, and for
|
|
257
|
+
* `m.x` where `m` is a whole-module binding. `undefined` when the name is
|
|
258
|
+
* not such a binding, the specifier is not a literal or does not resolve,
|
|
259
|
+
* or the module has no such export.
|
|
260
|
+
*/
|
|
261
|
+
private requiredExport;
|
|
262
|
+
/** The `require` binding a symbol is, when its only declaration is one. */
|
|
263
|
+
private requireBinding;
|
|
264
|
+
/** `"m"` of a call `require("m")` to the global `require`, else `undefined`. */
|
|
265
|
+
private requireSpecifier;
|
|
266
|
+
private exportOfRequired;
|
|
267
|
+
private host;
|
|
268
|
+
private resolutionHost;
|
|
269
|
+
}
|
|
270
|
+
/** Order two `decl_file` names, `null` last. */
|
|
271
|
+
export declare function compareNames(a: string | null, b: string | null): number;
|
|
154
272
|
/** The kind of row a node gives, if any (exported for the editor-parity test, carrick#2418). */
|
|
155
273
|
export declare function kindOf(node: ts.Node): NodeKind | undefined;
|
|
@@ -53,7 +53,7 @@ import * as path from 'node:path';
|
|
|
53
53
|
import * as zlib from 'node:zlib';
|
|
54
54
|
import { ts } from 'ts-morph';
|
|
55
55
|
import { WriteGuard, installedPackageDirectory, isDeclarationFileName, moduleExport } from './capture/index.js';
|
|
56
|
-
import { attributedDeclaration, installedPackageOf } from './declaration-attribution.js';
|
|
56
|
+
import { attributedDeclaration, installedPackageOf, typeDeclaration } from './declaration-attribution.js';
|
|
57
57
|
import { typeToStringAsDeclared } from './print-type.js';
|
|
58
58
|
/** The format's version, written in the header. */
|
|
59
59
|
export const POSITION_ROWS_VERSION = 4;
|
|
@@ -76,6 +76,17 @@ export const FLAG_TOO_MANY = 16;
|
|
|
76
76
|
export const FLAG_PUBLISHED = 32;
|
|
77
77
|
/** The declaration is what its module exports as `export =` or `default` (carrick#2508). */
|
|
78
78
|
export const FLAG_MODULE_DEFAULT = 64;
|
|
79
|
+
/**
|
|
80
|
+
* A `call` row only: the call's declared return is the result of the
|
|
81
|
+
* function it is handed (`ReturnType<F>`, a bare type parameter the handed
|
|
82
|
+
* function returns, or an awaitable of one), so the library runs it and
|
|
83
|
+
* hands its result back (carrick#2634). Set when the call passes at least
|
|
84
|
+
* one argument at a function-typed parameter and every such parameter
|
|
85
|
+
* meets that return. The last free bit of the `u8`: the next flag widens
|
|
86
|
+
* the field and bumps the format. Pinned to `FLAG_RUNS_HANDED` in
|
|
87
|
+
* `src/position_rows.rs` by `position-rows-runs-handed.test.ts`.
|
|
88
|
+
*/
|
|
89
|
+
export const FLAG_RUNS_HANDED = 128;
|
|
79
90
|
/** The most `decl` rows one position lists. */
|
|
80
91
|
export const DECL_CAP = 16;
|
|
81
92
|
const COMPARE_OPERATORS = new Set([
|
|
@@ -102,7 +113,7 @@ export function writePositionRows(options) {
|
|
|
102
113
|
const { loader, files, scanRoot, outPath, service } = options;
|
|
103
114
|
const outDir = path.dirname(outPath);
|
|
104
115
|
const guard = WriteGuard.of({ dirs: [outDir], protect: [loader.getRepoRoot(), scanRoot] });
|
|
105
|
-
const paths = new PathNames(scanRoot);
|
|
116
|
+
const paths = new PathNames(scanRoot, (file) => loader.packageDirectoryOf(file));
|
|
106
117
|
const lines = new Array(files.length);
|
|
107
118
|
const counts = {
|
|
108
119
|
files: files.length,
|
|
@@ -256,8 +267,15 @@ function fileLine(line) {
|
|
|
256
267
|
* through a link still contains its files), `lib:<name>` for the compiler's
|
|
257
268
|
* default library, `pkg:<name>/<path>` for an installed package outside the
|
|
258
269
|
* root, and nothing otherwise.
|
|
270
|
+
*
|
|
271
|
+
* An installed package outside the root is found by its path's last
|
|
272
|
+
* `node_modules` segment, else by `packageDirectoryOf`: the module graph's
|
|
273
|
+
* answer where the resolver serves a package from a cache whose path has no
|
|
274
|
+
* `node_modules` segment (carrick#2599). Either way the directory must hold a
|
|
275
|
+
* package.json.
|
|
259
276
|
*/
|
|
260
277
|
export class PathNames {
|
|
278
|
+
packageDirectoryOf;
|
|
261
279
|
roots;
|
|
262
280
|
packageNames = new Map();
|
|
263
281
|
/**
|
|
@@ -267,7 +285,8 @@ export class PathNames {
|
|
|
267
285
|
*/
|
|
268
286
|
declaringFiles = new Map();
|
|
269
287
|
declaringPackages = new Map();
|
|
270
|
-
constructor(scanRoot) {
|
|
288
|
+
constructor(scanRoot, packageDirectoryOf = () => undefined) {
|
|
289
|
+
this.packageDirectoryOf = packageDirectoryOf;
|
|
271
290
|
const resolved = path.resolve(scanRoot);
|
|
272
291
|
let real = resolved;
|
|
273
292
|
try {
|
|
@@ -306,7 +325,7 @@ export class PathNames {
|
|
|
306
325
|
const inside = this.inside(fileName);
|
|
307
326
|
if (inside)
|
|
308
327
|
return toSlashes(inside.rel);
|
|
309
|
-
const installed = installedPackageDirectory(this.roots[0], fileName);
|
|
328
|
+
const installed = installedPackageDirectory(this.roots[0], fileName) ?? this.packageDirectoryOf(fileName);
|
|
310
329
|
if (installed && fs.existsSync(path.join(installed.directory, 'package.json'))) {
|
|
311
330
|
return `pkg:${installed.name}/${toSlashes(path.relative(installed.directory, fileName))}`;
|
|
312
331
|
}
|
|
@@ -381,8 +400,12 @@ export class PathNames {
|
|
|
381
400
|
function toSlashes(p) {
|
|
382
401
|
return p.split(path.sep).join('/');
|
|
383
402
|
}
|
|
384
|
-
/**
|
|
385
|
-
|
|
403
|
+
/**
|
|
404
|
+
* The rows of one program's files. The `implementations` action
|
|
405
|
+
* (`implementations.ts`, carrick#2432) reads a call's symbol and names its
|
|
406
|
+
* answers through the same walker, so they join as the rows do.
|
|
407
|
+
*/
|
|
408
|
+
export class PositionWalker {
|
|
386
409
|
program;
|
|
387
410
|
paths;
|
|
388
411
|
loader;
|
|
@@ -426,6 +449,8 @@ class PositionWalker {
|
|
|
426
449
|
if (type.flags & ts.TypeFlags.Any) {
|
|
427
450
|
flags |= type.intrinsicName === 'error' ? FLAG_ERROR_TYPE : FLAG_ANY;
|
|
428
451
|
}
|
|
452
|
+
if (kind === 'call' && this.runsHanded(node))
|
|
453
|
+
flags |= FLAG_RUNS_HANDED;
|
|
429
454
|
const typeText = this.paths.scrubType(typeToStringAsDeclared(this.checker, type, undefined));
|
|
430
455
|
if (!symbol)
|
|
431
456
|
return [kind, start, end, null, null, null, null, typeText, flags];
|
|
@@ -453,6 +478,114 @@ class PositionWalker {
|
|
|
453
478
|
return [kind, start, end, null, null, null, null, null, FLAG_CHECKER_THREW];
|
|
454
479
|
}
|
|
455
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* Whether a call's declared return is the result of the function it is
|
|
483
|
+
* handed (carrick#2634), read from the declared signature through public
|
|
484
|
+
* checker calls. See {@link FLAG_RUNS_HANDED}.
|
|
485
|
+
*/
|
|
486
|
+
runsHanded(node) {
|
|
487
|
+
if (!ts.isCallExpression(node) && !ts.isNewExpression(node))
|
|
488
|
+
return false;
|
|
489
|
+
const args = node.arguments ?? [];
|
|
490
|
+
if (args.length === 0)
|
|
491
|
+
return false;
|
|
492
|
+
try {
|
|
493
|
+
const declaration = this.checker.getResolvedSignature(node)?.declaration;
|
|
494
|
+
if (!declaration || ts.isJSDocSignature(declaration))
|
|
495
|
+
return false;
|
|
496
|
+
const declared = this.checker.getSignatureFromDeclaration(declaration);
|
|
497
|
+
if (!declared)
|
|
498
|
+
return false;
|
|
499
|
+
const own = new Set(declared.getTypeParameters() ?? []);
|
|
500
|
+
const results = new Map();
|
|
501
|
+
const resultOf = (f) => {
|
|
502
|
+
let atom = results.get(f);
|
|
503
|
+
if (!atom)
|
|
504
|
+
results.set(f, (atom = {}));
|
|
505
|
+
return atom;
|
|
506
|
+
};
|
|
507
|
+
const atoms = (t, out, depth = 0) => {
|
|
508
|
+
if (depth > 8)
|
|
509
|
+
return out;
|
|
510
|
+
if (t.flags & ts.TypeFlags.TypeParameter) {
|
|
511
|
+
if (own.has(t))
|
|
512
|
+
out.add(t);
|
|
513
|
+
}
|
|
514
|
+
else if (t.flags & ts.TypeFlags.UnionOrIntersection) {
|
|
515
|
+
for (const member of t.types)
|
|
516
|
+
atoms(member, out, depth + 1);
|
|
517
|
+
}
|
|
518
|
+
else if (t.flags & ts.TypeFlags.Conditional) {
|
|
519
|
+
const f = resultOfConditional(t, own);
|
|
520
|
+
if (f)
|
|
521
|
+
out.add(resultOf(f));
|
|
522
|
+
}
|
|
523
|
+
else if (isReference(t) && this.isAwaitable(t)) {
|
|
524
|
+
for (const arg of this.checker.getTypeArguments(t))
|
|
525
|
+
atoms(arg, out, depth + 1);
|
|
526
|
+
}
|
|
527
|
+
return out;
|
|
528
|
+
};
|
|
529
|
+
const returned = atoms(this.checker.getReturnTypeOfSignature(declared), new Set());
|
|
530
|
+
if (returned.size === 0)
|
|
531
|
+
return false;
|
|
532
|
+
const parameters = declared.getParameters();
|
|
533
|
+
let handed = 0;
|
|
534
|
+
for (let i = 0; i < args.length; i++) {
|
|
535
|
+
const parameter = parameters[Math.min(i, parameters.length - 1)];
|
|
536
|
+
if (!parameter)
|
|
537
|
+
continue;
|
|
538
|
+
const isRest = parameter.valueDeclaration !== undefined &&
|
|
539
|
+
ts.isParameter(parameter.valueDeclaration) &&
|
|
540
|
+
parameter.valueDeclaration.dotDotDotToken !== undefined;
|
|
541
|
+
if (!isRest && i >= parameters.length)
|
|
542
|
+
continue;
|
|
543
|
+
let type = this.checker.getTypeOfSymbolAtLocation(parameter, declaration);
|
|
544
|
+
if (isRest) {
|
|
545
|
+
if (!isReference(type))
|
|
546
|
+
continue;
|
|
547
|
+
const [element] = this.checker.getTypeArguments(type);
|
|
548
|
+
if (!element)
|
|
549
|
+
continue;
|
|
550
|
+
type = element;
|
|
551
|
+
}
|
|
552
|
+
const signatures = this.callSignaturesOf(type);
|
|
553
|
+
if (signatures.length === 0)
|
|
554
|
+
continue;
|
|
555
|
+
handed++;
|
|
556
|
+
const mine = new Set();
|
|
557
|
+
if (type.flags & ts.TypeFlags.TypeParameter)
|
|
558
|
+
mine.add(resultOf(type));
|
|
559
|
+
else
|
|
560
|
+
for (const signature of signatures)
|
|
561
|
+
atoms(this.checker.getReturnTypeOfSignature(signature), mine);
|
|
562
|
+
if (![...mine].some((atom) => returned.has(atom)))
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
return handed > 0;
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/** The call signatures of a parameter's type, a type parameter read through its constraint, `null` and `undefined` skipped. */
|
|
572
|
+
callSignaturesOf(type) {
|
|
573
|
+
let t = type;
|
|
574
|
+
if (t.flags & ts.TypeFlags.TypeParameter)
|
|
575
|
+
t = this.checker.getBaseConstraintOfType(t) ?? t;
|
|
576
|
+
if (t.flags & ts.TypeFlags.Union) {
|
|
577
|
+
const kept = t.types.filter((m) => !(m.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)));
|
|
578
|
+
if (kept.length !== 1)
|
|
579
|
+
return [];
|
|
580
|
+
t = kept[0];
|
|
581
|
+
}
|
|
582
|
+
return this.checker.getSignaturesOfType(t, ts.SignatureKind.Call);
|
|
583
|
+
}
|
|
584
|
+
/** The compiler's own awaited type differs from the type: `Promise<R>`, `PromiseLike<R>`. */
|
|
585
|
+
isAwaitable(t) {
|
|
586
|
+
const awaited = this.checker.getAwaitedType(t);
|
|
587
|
+
return awaited !== undefined && awaited !== t;
|
|
588
|
+
}
|
|
456
589
|
/**
|
|
457
590
|
* An intrinsic element's type: the attributes `JSX.IntrinsicElements`
|
|
458
591
|
* gives its tag. The compiler types an intrinsic tag name itself as the
|
|
@@ -495,8 +628,7 @@ class PositionWalker {
|
|
|
495
628
|
}
|
|
496
629
|
/** The declaration of a type's symbol, else of its alias symbol: a mapped type node, or the alias naming it. */
|
|
497
630
|
typeDeclaration(type) {
|
|
498
|
-
|
|
499
|
-
return attributedDeclaration(() => this.program, owner?.declarations ?? []);
|
|
631
|
+
return typeDeclaration(() => this.program, type);
|
|
500
632
|
}
|
|
501
633
|
/**
|
|
502
634
|
* How `declaration`'s module publishes `symbol`: {@link FLAG_PUBLISHED}
|
|
@@ -742,7 +874,7 @@ function tail(row) {
|
|
|
742
874
|
return [row[3], row[4], row[5], row[6], row[7], row[8]];
|
|
743
875
|
}
|
|
744
876
|
/** Order two `decl_file` names, `null` last. */
|
|
745
|
-
function compareNames(a, b) {
|
|
877
|
+
export function compareNames(a, b) {
|
|
746
878
|
if (a === b)
|
|
747
879
|
return 0;
|
|
748
880
|
if (a === null)
|
|
@@ -751,6 +883,28 @@ function compareNames(a, b) {
|
|
|
751
883
|
return -1;
|
|
752
884
|
return a < b ? -1 : 1;
|
|
753
885
|
}
|
|
886
|
+
function isReference(t) {
|
|
887
|
+
return !!(t.flags & ts.TypeFlags.Object) && !!(t.objectFlags & ts.ObjectFlags.Reference);
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* The type parameter `F` of a conditional written `F extends (...) => infer R ? R : _`
|
|
891
|
+
* (`ReturnType<F>`): the result of `F`. `Parameters<F>` and the like infer
|
|
892
|
+
* elsewhere and give nothing.
|
|
893
|
+
*/
|
|
894
|
+
function resultOfConditional(t, own) {
|
|
895
|
+
if (!(t.checkType.flags & ts.TypeFlags.TypeParameter) || !own.has(t.checkType))
|
|
896
|
+
return undefined;
|
|
897
|
+
const node = t.root.node;
|
|
898
|
+
if (!ts.isFunctionTypeNode(node.extendsType))
|
|
899
|
+
return undefined;
|
|
900
|
+
const returns = node.extendsType.type;
|
|
901
|
+
if (!ts.isInferTypeNode(returns))
|
|
902
|
+
return undefined;
|
|
903
|
+
const yielded = node.trueType;
|
|
904
|
+
if (!ts.isTypeReferenceNode(yielded) || !ts.isIdentifier(yielded.typeName))
|
|
905
|
+
return undefined;
|
|
906
|
+
return yielded.typeName.text === returns.typeParameter.name.text ? t.checkType : undefined;
|
|
907
|
+
}
|
|
754
908
|
/** The kind of row a node gives, if any (exported for the editor-parity test, carrick#2418). */
|
|
755
909
|
export function kindOf(node) {
|
|
756
910
|
if (ts.isCallExpression(node) || ts.isNewExpression(node) || ts.isTaggedTemplateExpression(node)) {
|
|
@@ -182,6 +182,21 @@ export declare class ProjectLoader {
|
|
|
182
182
|
* through Deno, and for a file the workspace itself owns.
|
|
183
183
|
*/
|
|
184
184
|
packageOf(filePath: string): string | undefined;
|
|
185
|
+
/**
|
|
186
|
+
* The installed package directory a resolved file lies in, and its name,
|
|
187
|
+
* when the module graph places it (carrick#2599). `undefined` for a project
|
|
188
|
+
* that did not resolve through Deno: there the path says it.
|
|
189
|
+
*/
|
|
190
|
+
packageDirectoryOf(filePath: string): {
|
|
191
|
+
directory: string;
|
|
192
|
+
name: string;
|
|
193
|
+
} | undefined;
|
|
194
|
+
/**
|
|
195
|
+
* How the module graph resolves `name` from `from`, as the program did
|
|
196
|
+
* (carrick#2599). `undefined` for a project that did not resolve through
|
|
197
|
+
* Deno: there Node resolution is the program's.
|
|
198
|
+
*/
|
|
199
|
+
resolveThroughGraph(name: string, from: string, options: import('typescript').CompilerOptions): import('typescript').ResolvedModuleFull | undefined;
|
|
185
200
|
/**
|
|
186
201
|
* Check if the project has been successfully initialized
|
|
187
202
|
*/
|
|
@@ -502,6 +502,22 @@ export class ProjectLoader {
|
|
|
502
502
|
packageOf(filePath) {
|
|
503
503
|
return this.denoProject?.packageOf(filePath);
|
|
504
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* The installed package directory a resolved file lies in, and its name,
|
|
507
|
+
* when the module graph places it (carrick#2599). `undefined` for a project
|
|
508
|
+
* that did not resolve through Deno: there the path says it.
|
|
509
|
+
*/
|
|
510
|
+
packageDirectoryOf(filePath) {
|
|
511
|
+
return this.denoProject?.packageDirectoryOf(filePath);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* How the module graph resolves `name` from `from`, as the program did
|
|
515
|
+
* (carrick#2599). `undefined` for a project that did not resolve through
|
|
516
|
+
* Deno: there Node resolution is the program's.
|
|
517
|
+
*/
|
|
518
|
+
resolveThroughGraph(name, from, options) {
|
|
519
|
+
return this.denoProject?.resolve(name, from, options);
|
|
520
|
+
}
|
|
505
521
|
/**
|
|
506
522
|
* Check if the project has been successfully initialized
|
|
507
523
|
*/
|
|
@@ -548,14 +548,8 @@ function bodyReadsOf(call) {
|
|
|
548
548
|
const chained = bodyReadOn(top);
|
|
549
549
|
if (chained)
|
|
550
550
|
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))
|
|
551
|
+
const name = responseBinding(top);
|
|
552
|
+
if (!name)
|
|
559
553
|
return [];
|
|
560
554
|
const reads = [];
|
|
561
555
|
let handedOn = false;
|
|
@@ -583,6 +577,92 @@ function bodyReadsOf(call) {
|
|
|
583
577
|
}
|
|
584
578
|
return checkedBodyReads(reads);
|
|
585
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* The name the located call's response is bound to, when the source binds it
|
|
582
|
+
* in one of three ways: `const res = await call`, the first parameter of a
|
|
583
|
+
* `.then` callback (`call.then((res) => res.json())`), or an element of an
|
|
584
|
+
* array destructured off `Promise.all` (`const [a, b] = await Promise.all([call, ...])`).
|
|
585
|
+
*/
|
|
586
|
+
function responseBinding(top) {
|
|
587
|
+
const declaration = top.getParent();
|
|
588
|
+
if (declaration && Node.isVariableDeclaration(declaration) && declaration.getInitializer() === top) {
|
|
589
|
+
const name = declaration.getNameNode();
|
|
590
|
+
return Node.isIdentifier(name) ? name : undefined;
|
|
591
|
+
}
|
|
592
|
+
return thenParameter(top) ?? promiseAllElement(top);
|
|
593
|
+
}
|
|
594
|
+
/** `top.then((res) => ...)`: the callback's first parameter. */
|
|
595
|
+
function thenParameter(top) {
|
|
596
|
+
const access = top.getParent();
|
|
597
|
+
if (!access || !Node.isPropertyAccessExpression(access) || access.getExpression() !== top) {
|
|
598
|
+
return undefined;
|
|
599
|
+
}
|
|
600
|
+
if (access.getName() !== 'then')
|
|
601
|
+
return undefined;
|
|
602
|
+
const then = access.getParent();
|
|
603
|
+
if (!then || !Node.isCallExpression(then) || then.getExpression() !== access)
|
|
604
|
+
return undefined;
|
|
605
|
+
const callback = then.getArguments()[0];
|
|
606
|
+
if (!callback || !(Node.isArrowFunction(callback) || Node.isFunctionExpression(callback))) {
|
|
607
|
+
return undefined;
|
|
608
|
+
}
|
|
609
|
+
const name = callback.getParameters()[0]?.getNameNode();
|
|
610
|
+
return name && Node.isIdentifier(name) ? name : undefined;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* The name `top` is destructured to, when `top` is one element of the array
|
|
614
|
+
* literal handed to the language library's `Promise.all` and the call's
|
|
615
|
+
* awaited result is destructured to names:
|
|
616
|
+
* `const [a, b] = await Promise.all([call, other])`. An element after a
|
|
617
|
+
* spread has no position the destructuring can be read against.
|
|
618
|
+
*/
|
|
619
|
+
function promiseAllElement(top) {
|
|
620
|
+
const array = top.getParent();
|
|
621
|
+
if (!array || !Node.isArrayLiteralExpression(array))
|
|
622
|
+
return undefined;
|
|
623
|
+
const elements = array.getElements();
|
|
624
|
+
const index = elements.indexOf(top);
|
|
625
|
+
if (index < 0 || elements.slice(0, index + 1).some((e) => Node.isSpreadElement(e))) {
|
|
626
|
+
return undefined;
|
|
627
|
+
}
|
|
628
|
+
const all = array.getParent();
|
|
629
|
+
if (!all ||
|
|
630
|
+
!Node.isCallExpression(all) ||
|
|
631
|
+
all.getArguments()[0] !== array ||
|
|
632
|
+
!isLibraryPromiseAll(all)) {
|
|
633
|
+
return undefined;
|
|
634
|
+
}
|
|
635
|
+
let result = all;
|
|
636
|
+
while (Node.isAwaitExpression(result.getParentOrThrow()) ||
|
|
637
|
+
Node.isParenthesizedExpression(result.getParentOrThrow())) {
|
|
638
|
+
result = result.getParentOrThrow();
|
|
639
|
+
}
|
|
640
|
+
const declaration = result.getParent();
|
|
641
|
+
if (!declaration || !Node.isVariableDeclaration(declaration) || declaration.getInitializer() !== result) {
|
|
642
|
+
return undefined;
|
|
643
|
+
}
|
|
644
|
+
const pattern = declaration.getNameNode();
|
|
645
|
+
if (!Node.isArrayBindingPattern(pattern))
|
|
646
|
+
return undefined;
|
|
647
|
+
const element = pattern.getElements()[index];
|
|
648
|
+
if (!element || !Node.isBindingElement(element) || element.getDotDotDotToken())
|
|
649
|
+
return undefined;
|
|
650
|
+
const name = element.getNameNode();
|
|
651
|
+
return Node.isIdentifier(name) ? name : undefined;
|
|
652
|
+
}
|
|
653
|
+
/** `Promise.all` as the language library declares it, not a lookalike. */
|
|
654
|
+
function isLibraryPromiseAll(call) {
|
|
655
|
+
const callee = call.getExpression();
|
|
656
|
+
if (!Node.isPropertyAccessExpression(callee) || callee.getName() !== 'all')
|
|
657
|
+
return false;
|
|
658
|
+
const declaration = resolvedDeclaration(call);
|
|
659
|
+
if (!declaration)
|
|
660
|
+
return false;
|
|
661
|
+
return call
|
|
662
|
+
.getProject()
|
|
663
|
+
.getProgram()
|
|
664
|
+
.compilerObject.isSourceFileDefaultLibrary(declaration.getSourceFile());
|
|
665
|
+
}
|
|
586
666
|
/**
|
|
587
667
|
* Why these body reads cannot be retyped, or the reads to retype.
|
|
588
668
|
*
|