@esportsplus/typescript 0.32.0 → 0.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -49
- package/build/cli/tsc.d.ts +3 -2
- package/build/cli/tsc.js +15 -97
- package/build/{probe → guard}/adapter.d.ts +1 -2
- package/build/{probe → guard}/adapter.js +1 -4
- package/build/{probe → guard}/async/channel.d.ts +1 -1
- package/build/{probe → guard}/async/channel.js +11 -191
- package/build/{probe → guard}/async/value.d.ts +1 -2
- package/build/{probe → guard}/async/value.js +1 -4
- package/build/guard/channels.d.ts +4 -0
- package/build/guard/channels.js +13 -0
- package/build/{probe → guard}/exceptions/channel.d.ts +3 -2
- package/build/{probe → guard}/exceptions/channel.js +167 -107
- package/build/guard/exceptions/derive.d.ts +49 -0
- package/build/guard/exceptions/derive.js +478 -0
- package/build/guard/exceptions/resolve-js.d.ts +2 -0
- package/build/guard/exceptions/resolve-js.js +26 -0
- package/build/{probe → guard}/exceptions/value.d.ts +3 -2
- package/build/{probe → guard}/exceptions/value.js +12 -4
- package/build/{probe → guard}/kernel/analyze.d.ts +2 -1
- package/build/guard/kernel/analyze.js +84 -0
- package/build/guard/kernel/ast.d.ts +13 -0
- package/build/{probe → guard}/kernel/ast.js +22 -15
- package/build/guard/kernel/config.js +93 -0
- package/build/guard/kernel/fixpoint.d.ts +6 -0
- package/build/{probe → guard}/kernel/fixpoint.js +8 -48
- package/build/guard/kernel/graph.d.ts +4 -0
- package/build/guard/kernel/graph.js +268 -0
- package/build/{probe → guard}/kernel/ids.d.ts +2 -3
- package/build/{probe → guard}/kernel/ids.js +1 -6
- package/build/{probe → guard}/kernel/types.d.ts +3 -32
- package/build/{probe → guard}/overlay/base/async.jsonc +1 -1
- package/build/{probe → guard}/overlay/base/exceptions.jsonc +16 -3
- package/build/{probe → guard}/overlay/base/resources.jsonc +7 -8
- package/build/{probe → guard}/overlay/load.d.ts +3 -7
- package/build/{probe → guard}/overlay/load.js +37 -120
- package/build/{probe → guard}/resources/channel.d.ts +1 -1
- package/build/{probe → guard}/resources/channel.js +81 -159
- package/build/{probe → guard}/resources/value.d.ts +1 -2
- package/build/{probe → guard}/resources/value.js +1 -14
- package/build/lsp/diagnostics.d.ts +2 -2
- package/build/lsp/diagnostics.js +2 -2
- package/build/lsp/server.js +41 -3
- package/build/lsp/workspace.d.ts +6 -3
- package/build/lsp/workspace.js +19 -5
- package/build/tsconfig.d.ts +2 -1
- package/build/tsconfig.js +44 -102
- package/package.json +2 -2
- package/tsconfig.base.json +12 -19
- package/tsconfig.package.json +6 -1
- package/build/probe/channels.d.ts +0 -4
- package/build/probe/channels.js +0 -16
- package/build/probe/kernel/analyze.js +0 -68
- package/build/probe/kernel/ast.d.ts +0 -11
- package/build/probe/kernel/config.js +0 -209
- package/build/probe/kernel/fixpoint.d.ts +0 -6
- package/build/probe/kernel/graph.d.ts +0 -4
- package/build/probe/kernel/graph.js +0 -507
- package/build/probe/overlay/presets/express.jsonc +0 -25
- package/build/probe/overlay/presets/node.jsonc +0 -17
- /package/build/{probe → guard}/exceptions/jsdoc.d.ts +0 -0
- /package/build/{probe → guard}/exceptions/jsdoc.js +0 -0
- /package/build/{probe → guard}/kernel/config.d.ts +0 -0
- /package/build/{probe → guard}/kernel/format.d.ts +0 -0
- /package/build/{probe → guard}/kernel/format.js +0 -0
- /package/build/{probe → guard}/kernel/program.d.ts +0 -0
- /package/build/{probe → guard}/kernel/program.js +0 -0
- /package/build/{probe → guard}/kernel/types.js +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ThrowIndex } from './derive.js';
|
|
2
2
|
import { type ExceptionsValue } from './value.js';
|
|
3
|
+
import type { Channel } from '../kernel/types.js';
|
|
3
4
|
declare function overlayThrows(entry: unknown): boolean;
|
|
4
|
-
declare function createExceptionsChannel(): Channel<ExceptionsValue>;
|
|
5
|
+
declare function createExceptionsChannel(throwIndex: ThrowIndex): Channel<ExceptionsValue>;
|
|
5
6
|
export { createExceptionsChannel, overlayThrows };
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import * as NodeFS from 'node:fs';
|
|
2
2
|
import * as ts from '../adapter.js';
|
|
3
|
-
import { bodyOf,
|
|
3
|
+
import { bodyOf, constituents, isAwaited, paramSymbols } from '../kernel/ast.js';
|
|
4
4
|
import { isFunctionLike, locationOf } from '../kernel/ids.js';
|
|
5
5
|
import { declaredExceptions } from './jsdoc.js';
|
|
6
|
-
import {
|
|
6
|
+
import { deriveThrows } from './derive.js';
|
|
7
|
+
import { bottom, equals, isEmpty, join, originOf, originsOf, refOfType, render, single, subtract, top, TOP_KEY, widen, withOrigin, } from './value.js';
|
|
7
8
|
function overlayThrows(entry) {
|
|
8
9
|
const e = (entry ?? {});
|
|
9
10
|
return ((Array.isArray(e.exceptions) && e.exceptions.length > 0) ||
|
|
10
11
|
(Array.isArray(e.exceptionsFromCallbacks) &&
|
|
11
12
|
e.exceptionsFromCallbacks.length > 0));
|
|
12
13
|
}
|
|
13
|
-
function createExceptionsChannel() {
|
|
14
|
+
function createExceptionsChannel(throwIndex) {
|
|
14
15
|
let unhandledCache;
|
|
15
16
|
const typeCache = new Map();
|
|
17
|
+
const importIndex = new Map();
|
|
18
|
+
const namedTypeCache = new Map();
|
|
16
19
|
const typeAt = (checker, node) => {
|
|
17
20
|
if (typeCache.has(node)) {
|
|
18
21
|
return typeCache.get(node);
|
|
@@ -21,6 +24,69 @@ function createExceptionsChannel() {
|
|
|
21
24
|
typeCache.set(node, type);
|
|
22
25
|
return type;
|
|
23
26
|
};
|
|
27
|
+
const importsFor = (sf) => {
|
|
28
|
+
let imports = importIndex.get(sf);
|
|
29
|
+
if (imports) {
|
|
30
|
+
return imports;
|
|
31
|
+
}
|
|
32
|
+
imports = new Map();
|
|
33
|
+
importIndex.set(sf, imports);
|
|
34
|
+
for (const statement of sf.statements) {
|
|
35
|
+
if (!ts.isImportDeclaration(statement) ||
|
|
36
|
+
!ts.isStringLiteral(statement.moduleSpecifier) ||
|
|
37
|
+
!statement.importClause) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const specifier = statement.moduleSpecifier.text;
|
|
41
|
+
if (specifier.startsWith('.') || specifier.startsWith('/')) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const clause = statement.importClause;
|
|
45
|
+
if (clause.name) {
|
|
46
|
+
imports.set(clause.name.text, {
|
|
47
|
+
exportName: 'default',
|
|
48
|
+
isNamespace: false,
|
|
49
|
+
memberName: undefined,
|
|
50
|
+
specifier,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
54
|
+
for (const element of clause.namedBindings.elements) {
|
|
55
|
+
imports.set(element.name.text, {
|
|
56
|
+
exportName: (element.propertyName ?? element.name).text,
|
|
57
|
+
isNamespace: false,
|
|
58
|
+
memberName: undefined,
|
|
59
|
+
specifier,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (clause.namedBindings &&
|
|
64
|
+
ts.isNamespaceImport(clause.namedBindings)) {
|
|
65
|
+
imports.set(clause.namedBindings.name.text, {
|
|
66
|
+
exportName: '',
|
|
67
|
+
isNamespace: true,
|
|
68
|
+
memberName: undefined,
|
|
69
|
+
specifier,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return imports;
|
|
74
|
+
};
|
|
75
|
+
const namedTypeAt = (checker, name, location) => {
|
|
76
|
+
const sf = location.getSourceFile();
|
|
77
|
+
let names = namedTypeCache.get(sf);
|
|
78
|
+
if (!names) {
|
|
79
|
+
names = new Map();
|
|
80
|
+
namedTypeCache.set(sf, names);
|
|
81
|
+
}
|
|
82
|
+
if (names.has(name)) {
|
|
83
|
+
return names.get(name);
|
|
84
|
+
}
|
|
85
|
+
const sym = checker.resolveName(name, ts.SymbolFlags.Type, location, false);
|
|
86
|
+
const type = sym ? checker.getDeclaredTypeOfSymbol(sym) : undefined;
|
|
87
|
+
names.set(name, type);
|
|
88
|
+
return type;
|
|
89
|
+
};
|
|
24
90
|
const computeUnhandled = (ctx) => {
|
|
25
91
|
if (unhandledCache)
|
|
26
92
|
return unhandledCache;
|
|
@@ -39,7 +105,7 @@ function createExceptionsChannel() {
|
|
|
39
105
|
equals,
|
|
40
106
|
widen,
|
|
41
107
|
transfer(ctx) {
|
|
42
|
-
const env = makeEnv(ctx.checker,
|
|
108
|
+
const env = makeEnv(ctx.checker, throwIndex, ctx.fn, ctx.summaryOf, ctx.resolveCall, typeAt, undefined, undefined, importsFor, namedTypeAt);
|
|
43
109
|
const body = bodyOf(ctx.fn.node);
|
|
44
110
|
let value = body ? escapeOf(env, body, undefined) : bottom();
|
|
45
111
|
const decl = declaredExceptions(ctx.fn.node, ctx.checker);
|
|
@@ -49,12 +115,12 @@ function createExceptionsChannel() {
|
|
|
49
115
|
},
|
|
50
116
|
diagnose(ctx) {
|
|
51
117
|
const out = [];
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
118
|
+
const mode = reportMode(ctx);
|
|
119
|
+
const base = makeEnv(ctx.checker, throwIndex, ctx.fn, ctx.summaryOf, ctx.resolveCall, typeAt, new Map(), new Map(), importsFor, namedTypeAt, mode);
|
|
120
|
+
const env = mode === 'all'
|
|
121
|
+
? base
|
|
55
122
|
: {
|
|
56
123
|
...base,
|
|
57
|
-
escapeCache: new Map(),
|
|
58
124
|
unhandled: computeUnhandled(ctx),
|
|
59
125
|
};
|
|
60
126
|
const body = bodyOf(ctx.fn.node);
|
|
@@ -72,28 +138,33 @@ function createExceptionsChannel() {
|
|
|
72
138
|
});
|
|
73
139
|
}
|
|
74
140
|
}
|
|
75
|
-
if (
|
|
141
|
+
if (body) {
|
|
76
142
|
checkErrorCause(body, out);
|
|
77
|
-
|
|
143
|
+
}
|
|
144
|
+
if (body) {
|
|
78
145
|
walkDiagnostics(env, ctx, body, undefined, undefined, out);
|
|
146
|
+
}
|
|
79
147
|
return out;
|
|
80
148
|
},
|
|
81
149
|
};
|
|
82
150
|
}
|
|
83
|
-
function makeEnv(checker,
|
|
151
|
+
function makeEnv(checker, throwIndex, fn, summaryOf, resolveCall, typeAt, escapeCache, callCache, importsFor, namedTypeAt, report = undefined) {
|
|
84
152
|
const symbols = paramSymbols(checker, fn.node);
|
|
85
153
|
return {
|
|
86
154
|
checker,
|
|
87
|
-
|
|
88
|
-
sinks,
|
|
155
|
+
throwIndex,
|
|
89
156
|
fn,
|
|
90
157
|
summaryOf,
|
|
91
158
|
resolveCall,
|
|
92
|
-
escapeCache
|
|
159
|
+
escapeCache,
|
|
160
|
+
callCache,
|
|
161
|
+
importsFor,
|
|
162
|
+
namedTypeAt: (name, location) => namedTypeAt(checker, name, location),
|
|
93
163
|
typeTable: new Map(),
|
|
94
164
|
typeAt: (node) => typeAt(checker, node),
|
|
95
165
|
paramSymbols: symbols,
|
|
96
166
|
fromCallbacks: new Set(),
|
|
167
|
+
reportMode: report,
|
|
97
168
|
};
|
|
98
169
|
}
|
|
99
170
|
function escapeOf(env, node, binding) {
|
|
@@ -112,7 +183,7 @@ function escapeOf(env, node, binding) {
|
|
|
112
183
|
if (ts.isThrowStatement(n)) {
|
|
113
184
|
if (n.expression && !isBindingRef(env, n.expression, binding)) {
|
|
114
185
|
const thrown = valueOfType(env, env.typeAt(n.expression));
|
|
115
|
-
acc = join(acc, withOrigin(thrown, originOf(n)));
|
|
186
|
+
acc = join(acc, withOrigin(thrown, originOf(n, n.getSourceFile())));
|
|
116
187
|
}
|
|
117
188
|
if (n.expression)
|
|
118
189
|
ts.forEachChild(n.expression, visit);
|
|
@@ -310,6 +381,10 @@ function isSubclassOf(c, base, seen = new Set()) {
|
|
|
310
381
|
return false;
|
|
311
382
|
}
|
|
312
383
|
function callEscape(env, call) {
|
|
384
|
+
const cached = env.callCache?.get(call);
|
|
385
|
+
if (cached) {
|
|
386
|
+
return cached;
|
|
387
|
+
}
|
|
313
388
|
detectParamCall(env, call);
|
|
314
389
|
const res = env.resolveCall(call);
|
|
315
390
|
let v = bottom();
|
|
@@ -321,15 +396,59 @@ function callEscape(env, call) {
|
|
|
321
396
|
v = join(v, env.summaryOf(f).value);
|
|
322
397
|
}
|
|
323
398
|
}
|
|
324
|
-
if (res.overlay)
|
|
399
|
+
if (res.overlay) {
|
|
325
400
|
v = join(v, overlayValue(env, res, call));
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
401
|
+
}
|
|
402
|
+
else if (res.targets.length === 0) {
|
|
403
|
+
const derived = deriveForCall(env, call);
|
|
404
|
+
if (derived)
|
|
405
|
+
v = join(v, derived);
|
|
406
|
+
}
|
|
407
|
+
env.callCache?.set(call, v);
|
|
331
408
|
return v;
|
|
332
409
|
}
|
|
410
|
+
function deriveForCall(env, call) {
|
|
411
|
+
const info = importInfoForCall(env, call);
|
|
412
|
+
if (!info) {
|
|
413
|
+
return undefined;
|
|
414
|
+
}
|
|
415
|
+
const summary = deriveThrows(env.throwIndex, {
|
|
416
|
+
awaited: ts.isCallExpression(call) && isAwaited(call),
|
|
417
|
+
exportName: info.exportName,
|
|
418
|
+
importerFileName: call.getSourceFile().fileName,
|
|
419
|
+
memberName: info.memberName,
|
|
420
|
+
specifier: info.specifier,
|
|
421
|
+
});
|
|
422
|
+
if (!summary) {
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
let v = bottom();
|
|
426
|
+
for (const [cls, origins] of summary.classes) {
|
|
427
|
+
let cv = namedValue(env, cls, call);
|
|
428
|
+
for (const origin of origins) {
|
|
429
|
+
cv = withOrigin(cv, origin);
|
|
430
|
+
}
|
|
431
|
+
v = join(v, cv);
|
|
432
|
+
}
|
|
433
|
+
return v;
|
|
434
|
+
}
|
|
435
|
+
function importInfoForCall(env, call) {
|
|
436
|
+
const imports = env.importsFor(call.getSourceFile());
|
|
437
|
+
const callee = call.expression;
|
|
438
|
+
if (ts.isIdentifier(callee)) {
|
|
439
|
+
return imports.get(callee.text);
|
|
440
|
+
}
|
|
441
|
+
if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.expression)) {
|
|
442
|
+
const imported = imports.get(callee.expression.text);
|
|
443
|
+
return imported?.isNamespace
|
|
444
|
+
? {
|
|
445
|
+
...imported,
|
|
446
|
+
exportName: callee.name.text,
|
|
447
|
+
}
|
|
448
|
+
: undefined;
|
|
449
|
+
}
|
|
450
|
+
return undefined;
|
|
451
|
+
}
|
|
333
452
|
function overlayValue(env, res, call) {
|
|
334
453
|
const entry = (res.overlay?.entry ?? {});
|
|
335
454
|
let v = bottom();
|
|
@@ -349,11 +468,9 @@ function overlayValue(env, res, call) {
|
|
|
349
468
|
return v;
|
|
350
469
|
}
|
|
351
470
|
function namedValue(env, name, location) {
|
|
352
|
-
const
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
if (t)
|
|
356
|
-
return valueOfType(env, t);
|
|
471
|
+
const type = env.namedTypeAt(name, location);
|
|
472
|
+
if (type) {
|
|
473
|
+
return valueOfType(env, type);
|
|
357
474
|
}
|
|
358
475
|
return single(name, name);
|
|
359
476
|
}
|
|
@@ -367,33 +484,6 @@ function detectParamCall(env, call) {
|
|
|
367
484
|
if (idx !== undefined)
|
|
368
485
|
env.fromCallbacks.add(idx);
|
|
369
486
|
}
|
|
370
|
-
function matchSink(env, call) {
|
|
371
|
-
if (!ts.isCallExpression(call))
|
|
372
|
-
return undefined;
|
|
373
|
-
const names = calleeSelectors(call.expression);
|
|
374
|
-
for (const s of env.sinks)
|
|
375
|
-
if (names.has(s.callee))
|
|
376
|
-
return s;
|
|
377
|
-
return undefined;
|
|
378
|
-
}
|
|
379
|
-
function applySink(v, sink) {
|
|
380
|
-
if (!sink.absorbs)
|
|
381
|
-
return bottom();
|
|
382
|
-
if (v.top)
|
|
383
|
-
return v;
|
|
384
|
-
const absorb = new Set(sink.absorbs);
|
|
385
|
-
const kept = new Map();
|
|
386
|
-
const keptOrigins = new Map();
|
|
387
|
-
for (const [k, d] of v.types) {
|
|
388
|
-
if (absorb.has(d))
|
|
389
|
-
continue;
|
|
390
|
-
kept.set(k, d);
|
|
391
|
-
const o = v.origins.get(k);
|
|
392
|
-
if (o)
|
|
393
|
-
keptOrigins.set(k, o);
|
|
394
|
-
}
|
|
395
|
-
return { top: false, types: kept, origins: keptOrigins };
|
|
396
|
-
}
|
|
397
487
|
function reportMode(ctx) {
|
|
398
488
|
const cc = ctx.channelConfig;
|
|
399
489
|
if (typeof cc === 'object' && cc !== null) {
|
|
@@ -403,15 +493,8 @@ function reportMode(ctx) {
|
|
|
403
493
|
}
|
|
404
494
|
return 'consumers';
|
|
405
495
|
}
|
|
406
|
-
function consumersOnly(
|
|
407
|
-
|
|
408
|
-
return mode === 'consumers' || mode === 'cross-module';
|
|
409
|
-
}
|
|
410
|
-
function errorCauseEnabled(ctx) {
|
|
411
|
-
const cc = ctx.channelConfig;
|
|
412
|
-
return (typeof cc === 'object' &&
|
|
413
|
-
cc !== null &&
|
|
414
|
-
cc['errorCause'] === true);
|
|
496
|
+
function consumersOnly(env) {
|
|
497
|
+
return env.reportMode === 'consumers' || env.reportMode === 'cross-module';
|
|
415
498
|
}
|
|
416
499
|
function hasCauseArg(node) {
|
|
417
500
|
for (const arg of node.arguments ?? []) {
|
|
@@ -482,19 +565,15 @@ function packageRootOf(fileName) {
|
|
|
482
565
|
}
|
|
483
566
|
return root;
|
|
484
567
|
}
|
|
485
|
-
function
|
|
486
|
-
|
|
487
|
-
if (res.targets.length === 0)
|
|
488
|
-
return true;
|
|
489
|
-
const home = packageRootOf(ctx.fn.fileName);
|
|
490
|
-
return res.targets.some((t) => packageRootOf(t.fileName) !== home);
|
|
568
|
+
function normalizeSlashes(fileName) {
|
|
569
|
+
return fileName.replace(/\\/g, '/');
|
|
491
570
|
}
|
|
492
|
-
function
|
|
571
|
+
function crossesBoundary(env, ctx, call, homeOf) {
|
|
493
572
|
const res = env.resolveCall(call);
|
|
494
573
|
if (res.targets.length === 0)
|
|
495
574
|
return true;
|
|
496
|
-
const home = ctx.fn.fileName
|
|
497
|
-
return res.targets.some((t) => t.fileName
|
|
575
|
+
const home = homeOf(ctx.fn.fileName);
|
|
576
|
+
return res.targets.some((t) => homeOf(t.fileName) !== home);
|
|
498
577
|
}
|
|
499
578
|
function reachesTop(env, rem) {
|
|
500
579
|
const u = env.unhandled;
|
|
@@ -506,6 +585,9 @@ function reachesTop(env, rem) {
|
|
|
506
585
|
return false;
|
|
507
586
|
}
|
|
508
587
|
function walkDiagnostics(env, ctx, node, binding, remainder, out) {
|
|
588
|
+
const homeOf = env.reportMode === 'cross-module'
|
|
589
|
+
? normalizeSlashes
|
|
590
|
+
: packageRootOf;
|
|
509
591
|
const visit = (n) => {
|
|
510
592
|
if (isFunctionLike(n))
|
|
511
593
|
return;
|
|
@@ -515,7 +597,7 @@ function walkDiagnostics(env, ctx, node, binding, remainder, out) {
|
|
|
515
597
|
}
|
|
516
598
|
if (ts.isThrowStatement(n)) {
|
|
517
599
|
if (n.expression) {
|
|
518
|
-
if (!consumersOnly(
|
|
600
|
+
if (!consumersOnly(env)) {
|
|
519
601
|
if (isBindingRef(env, n.expression, binding)) {
|
|
520
602
|
if (remainder && !isEmpty(remainder))
|
|
521
603
|
out.push(throwDiagnostic(ctx, n, remainder));
|
|
@@ -532,13 +614,11 @@ function walkDiagnostics(env, ctx, node, binding, remainder, out) {
|
|
|
532
614
|
}
|
|
533
615
|
if (ts.isCallExpression(n) || ts.isNewExpression(n)) {
|
|
534
616
|
const rem = callEscape(env, n);
|
|
535
|
-
const mode = reportMode
|
|
617
|
+
const mode = env.reportMode;
|
|
536
618
|
const report = mode === 'all'
|
|
537
619
|
? true
|
|
538
|
-
:
|
|
539
|
-
|
|
540
|
-
: crossesPackageBoundary(env, ctx, n) &&
|
|
541
|
-
reachesTop(env, rem);
|
|
620
|
+
: crossesBoundary(env, ctx, n, homeOf) &&
|
|
621
|
+
reachesTop(env, rem);
|
|
542
622
|
if (!isEmpty(rem) && report)
|
|
543
623
|
out.push(callDiagnostic(env, ctx, n, rem));
|
|
544
624
|
ts.forEachChild(n, visit);
|
|
@@ -562,22 +642,8 @@ function handleTry(env, ctx, n, binding, remainder, out) {
|
|
|
562
642
|
if (n.finallyBlock)
|
|
563
643
|
walkDiagnostics(env, ctx, n.finallyBlock, binding, remainder, out);
|
|
564
644
|
}
|
|
565
|
-
function originOf(node) {
|
|
566
|
-
const sf = node.getSourceFile();
|
|
567
|
-
const start = node.getStart(sf);
|
|
568
|
-
const { line, character } = sf.getLineAndCharacterOfPosition(start);
|
|
569
|
-
const raw = node.getText(sf).replace(/\s+/g, ' ').trim();
|
|
570
|
-
return {
|
|
571
|
-
fileName: sf.fileName,
|
|
572
|
-
pos: start,
|
|
573
|
-
end: node.getEnd(),
|
|
574
|
-
line: line + 1,
|
|
575
|
-
column: character + 1,
|
|
576
|
-
text: raw.length > 120 ? `${raw.slice(0, 117)}…` : raw,
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
645
|
function relatedFromOrigins(origins) {
|
|
580
|
-
return origins.
|
|
646
|
+
return origins.map((o) => ({
|
|
581
647
|
message: o.text,
|
|
582
648
|
location: {
|
|
583
649
|
fileName: o.fileName,
|
|
@@ -599,7 +665,7 @@ function callDiagnostic(env, ctx, call, rem) {
|
|
|
599
665
|
location: locationOf(call, call.getSourceFile()),
|
|
600
666
|
related: origins.length > 0
|
|
601
667
|
? relatedFromOrigins(origins)
|
|
602
|
-
: buildRelated(
|
|
668
|
+
: buildRelated(res.targets),
|
|
603
669
|
};
|
|
604
670
|
}
|
|
605
671
|
function throwDiagnostic(ctx, node, rem) {
|
|
@@ -607,7 +673,7 @@ function throwDiagnostic(ctx, node, rem) {
|
|
|
607
673
|
channel: 'exceptions',
|
|
608
674
|
message: `Throw may throw ${render(rem)} with no catch on the path to \`${ctx.fn.name}\``,
|
|
609
675
|
location: locationOf(node, node.getSourceFile()),
|
|
610
|
-
related:
|
|
676
|
+
related: [],
|
|
611
677
|
};
|
|
612
678
|
}
|
|
613
679
|
function calleeDisplay(res, call) {
|
|
@@ -615,16 +681,16 @@ function calleeDisplay(res, call) {
|
|
|
615
681
|
return res.overlay.symbol;
|
|
616
682
|
if (res.targets[0])
|
|
617
683
|
return res.targets[0].name;
|
|
618
|
-
const callee =
|
|
619
|
-
|
|
620
|
-
: undefined;
|
|
621
|
-
if (callee && ts.isPropertyAccessExpression(callee))
|
|
684
|
+
const callee = call.expression;
|
|
685
|
+
if (ts.isPropertyAccessExpression(callee)) {
|
|
622
686
|
return callee.getText();
|
|
623
|
-
|
|
687
|
+
}
|
|
688
|
+
if (ts.isIdentifier(callee)) {
|
|
624
689
|
return callee.text;
|
|
690
|
+
}
|
|
625
691
|
return undefined;
|
|
626
692
|
}
|
|
627
|
-
function buildRelated(
|
|
693
|
+
function buildRelated(targets) {
|
|
628
694
|
const related = [];
|
|
629
695
|
for (const t of targets) {
|
|
630
696
|
related.push({
|
|
@@ -632,19 +698,13 @@ function buildRelated(ctx, targets) {
|
|
|
632
698
|
location: locationOf(t.node, t.sourceFile),
|
|
633
699
|
});
|
|
634
700
|
}
|
|
635
|
-
for (const f of ctx.pathToBoundary(ctx.fn)) {
|
|
636
|
-
related.push({
|
|
637
|
-
message: `on the path to boundary via ${f.name}`,
|
|
638
|
-
location: locationOf(f.node, f.sourceFile),
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
701
|
return related;
|
|
642
702
|
}
|
|
643
703
|
function valueOfType(env, type) {
|
|
644
704
|
let v = bottom();
|
|
645
705
|
if (!type)
|
|
646
706
|
return v;
|
|
647
|
-
for (const t of
|
|
707
|
+
for (const t of constituents(type)) {
|
|
648
708
|
const r = refOfType(env.checker, t);
|
|
649
709
|
if (r.top) {
|
|
650
710
|
v = join(v, top());
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as ts from '../adapter.js';
|
|
2
|
+
import { API } from 'typescript/unstable/sync';
|
|
3
|
+
import type { ExceptionOrigin } from './value.js';
|
|
4
|
+
type ImportTarget = {
|
|
5
|
+
readonly exportName: string;
|
|
6
|
+
readonly specifier: string;
|
|
7
|
+
};
|
|
8
|
+
type FileIndex = {
|
|
9
|
+
readonly classes: Map<string, ts.Node>;
|
|
10
|
+
readonly exportsByName: Map<string, ts.Node>;
|
|
11
|
+
readonly fns: Map<string, ts.Node>;
|
|
12
|
+
readonly imports: Map<string, ImportTarget>;
|
|
13
|
+
readonly namespaces: Map<string, string>;
|
|
14
|
+
readonly reexportAll: string | undefined;
|
|
15
|
+
readonly reexports: Map<string, ImportTarget>;
|
|
16
|
+
};
|
|
17
|
+
type ParsedFile = {
|
|
18
|
+
readonly fileIndex: FileIndex | null;
|
|
19
|
+
readonly mtimeMs: number;
|
|
20
|
+
readonly size: number;
|
|
21
|
+
readonly sourceFile: ts.SourceFile | null;
|
|
22
|
+
};
|
|
23
|
+
type Cached = {
|
|
24
|
+
readonly async: boolean;
|
|
25
|
+
readonly classes: Map<string, ExceptionOrigin[]>;
|
|
26
|
+
} | null;
|
|
27
|
+
type ThrowIndex = {
|
|
28
|
+
api: API | null;
|
|
29
|
+
readonly contents: Map<string, string>;
|
|
30
|
+
nextProject: number;
|
|
31
|
+
readonly parsed: Map<string, ParsedFile>;
|
|
32
|
+
readonly resolved: Map<string, string | undefined>;
|
|
33
|
+
readonly snapshots: ReturnType<API['updateSnapshot']>[];
|
|
34
|
+
readonly summaries: Map<string, Cached>;
|
|
35
|
+
};
|
|
36
|
+
type DerivedSummary = {
|
|
37
|
+
readonly classes: ReadonlyMap<string, ReadonlyArray<ExceptionOrigin>>;
|
|
38
|
+
};
|
|
39
|
+
type DeriveParams = {
|
|
40
|
+
readonly awaited: boolean;
|
|
41
|
+
readonly exportName: string;
|
|
42
|
+
readonly importerFileName: string;
|
|
43
|
+
readonly memberName: string | undefined;
|
|
44
|
+
readonly specifier: string;
|
|
45
|
+
};
|
|
46
|
+
declare function createThrowIndex(): ThrowIndex;
|
|
47
|
+
declare function disposeThrowIndex(index: ThrowIndex): void;
|
|
48
|
+
declare function deriveThrows(index: ThrowIndex, params: DeriveParams): DerivedSummary | undefined;
|
|
49
|
+
export { createThrowIndex, deriveThrows, disposeThrowIndex, type DerivedSummary, type ThrowIndex };
|