@esportsplus/typescript 0.31.1 → 0.33.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.
- package/README.md +34 -44
- 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 +12 -192
- 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 +173 -101
- package/build/guard/exceptions/derive.d.ts +49 -0
- package/build/guard/exceptions/derive.js +478 -0
- package/build/{probe → guard}/exceptions/jsdoc.d.ts +1 -1
- package/build/{probe → guard}/exceptions/jsdoc.js +1 -1
- 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 +4 -3
- package/build/{probe → guard}/exceptions/value.js +13 -5
- package/build/{probe → guard}/kernel/analyze.d.ts +3 -2
- package/build/guard/kernel/analyze.js +84 -0
- package/build/guard/kernel/ast.d.ts +13 -0
- package/build/guard/kernel/ast.js +56 -0
- 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 +3 -4
- package/build/{probe → guard}/kernel/ids.js +2 -7
- package/build/{probe → guard}/kernel/program.d.ts +1 -1
- package/build/{probe → guard}/kernel/types.d.ts +4 -33
- 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 +38 -121
- package/build/{probe → guard}/resources/channel.d.ts +1 -1
- package/build/{probe → guard}/resources/channel.js +80 -158
- 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 +8 -8
- 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/ast.js +0 -49
- 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}/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.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
|
-
import * as ts from '
|
|
3
|
-
import { bodyOf,
|
|
2
|
+
import * as ts from '../adapter.js';
|
|
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,14 +115,14 @@ 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
|
|
122
|
+
: {
|
|
55
123
|
...base,
|
|
56
|
-
escapeCache: new Map(),
|
|
57
124
|
unhandled: computeUnhandled(ctx),
|
|
58
|
-
}
|
|
59
|
-
: { ...base, escapeCache: new Map() };
|
|
125
|
+
};
|
|
60
126
|
const body = bodyOf(ctx.fn.node);
|
|
61
127
|
const decl = declaredExceptions(ctx.fn.node, ctx.checker);
|
|
62
128
|
if (decl.declared && body) {
|
|
@@ -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);
|
|
408
|
+
return v;
|
|
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
|
+
}
|
|
331
433
|
return v;
|
|
332
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,12 +565,15 @@ function packageRootOf(fileName) {
|
|
|
482
565
|
}
|
|
483
566
|
return root;
|
|
484
567
|
}
|
|
485
|
-
function
|
|
568
|
+
function normalizeSlashes(fileName) {
|
|
569
|
+
return fileName.replace(/\\/g, '/');
|
|
570
|
+
}
|
|
571
|
+
function crossesBoundary(env, ctx, call, homeOf) {
|
|
486
572
|
const res = env.resolveCall(call);
|
|
487
573
|
if (res.targets.length === 0)
|
|
488
574
|
return true;
|
|
489
|
-
const home =
|
|
490
|
-
return res.targets.some((t) =>
|
|
575
|
+
const home = homeOf(ctx.fn.fileName);
|
|
576
|
+
return res.targets.some((t) => homeOf(t.fileName) !== home);
|
|
491
577
|
}
|
|
492
578
|
function reachesTop(env, rem) {
|
|
493
579
|
const u = env.unhandled;
|
|
@@ -499,6 +585,9 @@ function reachesTop(env, rem) {
|
|
|
499
585
|
return false;
|
|
500
586
|
}
|
|
501
587
|
function walkDiagnostics(env, ctx, node, binding, remainder, out) {
|
|
588
|
+
const homeOf = env.reportMode === 'cross-module'
|
|
589
|
+
? normalizeSlashes
|
|
590
|
+
: packageRootOf;
|
|
502
591
|
const visit = (n) => {
|
|
503
592
|
if (isFunctionLike(n))
|
|
504
593
|
return;
|
|
@@ -508,7 +597,7 @@ function walkDiagnostics(env, ctx, node, binding, remainder, out) {
|
|
|
508
597
|
}
|
|
509
598
|
if (ts.isThrowStatement(n)) {
|
|
510
599
|
if (n.expression) {
|
|
511
|
-
if (!consumersOnly(
|
|
600
|
+
if (!consumersOnly(env)) {
|
|
512
601
|
if (isBindingRef(env, n.expression, binding)) {
|
|
513
602
|
if (remainder && !isEmpty(remainder))
|
|
514
603
|
out.push(throwDiagnostic(ctx, n, remainder));
|
|
@@ -525,8 +614,11 @@ function walkDiagnostics(env, ctx, node, binding, remainder, out) {
|
|
|
525
614
|
}
|
|
526
615
|
if (ts.isCallExpression(n) || ts.isNewExpression(n)) {
|
|
527
616
|
const rem = callEscape(env, n);
|
|
528
|
-
const
|
|
529
|
-
|
|
617
|
+
const mode = env.reportMode;
|
|
618
|
+
const report = mode === 'all'
|
|
619
|
+
? true
|
|
620
|
+
: crossesBoundary(env, ctx, n, homeOf) &&
|
|
621
|
+
reachesTop(env, rem);
|
|
530
622
|
if (!isEmpty(rem) && report)
|
|
531
623
|
out.push(callDiagnostic(env, ctx, n, rem));
|
|
532
624
|
ts.forEachChild(n, visit);
|
|
@@ -550,22 +642,8 @@ function handleTry(env, ctx, n, binding, remainder, out) {
|
|
|
550
642
|
if (n.finallyBlock)
|
|
551
643
|
walkDiagnostics(env, ctx, n.finallyBlock, binding, remainder, out);
|
|
552
644
|
}
|
|
553
|
-
function originOf(node) {
|
|
554
|
-
const sf = node.getSourceFile();
|
|
555
|
-
const start = node.getStart(sf);
|
|
556
|
-
const { line, character } = sf.getLineAndCharacterOfPosition(start);
|
|
557
|
-
const raw = node.getText(sf).replace(/\s+/g, ' ').trim();
|
|
558
|
-
return {
|
|
559
|
-
fileName: sf.fileName,
|
|
560
|
-
pos: start,
|
|
561
|
-
end: node.getEnd(),
|
|
562
|
-
line: line + 1,
|
|
563
|
-
column: character + 1,
|
|
564
|
-
text: raw.length > 120 ? `${raw.slice(0, 117)}…` : raw,
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
645
|
function relatedFromOrigins(origins) {
|
|
568
|
-
return origins.
|
|
646
|
+
return origins.map((o) => ({
|
|
569
647
|
message: o.text,
|
|
570
648
|
location: {
|
|
571
649
|
fileName: o.fileName,
|
|
@@ -587,7 +665,7 @@ function callDiagnostic(env, ctx, call, rem) {
|
|
|
587
665
|
location: locationOf(call, call.getSourceFile()),
|
|
588
666
|
related: origins.length > 0
|
|
589
667
|
? relatedFromOrigins(origins)
|
|
590
|
-
: buildRelated(
|
|
668
|
+
: buildRelated(res.targets),
|
|
591
669
|
};
|
|
592
670
|
}
|
|
593
671
|
function throwDiagnostic(ctx, node, rem) {
|
|
@@ -595,7 +673,7 @@ function throwDiagnostic(ctx, node, rem) {
|
|
|
595
673
|
channel: 'exceptions',
|
|
596
674
|
message: `Throw may throw ${render(rem)} with no catch on the path to \`${ctx.fn.name}\``,
|
|
597
675
|
location: locationOf(node, node.getSourceFile()),
|
|
598
|
-
related:
|
|
676
|
+
related: [],
|
|
599
677
|
};
|
|
600
678
|
}
|
|
601
679
|
function calleeDisplay(res, call) {
|
|
@@ -603,16 +681,16 @@ function calleeDisplay(res, call) {
|
|
|
603
681
|
return res.overlay.symbol;
|
|
604
682
|
if (res.targets[0])
|
|
605
683
|
return res.targets[0].name;
|
|
606
|
-
const callee =
|
|
607
|
-
|
|
608
|
-
: undefined;
|
|
609
|
-
if (callee && ts.isPropertyAccessExpression(callee))
|
|
684
|
+
const callee = call.expression;
|
|
685
|
+
if (ts.isPropertyAccessExpression(callee)) {
|
|
610
686
|
return callee.getText();
|
|
611
|
-
|
|
687
|
+
}
|
|
688
|
+
if (ts.isIdentifier(callee)) {
|
|
612
689
|
return callee.text;
|
|
690
|
+
}
|
|
613
691
|
return undefined;
|
|
614
692
|
}
|
|
615
|
-
function buildRelated(
|
|
693
|
+
function buildRelated(targets) {
|
|
616
694
|
const related = [];
|
|
617
695
|
for (const t of targets) {
|
|
618
696
|
related.push({
|
|
@@ -620,19 +698,13 @@ function buildRelated(ctx, targets) {
|
|
|
620
698
|
location: locationOf(t.node, t.sourceFile),
|
|
621
699
|
});
|
|
622
700
|
}
|
|
623
|
-
for (const f of ctx.pathToBoundary(ctx.fn)) {
|
|
624
|
-
related.push({
|
|
625
|
-
message: `on the path to boundary via ${f.name}`,
|
|
626
|
-
location: locationOf(f.node, f.sourceFile),
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
701
|
return related;
|
|
630
702
|
}
|
|
631
703
|
function valueOfType(env, type) {
|
|
632
704
|
let v = bottom();
|
|
633
705
|
if (!type)
|
|
634
706
|
return v;
|
|
635
|
-
for (const t of
|
|
707
|
+
for (const t of constituents(type)) {
|
|
636
708
|
const r = refOfType(env.checker, t);
|
|
637
709
|
if (r.top) {
|
|
638
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 };
|