@esportsplus/typescript 0.31.0 → 0.32.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 +91 -0
- package/bin/tsc-lsp +3 -0
- package/build/cli/diagnostics.d.ts +5 -1
- package/build/cli/diagnostics.js +13 -8
- package/build/cli/tsc.d.ts +3 -1
- package/build/cli/tsc.js +77 -87
- package/build/compiler/coordinator.d.ts +1 -2
- package/build/compiler/coordinator.js +33 -22
- package/build/compiler/imports.d.ts +2 -0
- package/build/compiler/imports.js +9 -2
- package/build/compiler/language-service.d.ts +15 -4
- package/build/compiler/language-service.js +56 -24
- package/build/compiler/plugins/vite.js +7 -5
- package/build/compiler/sourcemap.d.ts +3 -1
- package/build/compiler/sourcemap.js +23 -5
- package/build/jsonc.d.ts +2 -0
- package/build/jsonc.js +85 -0
- package/build/lsp/bin.d.ts +1 -0
- package/build/lsp/bin.js +2 -0
- package/build/lsp/diagnostics.d.ts +10 -0
- package/build/lsp/diagnostics.js +69 -0
- package/build/lsp/index.d.ts +2 -0
- package/build/lsp/index.js +2 -0
- package/build/lsp/server.d.ts +4 -0
- package/build/lsp/server.js +130 -0
- package/build/lsp/workspace.d.ts +14 -0
- package/build/lsp/workspace.js +46 -0
- package/build/probe/adapter.d.ts +14 -0
- package/build/probe/adapter.js +42 -0
- package/build/probe/async/channel.d.ts +4 -0
- package/build/probe/async/channel.js +560 -0
- package/build/probe/async/value.d.ts +9 -0
- package/build/probe/async/value.js +16 -0
- package/build/probe/channels.d.ts +4 -0
- package/build/probe/channels.js +16 -0
- package/build/probe/exceptions/channel.d.ts +5 -0
- package/build/probe/exceptions/channel.js +669 -0
- package/build/probe/exceptions/jsdoc.d.ts +8 -0
- package/build/probe/exceptions/jsdoc.js +34 -0
- package/build/probe/exceptions/value.d.ts +39 -0
- package/build/probe/exceptions/value.js +158 -0
- package/build/probe/kernel/analyze.d.ts +8 -0
- package/build/probe/kernel/analyze.js +68 -0
- package/build/probe/kernel/ast.d.ts +11 -0
- package/build/probe/kernel/ast.js +49 -0
- package/build/probe/kernel/config.d.ts +5 -0
- package/build/probe/kernel/config.js +209 -0
- package/build/probe/kernel/fixpoint.d.ts +6 -0
- package/build/probe/kernel/fixpoint.js +206 -0
- package/build/probe/kernel/format.d.ts +4 -0
- package/build/probe/kernel/format.js +32 -0
- package/build/probe/kernel/graph.d.ts +4 -0
- package/build/probe/kernel/graph.js +507 -0
- package/build/probe/kernel/ids.d.ts +8 -0
- package/build/probe/kernel/ids.js +66 -0
- package/build/probe/kernel/program.d.ts +8 -0
- package/build/probe/kernel/program.js +13 -0
- package/build/probe/kernel/types.d.ts +134 -0
- package/build/probe/kernel/types.js +1 -0
- package/build/probe/overlay/base/async.jsonc +13 -0
- package/build/probe/overlay/base/exceptions.jsonc +54 -0
- package/build/probe/overlay/base/resources.jsonc +57 -0
- package/build/probe/overlay/load.d.ts +18 -0
- package/build/probe/overlay/load.js +302 -0
- package/build/probe/overlay/presets/express.jsonc +25 -0
- package/build/probe/overlay/presets/node.jsonc +17 -0
- package/build/probe/resources/channel.d.ts +4 -0
- package/build/probe/resources/channel.js +798 -0
- package/build/probe/resources/value.d.ts +9 -0
- package/build/probe/resources/value.js +36 -0
- package/build/tsconfig.d.ts +2 -0
- package/build/tsconfig.js +150 -0
- package/package.json +14 -8
- package/tsconfig.base.json +19 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
const WIDEN_AFTER = 3;
|
|
2
|
+
const MAX_ROUNDS = 12;
|
|
3
|
+
function setsEqual(a, b) {
|
|
4
|
+
if (a.size !== b.size) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
for (const x of a) {
|
|
8
|
+
if (!b.has(x)) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
function tarjanSccs(nodes, successors) {
|
|
15
|
+
const index = new Map();
|
|
16
|
+
const low = new Map();
|
|
17
|
+
const onStack = new Set();
|
|
18
|
+
const stack = [];
|
|
19
|
+
const sccs = [];
|
|
20
|
+
let counter = 0;
|
|
21
|
+
const open = (node) => {
|
|
22
|
+
index.set(node.id, counter);
|
|
23
|
+
low.set(node.id, counter);
|
|
24
|
+
counter += 1;
|
|
25
|
+
stack.push(node);
|
|
26
|
+
onStack.add(node.id);
|
|
27
|
+
return { node, succ: successors(node), i: 0 };
|
|
28
|
+
};
|
|
29
|
+
for (const start of nodes) {
|
|
30
|
+
if (index.has(start.id)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const work = [open(start)];
|
|
34
|
+
while (work.length > 0) {
|
|
35
|
+
const frame = work[work.length - 1];
|
|
36
|
+
const node = frame.node;
|
|
37
|
+
if (frame.i < frame.succ.length) {
|
|
38
|
+
const w = frame.succ[frame.i];
|
|
39
|
+
frame.i += 1;
|
|
40
|
+
if (!index.has(w.id)) {
|
|
41
|
+
work.push(open(w));
|
|
42
|
+
}
|
|
43
|
+
else if (onStack.has(w.id)) {
|
|
44
|
+
low.set(node.id, Math.min(low.get(node.id), index.get(w.id)));
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (low.get(node.id) === index.get(node.id)) {
|
|
49
|
+
const component = [];
|
|
50
|
+
for (;;) {
|
|
51
|
+
const w = stack.pop();
|
|
52
|
+
onStack.delete(w.id);
|
|
53
|
+
component.push(w);
|
|
54
|
+
if (w.id === node.id) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
sccs.push(component);
|
|
59
|
+
}
|
|
60
|
+
work.pop();
|
|
61
|
+
const parent = work[work.length - 1];
|
|
62
|
+
if (parent) {
|
|
63
|
+
low.set(parent.node.id, Math.min(low.get(parent.node.id), low.get(node.id)));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return sccs;
|
|
68
|
+
}
|
|
69
|
+
function runChannel(analysis, channel, dispatch, channelConfig, peers) {
|
|
70
|
+
const graph = analysis.graph;
|
|
71
|
+
const reached = graph.reachedFunctions();
|
|
72
|
+
const reachedById = new Map();
|
|
73
|
+
for (const fn of reached) {
|
|
74
|
+
reachedById.set(fn.id, fn);
|
|
75
|
+
}
|
|
76
|
+
const calleesOf = (fn) => graph.calleesOf(fn).filter((c) => reachedById.has(c.id));
|
|
77
|
+
const summaries = new Map();
|
|
78
|
+
const bottomSummary = () => ({
|
|
79
|
+
value: channel.bottom(),
|
|
80
|
+
fromCallbacks: new Set(),
|
|
81
|
+
});
|
|
82
|
+
const summaryOf = (fn) => summaries.get(fn.id) ?? bottomSummary();
|
|
83
|
+
const makeTransferContext = (fn) => ({
|
|
84
|
+
checker: analysis.checker,
|
|
85
|
+
fn,
|
|
86
|
+
dispatch,
|
|
87
|
+
channelConfig,
|
|
88
|
+
sinks: analysis.config.sinks,
|
|
89
|
+
summaryOf,
|
|
90
|
+
resolveCall: (call) => graph.resolveCall(call, channel.name),
|
|
91
|
+
resolveCallFor: (peerChannel, call) => graph.resolveCall(call, peerChannel),
|
|
92
|
+
peerSummaryValue: (peerChannel, fnId) => peers.get(peerChannel)?.get(fnId).value,
|
|
93
|
+
});
|
|
94
|
+
const sccs = tarjanSccs(reached, calleesOf);
|
|
95
|
+
for (const scc of sccs) {
|
|
96
|
+
for (const fn of scc) {
|
|
97
|
+
summaries.set(fn.id, bottomSummary());
|
|
98
|
+
}
|
|
99
|
+
let round = 0;
|
|
100
|
+
for (;;) {
|
|
101
|
+
round += 1;
|
|
102
|
+
let changed = false;
|
|
103
|
+
for (const fn of scc) {
|
|
104
|
+
const prev = summaries.get(fn.id);
|
|
105
|
+
const computed = channel.transfer(makeTransferContext(fn));
|
|
106
|
+
const nextValue = round > WIDEN_AFTER
|
|
107
|
+
? channel.widen(prev.value, computed.value, round)
|
|
108
|
+
: computed.value;
|
|
109
|
+
const next = {
|
|
110
|
+
value: nextValue,
|
|
111
|
+
fromCallbacks: computed.fromCallbacks,
|
|
112
|
+
};
|
|
113
|
+
summaries.set(fn.id, next);
|
|
114
|
+
if (!channel.equals(prev.value, next.value) ||
|
|
115
|
+
!setsEqual(prev.fromCallbacks, next.fromCallbacks)) {
|
|
116
|
+
changed = true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!changed) {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
if (round >= MAX_ROUNDS) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const reverse = new Map();
|
|
128
|
+
for (const fn of reached) {
|
|
129
|
+
for (const callee of calleesOf(fn)) {
|
|
130
|
+
const callers = reverse.get(callee.id);
|
|
131
|
+
if (callers) {
|
|
132
|
+
callers.push(fn);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
reverse.set(callee.id, [fn]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const boundaries = graph.boundaries();
|
|
140
|
+
const pathToBoundary = (fn) => {
|
|
141
|
+
if (boundaries.has(fn.id)) {
|
|
142
|
+
return [fn];
|
|
143
|
+
}
|
|
144
|
+
const parent = new Map();
|
|
145
|
+
const visited = new Set([fn.id]);
|
|
146
|
+
const queue = [fn];
|
|
147
|
+
let head = 0;
|
|
148
|
+
while (head < queue.length) {
|
|
149
|
+
const cur = queue[head];
|
|
150
|
+
head += 1;
|
|
151
|
+
for (const caller of reverse.get(cur.id) ?? []) {
|
|
152
|
+
if (visited.has(caller.id)) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
visited.add(caller.id);
|
|
156
|
+
parent.set(caller.id, cur);
|
|
157
|
+
if (boundaries.has(caller.id)) {
|
|
158
|
+
const rev = [];
|
|
159
|
+
let node = caller;
|
|
160
|
+
while (node) {
|
|
161
|
+
rev.push(node);
|
|
162
|
+
if (node.id === fn.id) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
node = parent.get(node.id);
|
|
166
|
+
}
|
|
167
|
+
return rev.toReversed();
|
|
168
|
+
}
|
|
169
|
+
queue.push(caller);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return [fn];
|
|
173
|
+
};
|
|
174
|
+
const roots = reached.filter((fn) => (reverse.get(fn.id) ?? []).length === 0);
|
|
175
|
+
const diagnostics = [];
|
|
176
|
+
const seen = new Set();
|
|
177
|
+
for (const fn of reached) {
|
|
178
|
+
const ctx = {
|
|
179
|
+
checker: analysis.checker,
|
|
180
|
+
fn,
|
|
181
|
+
dispatch,
|
|
182
|
+
channelConfig,
|
|
183
|
+
sinks: analysis.config.sinks,
|
|
184
|
+
isBoundary: boundaries.has(fn.id),
|
|
185
|
+
summaryOf,
|
|
186
|
+
resolveCall: (call) => graph.resolveCall(call, channel.name),
|
|
187
|
+
resolveCallFor: (peerChannel, call) => graph.resolveCall(call, peerChannel),
|
|
188
|
+
peerSummaryValue: (peerChannel, fnId) => peers.get(peerChannel)?.get(fnId).value,
|
|
189
|
+
pathToBoundary,
|
|
190
|
+
roots: () => roots,
|
|
191
|
+
};
|
|
192
|
+
for (const d of channel.diagnose(ctx)) {
|
|
193
|
+
const key = `${d.channel}\u0000${d.location.fileName}\u0000${d.location.pos}\u0000${d.message}`;
|
|
194
|
+
if (seen.has(key)) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
seen.add(key);
|
|
198
|
+
diagnostics.push(d);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const store = {
|
|
202
|
+
get: (id) => summaries.get(id) ?? bottomSummary(),
|
|
203
|
+
};
|
|
204
|
+
return { store, diagnostics };
|
|
205
|
+
}
|
|
206
|
+
export { runChannel };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Diagnostic } from './types.js';
|
|
2
|
+
declare function formatDiagnostic(diagnostic: Diagnostic, projectRoot: string): string;
|
|
3
|
+
declare function formatDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, projectRoot: string): string;
|
|
4
|
+
export { formatDiagnostic, formatDiagnostics };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as NodePath from 'node:path';
|
|
2
|
+
function rel(projectRoot, fileName) {
|
|
3
|
+
const r = NodePath.relative(projectRoot, fileName);
|
|
4
|
+
return r === '' || r.startsWith('..')
|
|
5
|
+
? fileName
|
|
6
|
+
: r.split(NodePath.sep).join('/');
|
|
7
|
+
}
|
|
8
|
+
function formatDiagnostic(diagnostic, projectRoot) {
|
|
9
|
+
const loc = diagnostic.location;
|
|
10
|
+
const head = `${rel(projectRoot, loc.fileName)}:${loc.line}:${loc.column} — ${diagnostic.message}`;
|
|
11
|
+
if (diagnostic.related.length === 0) {
|
|
12
|
+
return head;
|
|
13
|
+
}
|
|
14
|
+
const chain = diagnostic.related
|
|
15
|
+
.map((r) => {
|
|
16
|
+
const l = r.location;
|
|
17
|
+
return ` ↳ ${rel(projectRoot, l.fileName)}:${l.line}:${l.column} — ${r.message}`;
|
|
18
|
+
})
|
|
19
|
+
.join('\n');
|
|
20
|
+
return `${head}\n${chain}`;
|
|
21
|
+
}
|
|
22
|
+
function formatDiagnostics(diagnostics, projectRoot) {
|
|
23
|
+
if (diagnostics.length === 0) {
|
|
24
|
+
return 'analyze: no findings.';
|
|
25
|
+
}
|
|
26
|
+
const body = diagnostics
|
|
27
|
+
.map((d) => formatDiagnostic(d, projectRoot))
|
|
28
|
+
.join('\n\n');
|
|
29
|
+
const noun = diagnostics.length === 1 ? 'finding' : 'findings';
|
|
30
|
+
return `${body}\n\nanalyze: ${diagnostics.length} ${noun}.`;
|
|
31
|
+
}
|
|
32
|
+
export { formatDiagnostic, formatDiagnostics };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as ts from '../adapter.js';
|
|
2
|
+
import type { CallGraph, OverlaySet, AnalyzeConfig } from './types.js';
|
|
3
|
+
declare function buildCallGraph(program: ts.Program, checker: ts.TypeChecker, config: AnalyzeConfig, overlays: OverlaySet): CallGraph;
|
|
4
|
+
export { buildCallGraph };
|