@cplieger/deadset-ts 3.12.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +4 -4
  2. package/dist/bin/node-host.js +10 -7
  3. package/dist/src/alias-chain.js +59 -7
  4. package/dist/src/analysis.js +217 -48
  5. package/dist/src/calls.js +23 -22
  6. package/dist/src/class-members.js +10 -11
  7. package/dist/src/components.js +4 -2
  8. package/dist/src/configured-declarations.js +56 -7
  9. package/dist/src/conformance-record.js +2 -2
  10. package/dist/src/dependencies.js +34 -17
  11. package/dist/src/deprecation.js +35 -24
  12. package/dist/src/destructuring.js +37 -29
  13. package/dist/src/discover.js +105 -28
  14. package/dist/src/edges.js +4 -1
  15. package/dist/src/entry-points.js +7 -0
  16. package/dist/src/enum-group.js +46 -40
  17. package/dist/src/exempt.js +42 -1
  18. package/dist/src/findings/completion.js +37 -8
  19. package/dist/src/findings/emitters.js +20 -6
  20. package/dist/src/findings/interfaces.js +7 -1
  21. package/dist/src/findings/intra-function.js +91 -2
  22. package/dist/src/findings/self-check.js +30 -7
  23. package/dist/src/findings/unused-declarations.js +15 -3
  24. package/dist/src/findings-pass.js +18 -11
  25. package/dist/src/framework-lifecycle.js +8 -6
  26. package/dist/src/implementations.js +45 -23
  27. package/dist/src/interface-satisfaction.js +30 -27
  28. package/dist/src/intra-function-parts.js +660 -0
  29. package/dist/src/inventory.js +85 -4
  30. package/dist/src/json-chunks.js +76 -0
  31. package/dist/src/kinds.js +337 -35
  32. package/dist/src/partial.js +23 -0
  33. package/dist/src/query.js +207 -0
  34. package/dist/src/references.js +92 -20
  35. package/dist/src/reflective-lookup.js +46 -4
  36. package/dist/src/report.js +14 -3
  37. package/dist/src/reporters/annotations.js +9 -5
  38. package/dist/src/reporters/json.js +3 -2
  39. package/dist/src/reporters/sarif.js +22 -16
  40. package/dist/src/reporters/template.js +112 -12
  41. package/dist/src/reporters/text.js +8 -6
  42. package/dist/src/roots.js +27 -11
  43. package/dist/src/serialization-contract.js +53 -32
  44. package/dist/src/session.js +79 -39
  45. package/dist/src/signatures.js +32 -0
  46. package/dist/src/suppress-file.js +29 -7
  47. package/dist/src/suppress-inline.js +8 -1
  48. package/dist/src/suppress.js +27 -0
  49. package/dist/src/sweep.js +4 -1
  50. package/dist/src/value-reach.js +44 -25
  51. package/dist/src/verbs/analyze.js +39 -14
  52. package/dist/src/verbs/describe.js +12 -8
  53. package/dist/src/verbs/explain.js +22 -9
  54. package/dist/src/verbs/print-projects.js +40 -7
  55. package/dist/src/verbs/print-retained.js +6 -2
  56. package/dist/src/verbs/print-roots.js +5 -1
  57. package/dist/src/version.js +1 -1
  58. package/jsr.json +1 -1
  59. package/package.json +3 -3
  60. package/src/alias-chain.ts +75 -11
  61. package/src/analysis.ts +385 -104
  62. package/src/calls.ts +10 -9
  63. package/src/class-members.ts +10 -11
  64. package/src/components.ts +4 -2
  65. package/src/configured-declarations.ts +80 -8
  66. package/src/conformance-record.ts +2 -2
  67. package/src/dependencies.ts +42 -20
  68. package/src/deprecation.ts +53 -27
  69. package/src/destructuring.ts +50 -39
  70. package/src/discover.ts +177 -33
  71. package/src/edges.ts +4 -1
  72. package/src/entry-points.ts +7 -0
  73. package/src/enum-group.ts +56 -42
  74. package/src/exempt.ts +50 -2
  75. package/src/finding.ts +5 -1
  76. package/src/findings/completion.ts +46 -10
  77. package/src/findings/emitter.ts +3 -0
  78. package/src/findings/emitters.ts +27 -6
  79. package/src/findings/interfaces.ts +7 -1
  80. package/src/findings/intra-function.ts +106 -3
  81. package/src/findings/self-check.ts +48 -7
  82. package/src/findings/unused-declarations.ts +18 -4
  83. package/src/findings-pass.ts +26 -11
  84. package/src/framework-lifecycle.ts +10 -6
  85. package/src/host.ts +5 -3
  86. package/src/implementations.ts +59 -23
  87. package/src/interface-satisfaction.ts +30 -27
  88. package/src/intra-function-parts.ts +889 -0
  89. package/src/inventory.ts +97 -4
  90. package/src/json-chunks.ts +87 -0
  91. package/src/kinds.ts +355 -41
  92. package/src/partial.ts +40 -0
  93. package/src/query.ts +522 -0
  94. package/src/references.ts +119 -38
  95. package/src/reflective-lookup.ts +56 -6
  96. package/src/report.ts +32 -4
  97. package/src/reporters/annotations.ts +23 -21
  98. package/src/reporters/json.ts +3 -2
  99. package/src/reporters/reporter.ts +2 -2
  100. package/src/reporters/sarif.ts +27 -18
  101. package/src/reporters/template.ts +119 -14
  102. package/src/reporters/text.ts +12 -12
  103. package/src/roots.ts +34 -12
  104. package/src/serialization-contract.ts +59 -40
  105. package/src/session.ts +146 -58
  106. package/src/signatures.ts +55 -0
  107. package/src/suppress-file.ts +40 -8
  108. package/src/suppress-inline.ts +8 -1
  109. package/src/suppress.ts +31 -0
  110. package/src/sweep.ts +9 -4
  111. package/src/value-reach.ts +66 -28
  112. package/src/verbs/analyze.ts +51 -14
  113. package/src/verbs/describe.ts +13 -9
  114. package/src/verbs/explain.ts +20 -9
  115. package/src/verbs/print-projects.ts +53 -7
  116. package/src/verbs/print-retained.ts +6 -2
  117. package/src/verbs/print-roots.ts +5 -1
  118. package/src/version.ts +1 -1
  119. package/dist/src/reporters/rules.js +0 -178
  120. package/src/reporters/rules.ts +0 -195
package/src/query.ts ADDED
@@ -0,0 +1,522 @@
1
+ /**
2
+ * The one way the analysis asks a project's checker anything. A question the compiler
3
+ * server panics on answers {@link UNANSWERED}, and a batch it panics on whole is asked
4
+ * again one question at a time; every caller reads an unanswered question as keeping a
5
+ * declaration live, and each is recorded once so a run can say where it was partial.
6
+ * Questions of one accessor about many locations go out together, through the array
7
+ * form where it has one and otherwise as one batch, one round trip per capped run.
8
+ */
9
+
10
+ import { isIdentifier, type Expression, type Node } from "@typescript/native/unstable/ast";
11
+ import type {
12
+ APIRequestGenerator,
13
+ Checker,
14
+ IndexInfo,
15
+ JSDocTagInfo,
16
+ Signature,
17
+ SignatureKind,
18
+ SymbolFlags,
19
+ Symbol as TSSymbol,
20
+ Type,
21
+ } from "@typescript/native/unstable/sync";
22
+
23
+ /**
24
+ * The greatest number of locations one batched request asks about. A batch is
25
+ * answered by an array of its own length, so an uncapped batch over a large file
26
+ * makes one answer proportional to that file. The figure bounds the size of one
27
+ * answer rather than the work: the median file is one batch at this cap and the
28
+ * largest production file a handful.
29
+ */
30
+ export const DEFAULT_BATCH_CAP = 4096;
31
+
32
+ /** The answer to a question the checker could not answer. */
33
+ export const UNANSWERED: unique symbol = Symbol("unanswered");
34
+
35
+ /** A checker's answer, or {@link UNANSWERED} where the server panicked on the question. */
36
+ export type Answer<T> = T | typeof UNANSWERED;
37
+
38
+ /** Whether one answer is an answer. */
39
+ export function isAnswered<T>(answer: Answer<T>): answer is T {
40
+ return answer !== UNANSWERED;
41
+ }
42
+
43
+ /**
44
+ * The stop a pass raises where it cannot go on without an answer the checker did not
45
+ * give. Whoever runs the pass catches it and keeps live everything the pass could
46
+ * have kept live, so a pass that throws it never computes a finding from the gap.
47
+ */
48
+ export class Unanswerable extends Error {
49
+ constructor() {
50
+ super("the checker did not answer a question this pass needs");
51
+ this.name = "Unanswerable";
52
+ }
53
+ }
54
+
55
+ /** The answer itself, or the stop of a pass that cannot go on without it. */
56
+ export function must<T>(answer: Answer<T>): T {
57
+ if (answer === UNANSWERED) {
58
+ throw new Unanswerable();
59
+ }
60
+ return answer;
61
+ }
62
+
63
+ /**
64
+ * Whether one failure is the server's report that a question panicked. The server
65
+ * recovers the panic and answers the question with its text, so the session
66
+ * survives it; any other failure, a closed channel among them, is not one this layer
67
+ * contains.
68
+ */
69
+ function panicked(error: unknown): boolean {
70
+ return error instanceof Error && error.message.startsWith("panic:");
71
+ }
72
+
73
+ /** Runs many questions in one round trip, answering each in order. */
74
+ export type Batch = <T>(questions: readonly APIRequestGenerator<T>[]) => T[];
75
+
76
+ /**
77
+ * Puts one question to the checker, by its accessor's name and the locations it asks
78
+ * about, and answers what it answers.
79
+ */
80
+ type Ask = <T>(accessor: string, locations: () => readonly string[], question: () => T) => T;
81
+
82
+ const ASK_DIRECTLY: Ask = (_accessor, _locations, question) => question();
83
+
84
+ /** One question the checker left unanswered, by the project it was asked in. */
85
+ export interface UnansweredQuestion {
86
+ /** The compiler configuration file of the project the question was asked in. */
87
+ readonly configFile: string;
88
+ /** The accessor that panicked. */
89
+ readonly accessor: string;
90
+ /** What was asked about: a file and offset, or a symbol's or a type's identity. */
91
+ readonly location: string;
92
+ }
93
+
94
+ /** What one run could not ask, each question once. */
95
+ export class UnansweredLog {
96
+ readonly #seen = new Map<string, UnansweredQuestion>();
97
+
98
+ /** Records one question, once however many times it is asked. */
99
+ note(question: UnansweredQuestion): void {
100
+ const key = [question.configFile, question.accessor, question.location].join("\u0000");
101
+ if (!this.#seen.has(key)) {
102
+ this.#seen.set(key, question);
103
+ }
104
+ }
105
+
106
+ /** Every question recorded, in the order first asked. */
107
+ get questions(): readonly UnansweredQuestion[] {
108
+ return [...this.#seen.values()];
109
+ }
110
+ }
111
+
112
+ function nodeLocation(node: Node): string {
113
+ return `${node.getSourceFile().fileName}:${String(node.pos)}`;
114
+ }
115
+
116
+ function symbolLocation(symbol: TSSymbol): string {
117
+ return `symbol ${String(symbol.id)} ${symbol.name}`;
118
+ }
119
+
120
+ function typeLocation(type: Type): string {
121
+ return `type ${String(type.id)}`;
122
+ }
123
+
124
+ /** One assignability question. */
125
+ interface Assignability {
126
+ readonly source: Type;
127
+ readonly target: Type;
128
+ }
129
+
130
+ /** The questions one project's analysis asks, each guarded. */
131
+ export interface Queries {
132
+ /** The symbol each node resolves to. */
133
+ symbolsAt(nodes: readonly Node[], cap?: number): Answer<TSSymbol | undefined>[];
134
+ /** The symbol one identifier names by name lookup at its position; nothing for another node. */
135
+ resolvedSymbol(node: Node): Answer<TSSymbol | undefined>;
136
+ /** The symbol the value of one shorthand property assignment names. */
137
+ shorthandValue(node: Node): Answer<TSSymbol | undefined>;
138
+ /** The symbol one alias names, one link along. */
139
+ immediateAliased(symbol: TSSymbol): Answer<TSSymbol | undefined>;
140
+ /** The symbol at the end of one alias's chain. */
141
+ aliased(symbol: TSSymbol): Answer<TSSymbol>;
142
+ resolveName(
143
+ name: string,
144
+ meaning: SymbolFlags,
145
+ location: Node | undefined,
146
+ excludeGlobals: boolean,
147
+ ): Answer<TSSymbol | undefined>;
148
+ exportsOfModule(module: TSSymbol): Answer<readonly TSSymbol[]>;
149
+ /** One symbol's member table. */
150
+ membersOf(symbol: TSSymbol): Answer<ReadonlyMap<string, TSSymbol>>;
151
+ /** One symbol's export table. */
152
+ exportsOf(symbol: TSSymbol): Answer<ReadonlyMap<string, TSSymbol>>;
153
+ /** The symbol that declares one symbol as a member. */
154
+ parentOf(symbol: TSSymbol): Answer<TSSymbol | undefined>;
155
+ /** The documentation tags of each symbol. */
156
+ jsDocTags(symbols: readonly TSSymbol[], cap?: number): Answer<readonly JSDocTagInfo[]>[];
157
+ /** The type at each node. */
158
+ typesAt(nodes: readonly Node[], cap?: number): Answer<Type | undefined>[];
159
+ typeAt(node: Node): Answer<Type | undefined>;
160
+ /** The type of each symbol. */
161
+ typesOfSymbols(symbols: readonly TSSymbol[], cap?: number): Answer<Type | undefined>[];
162
+ typeOfSymbol(symbol: TSSymbol): Answer<Type | undefined>;
163
+ declaredTypeOf(symbol: TSSymbol): Answer<Type>;
164
+ /** The type each value position expects. */
165
+ contextualTypes(nodes: readonly Expression[], cap?: number): Answer<Type | undefined>[];
166
+ propertiesOf(type: Type): Answer<readonly TSSymbol[]>;
167
+ indexInfosOf(type: Type): Answer<readonly IndexInfo[]>;
168
+ /** The type arguments of a type reference; none for another type. */
169
+ typeArguments(type: Type): Answer<readonly Type[]>;
170
+ nonNullable(type: Type): Answer<Type>;
171
+ isArray(type: Type): Answer<boolean>;
172
+ /** Whether each source is assignable to its target. */
173
+ assignableEach(pairs: readonly Assignability[], cap?: number): Answer<boolean>[];
174
+ /** The base types of a class or an interface; none for another type. */
175
+ baseTypes(type: Type): Answer<readonly Type[]>;
176
+ /** The constituents of a union or an intersection; the type itself for another type. */
177
+ constituents(type: Type): Answer<readonly Type[]>;
178
+ /** The generic type a type reference instantiates; the type itself for another type. */
179
+ targetOf(type: Type): Answer<Type>;
180
+ /** The symbol a type is declared by. */
181
+ symbolOfType(type: Type): Answer<TSSymbol | undefined>;
182
+ signaturesOf(type: Type, kind: SignatureKind): Answer<readonly Signature[]>;
183
+ resolvedSignature(node: Node): Answer<Signature | undefined>;
184
+ parameterType(signature: Signature, index: number): Answer<Type | undefined>;
185
+ signatureOf(declaration: Node): Answer<Signature | undefined>;
186
+ returnTypeOf(signature: Signature): Answer<Type | undefined>;
187
+ typeToString(type: Type): Answer<string>;
188
+ }
189
+
190
+ /**
191
+ * The guarded questions over one project's checker. `configFile` names the project
192
+ * in the log, `batch` sends many questions in one round trip, `log` is the run's,
193
+ * shared by every project, and every question is put through `ask`.
194
+ */
195
+ export function queriesOf(
196
+ checker: Checker,
197
+ configFile: string,
198
+ batch: Batch,
199
+ log: UnansweredLog,
200
+ ask: Ask = ASK_DIRECTLY,
201
+ ): Queries {
202
+ const note = (accessor: string, location: string): void => {
203
+ log.note({ configFile, accessor, location });
204
+ };
205
+
206
+ const one = <T>(accessor: string, location: () => string, question: () => T): Answer<T> => {
207
+ try {
208
+ return ask(accessor, () => [location()], question);
209
+ } catch (error: unknown) {
210
+ if (!panicked(error)) {
211
+ throw error;
212
+ }
213
+ note(accessor, location());
214
+ return UNANSWERED;
215
+ }
216
+ };
217
+
218
+ /**
219
+ * One question per item of `items`, in runs of at most `cap`, each run in one
220
+ * round trip. A run fails as a whole only where the server panics outside any one
221
+ * question, and is then asked one question at a time.
222
+ */
223
+ const each = <In, Out>(
224
+ accessor: string,
225
+ items: readonly In[],
226
+ cap: number,
227
+ locate: (item: In) => string,
228
+ question: (item: In) => APIRequestGenerator<Out>,
229
+ alone: (item: In) => Out,
230
+ ): Answer<Out>[] => {
231
+ function* guarded(item: In): APIRequestGenerator<Answer<Out>> {
232
+ try {
233
+ return yield* ask(
234
+ accessor,
235
+ () => [locate(item)],
236
+ () => question(item),
237
+ );
238
+ } catch (error: unknown) {
239
+ if (!panicked(error)) {
240
+ throw error;
241
+ }
242
+ note(accessor, locate(item));
243
+ return UNANSWERED;
244
+ }
245
+ }
246
+ const answers: Answer<Out>[] = [];
247
+ for (let from = 0; from < items.length; from += cap) {
248
+ const run = items.slice(from, from + cap);
249
+ try {
250
+ answers.push(...batch(run.map(guarded)));
251
+ } catch (error: unknown) {
252
+ if (!panicked(error)) {
253
+ throw error;
254
+ }
255
+ answers.push(
256
+ ...run.map((item) =>
257
+ one(
258
+ accessor,
259
+ () => locate(item),
260
+ () => alone(item),
261
+ ),
262
+ ),
263
+ );
264
+ }
265
+ }
266
+ return answers;
267
+ };
268
+
269
+ /**
270
+ * One accessor's array form over `items`, in runs of at most `cap`. A run the server
271
+ * panics on is asked again as two halves, down to one item, so the items it can
272
+ * answer are answered and only an item that panics alone is unanswered.
273
+ */
274
+ const many = <In, Out>(
275
+ accessor: string,
276
+ items: readonly In[],
277
+ cap: number,
278
+ locate: (item: In) => string,
279
+ question: (run: readonly In[]) => readonly Out[],
280
+ ): Answer<Out>[] => {
281
+ const answers: Answer<Out>[] = [];
282
+ const settle = (run: readonly In[]): void => {
283
+ try {
284
+ answers.push(
285
+ ...ask(
286
+ accessor,
287
+ () => run.map(locate),
288
+ () => question(run),
289
+ ),
290
+ );
291
+ return;
292
+ } catch (error: unknown) {
293
+ if (!panicked(error)) {
294
+ throw error;
295
+ }
296
+ }
297
+ const [only] = run;
298
+ if (run.length === 1 && only !== undefined) {
299
+ note(accessor, locate(only));
300
+ answers.push(UNANSWERED);
301
+ return;
302
+ }
303
+ const half = Math.ceil(run.length / 2);
304
+ settle(run.slice(0, half));
305
+ settle(run.slice(half));
306
+ };
307
+ for (let from = 0; from < items.length; from += cap) {
308
+ settle(items.slice(from, from + cap));
309
+ }
310
+ return answers;
311
+ };
312
+
313
+ return {
314
+ symbolsAt: (nodes, cap = DEFAULT_BATCH_CAP) =>
315
+ many("getSymbolAtLocation", nodes, cap, nodeLocation, (run) =>
316
+ checker.getSymbolAtLocation(run),
317
+ ),
318
+ resolvedSymbol: (node) =>
319
+ isIdentifier(node)
320
+ ? one(
321
+ "getResolvedSymbol",
322
+ () => nodeLocation(node),
323
+ () => checker.getResolvedSymbol(node),
324
+ )
325
+ : undefined,
326
+ shorthandValue: (node) =>
327
+ one(
328
+ "getShorthandAssignmentValueSymbol",
329
+ () => nodeLocation(node),
330
+ () => checker.getShorthandAssignmentValueSymbol(node),
331
+ ),
332
+ immediateAliased: (symbol) =>
333
+ one(
334
+ "getImmediateAliasedSymbol",
335
+ () => symbolLocation(symbol),
336
+ () => checker.getImmediateAliasedSymbol(symbol),
337
+ ),
338
+ aliased: (symbol) =>
339
+ one(
340
+ "getAliasedSymbol",
341
+ () => symbolLocation(symbol),
342
+ () => checker.getAliasedSymbol(symbol),
343
+ ),
344
+ resolveName: (name, meaning, location, excludeGlobals) =>
345
+ one(
346
+ "resolveName",
347
+ () => (location === undefined ? `name ${name}` : nodeLocation(location)),
348
+ () => checker.resolveName(name, meaning, location, excludeGlobals),
349
+ ),
350
+ exportsOfModule: (module) =>
351
+ one(
352
+ "getExportsOfModule",
353
+ () => symbolLocation(module),
354
+ () => checker.getExportsOfModule(module),
355
+ ),
356
+ membersOf: (symbol) =>
357
+ one(
358
+ "getMembers",
359
+ () => symbolLocation(symbol),
360
+ () => symbol.getMembers(),
361
+ ),
362
+ exportsOf: (symbol) =>
363
+ one(
364
+ "getExports",
365
+ () => symbolLocation(symbol),
366
+ () => symbol.getExports(),
367
+ ),
368
+ parentOf: (symbol) =>
369
+ one(
370
+ "getParent",
371
+ () => symbolLocation(symbol),
372
+ () => symbol.getParent(),
373
+ ),
374
+ jsDocTags: (symbols, cap = DEFAULT_BATCH_CAP) =>
375
+ each(
376
+ "getJsDocTags",
377
+ symbols,
378
+ cap,
379
+ symbolLocation,
380
+ (symbol) => symbol.getJsDocTags.gen(checker),
381
+ (symbol) => symbol.getJsDocTags(checker),
382
+ ),
383
+ typesAt: (nodes, cap = DEFAULT_BATCH_CAP) =>
384
+ many("getTypeAtLocation", nodes, cap, nodeLocation, (run) => checker.getTypeAtLocation(run)),
385
+ typeAt: (node) =>
386
+ one(
387
+ "getTypeAtLocation",
388
+ () => nodeLocation(node),
389
+ () => checker.getTypeAtLocation(node),
390
+ ),
391
+ typesOfSymbols: (symbols, cap = DEFAULT_BATCH_CAP) =>
392
+ many("getTypeOfSymbol", symbols, cap, symbolLocation, (run) => checker.getTypeOfSymbol(run)),
393
+ typeOfSymbol: (symbol) =>
394
+ one(
395
+ "getTypeOfSymbol",
396
+ () => symbolLocation(symbol),
397
+ () => checker.getTypeOfSymbol(symbol),
398
+ ),
399
+ declaredTypeOf: (symbol) =>
400
+ one(
401
+ "getDeclaredTypeOfSymbol",
402
+ () => symbolLocation(symbol),
403
+ () => checker.getDeclaredTypeOfSymbol(symbol),
404
+ ),
405
+ contextualTypes: (nodes, cap = DEFAULT_BATCH_CAP) =>
406
+ each(
407
+ "getContextualType",
408
+ nodes,
409
+ cap,
410
+ nodeLocation,
411
+ (node) => checker.getContextualType.gen(node),
412
+ (node) => checker.getContextualType(node),
413
+ ),
414
+ propertiesOf: (type) =>
415
+ one(
416
+ "getPropertiesOfType",
417
+ () => typeLocation(type),
418
+ () => checker.getPropertiesOfType(type),
419
+ ),
420
+ indexInfosOf: (type) =>
421
+ one(
422
+ "getIndexInfosOfType",
423
+ () => typeLocation(type),
424
+ () => checker.getIndexInfosOfType(type),
425
+ ),
426
+ typeArguments: (type) =>
427
+ type.isTypeReference()
428
+ ? one(
429
+ "getTypeArguments",
430
+ () => typeLocation(type),
431
+ () => checker.getTypeArguments(type),
432
+ )
433
+ : [],
434
+ nonNullable: (type) =>
435
+ one(
436
+ "getNonNullableType",
437
+ () => typeLocation(type),
438
+ () => checker.getNonNullableType(type),
439
+ ),
440
+ isArray: (type) =>
441
+ one(
442
+ "isArrayType",
443
+ () => typeLocation(type),
444
+ () => checker.isArrayType(type),
445
+ ),
446
+ assignableEach: (pairs, cap = DEFAULT_BATCH_CAP) =>
447
+ each(
448
+ "isTypeAssignableTo",
449
+ pairs,
450
+ cap,
451
+ (pair) => `${typeLocation(pair.source)} to ${typeLocation(pair.target)}`,
452
+ (pair) => checker.isTypeAssignableTo.gen(pair.source, pair.target),
453
+ (pair) => checker.isTypeAssignableTo(pair.source, pair.target),
454
+ ),
455
+ baseTypes: (type) =>
456
+ type.isClassOrInterface()
457
+ ? one(
458
+ "getBaseTypes",
459
+ () => typeLocation(type),
460
+ () => checker.getBaseTypes(type),
461
+ )
462
+ : [],
463
+ constituents: (type) =>
464
+ type.isUnionType() || type.isIntersectionType()
465
+ ? one(
466
+ "getTypes",
467
+ () => typeLocation(type),
468
+ () => type.getTypes(),
469
+ )
470
+ : [type],
471
+ targetOf: (type) =>
472
+ type.isTypeReference()
473
+ ? one(
474
+ "getTarget",
475
+ () => typeLocation(type),
476
+ () => type.getTarget(),
477
+ )
478
+ : type,
479
+ symbolOfType: (type) =>
480
+ one(
481
+ "getSymbol",
482
+ () => typeLocation(type),
483
+ () => type.getSymbol(),
484
+ ),
485
+ signaturesOf: (type, kind) =>
486
+ one(
487
+ "getSignaturesOfType",
488
+ () => typeLocation(type),
489
+ () => checker.getSignaturesOfType(type, kind),
490
+ ),
491
+ resolvedSignature: (node) =>
492
+ one(
493
+ "getResolvedSignature",
494
+ () => nodeLocation(node),
495
+ () => checker.getResolvedSignature(node),
496
+ ),
497
+ parameterType: (signature, index) =>
498
+ one(
499
+ "getParameterType",
500
+ () => `signature ${String(signature.id)} parameter ${String(index)}`,
501
+ () => checker.getParameterType(signature, index),
502
+ ),
503
+ signatureOf: (declaration) =>
504
+ one(
505
+ "getSignatureFromDeclaration",
506
+ () => nodeLocation(declaration),
507
+ () => checker.getSignatureFromDeclaration(declaration),
508
+ ),
509
+ returnTypeOf: (signature) =>
510
+ one(
511
+ "getReturnTypeOfSignature",
512
+ () => `signature ${String(signature.id)}`,
513
+ () => checker.getReturnTypeOfSignature(signature),
514
+ ),
515
+ typeToString: (type) =>
516
+ one(
517
+ "typeToString",
518
+ () => typeLocation(type),
519
+ () => checker.typeToString(type),
520
+ ),
521
+ };
522
+ }