@esportsplus/typescript 0.29.6 → 0.31.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 +97 -3
- package/bin/tsc-alias +1 -1
- package/bin/tsc-lsp +3 -0
- package/build/cli/diagnostics.d.ts +8 -0
- package/build/cli/diagnostics.js +95 -0
- package/build/cli/tsc.d.ts +12 -2
- package/build/cli/tsc.js +343 -52
- package/build/compiler/ast.d.ts +7 -5
- package/build/compiler/ast.js +6 -6
- package/build/compiler/code.d.ts +5 -4
- package/build/compiler/code.js +12 -1
- package/build/compiler/coordinator.d.ts +16 -7
- package/build/compiler/coordinator.js +75 -41
- package/build/compiler/imports.d.ts +8 -3
- package/build/compiler/imports.js +34 -24
- package/build/compiler/index.d.ts +3 -0
- package/build/compiler/index.js +1 -0
- package/build/compiler/language-service.d.ts +36 -6
- package/build/compiler/language-service.js +252 -58
- package/build/compiler/plugins/index.d.ts +4 -2
- package/build/compiler/plugins/tsc.d.ts +1 -1
- package/build/compiler/plugins/vite.d.ts +6 -3
- package/build/compiler/plugins/vite.js +15 -8
- package/build/compiler/sourcemap.d.ts +52 -0
- package/build/compiler/sourcemap.js +265 -0
- package/build/compiler/types.d.ts +7 -6
- package/build/compiler/uid.d.ts +5 -2
- package/build/compiler/uid.js +33 -4
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- 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 +657 -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/ts.d.ts +3 -0
- package/build/ts.js +3 -0
- package/build/tsconfig.d.ts +2 -0
- package/build/tsconfig.js +150 -0
- package/package.json +29 -9
- package/tsconfig.base.json +19 -0
- package/tsconfig.dev.json +13 -0
- package/tsconfig.package.json +4 -1
- package/.claude/skills/code-audit/registry-typescript.json +0 -326
- package/.editorconfig +0 -9
- package/.gitattributes +0 -2
- package/.github/dependabot.yml +0 -25
- package/.github/workflows/bump.yml +0 -27
- package/.github/workflows/dependabot.yml +0 -58
- package/.github/workflows/publish.yml +0 -42
- package/.github/workflows/templates/bump.yml +0 -9
- package/.github/workflows/templates/dependabot.yml +0 -12
- package/.github/workflows/templates/publish.yml +0 -16
- package/pnpm-workspace.yaml +0 -6
- package/src/cli/tsc.ts +0 -235
- package/src/compiler/ast.ts +0 -60
- package/src/compiler/code.ts +0 -27
- package/src/compiler/coordinator.ts +0 -284
- package/src/compiler/imports.ts +0 -185
- package/src/compiler/index.ts +0 -7
- package/src/compiler/language-service.ts +0 -121
- package/src/compiler/plugins/index.ts +0 -5
- package/src/compiler/plugins/tsc.ts +0 -6
- package/src/compiler/plugins/vite.ts +0 -91
- package/src/compiler/types.ts +0 -83
- package/src/compiler/uid.ts +0 -10
- package/src/constants.ts +0 -4
- package/src/index.ts +0 -1
- package/tests/cli/tsc.test.ts +0 -155
- package/tests/compiler/ast.test.ts +0 -131
- package/tests/compiler/code.test.ts +0 -73
- package/tests/compiler/coordinator.bench.ts +0 -101
- package/tests/compiler/coordinator.test.ts +0 -872
- package/tests/compiler/imports.test.ts +0 -167
- package/tests/compiler/language-service.test.ts +0 -90
- package/tests/compiler/plugins.test.ts +0 -172
- package/tests/compiler/uid.test.ts +0 -70
- package/tsconfig.json +0 -3
- package/vitest.config.ts +0 -14
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
const BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
2
|
+
const CLASS_OTHER = 2;
|
|
3
|
+
const CLASS_SPACE = 1;
|
|
4
|
+
const CLASS_WORD = 0;
|
|
5
|
+
let inverse = buildInverse();
|
|
6
|
+
function buildInverse() {
|
|
7
|
+
let table = new Int8Array(128).fill(-1);
|
|
8
|
+
for (let i = 0, n = BASE64.length; i < n; i++) {
|
|
9
|
+
table[BASE64.charCodeAt(i)] = i;
|
|
10
|
+
}
|
|
11
|
+
return table;
|
|
12
|
+
}
|
|
13
|
+
function charClass(code) {
|
|
14
|
+
if ((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 36 || code === 95) {
|
|
15
|
+
return CLASS_WORD;
|
|
16
|
+
}
|
|
17
|
+
if (code === 9 || code === 10 || code === 13 || code === 32) {
|
|
18
|
+
return CLASS_SPACE;
|
|
19
|
+
}
|
|
20
|
+
return CLASS_OTHER;
|
|
21
|
+
}
|
|
22
|
+
function decodeVlqArray(segment) {
|
|
23
|
+
let out = [], i = 0, n = segment.length;
|
|
24
|
+
while (i < n) {
|
|
25
|
+
let digit = 0, result = 0, shift = 0;
|
|
26
|
+
do {
|
|
27
|
+
digit = inverse[segment.charCodeAt(i)];
|
|
28
|
+
i++;
|
|
29
|
+
result += (digit & 31) << shift;
|
|
30
|
+
shift += 5;
|
|
31
|
+
} while (digit & 32);
|
|
32
|
+
out.push((result & 1) ? -(result >>> 1) : (result >>> 1));
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
function encodeVlq(value) {
|
|
37
|
+
let out = '', vlq = value < 0 ? ((-value) << 1) | 1 : value << 1;
|
|
38
|
+
do {
|
|
39
|
+
let digit = vlq & 31;
|
|
40
|
+
vlq >>>= 5;
|
|
41
|
+
if (vlq > 0) {
|
|
42
|
+
digit |= 32;
|
|
43
|
+
}
|
|
44
|
+
out += BASE64[digit];
|
|
45
|
+
} while (vlq > 0);
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
function lineStarts(text) {
|
|
49
|
+
let starts = [0];
|
|
50
|
+
for (let i = 0, n = text.length; i < n; i++) {
|
|
51
|
+
if (text.charCodeAt(i) === 10) {
|
|
52
|
+
starts.push(i + 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return starts;
|
|
56
|
+
}
|
|
57
|
+
function offsetToLineCol(starts, offset) {
|
|
58
|
+
let hi = starts.length - 1, line = 0, lo = 0;
|
|
59
|
+
while (lo <= hi) {
|
|
60
|
+
let mid = (lo + hi) >> 1;
|
|
61
|
+
if (starts[mid] <= offset) {
|
|
62
|
+
line = mid;
|
|
63
|
+
lo = mid + 1;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
hi = mid - 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { column: offset - starts[line], line };
|
|
70
|
+
}
|
|
71
|
+
function rawToSegments(raw) {
|
|
72
|
+
let name = 0, origColumn = 0, origLine = 0, source = 0;
|
|
73
|
+
return raw.map((line) => {
|
|
74
|
+
let genColumn = 0;
|
|
75
|
+
return line.map((values) => {
|
|
76
|
+
genColumn += values[0];
|
|
77
|
+
let segment = { genColumn };
|
|
78
|
+
if (values.length >= 4) {
|
|
79
|
+
source += values[1];
|
|
80
|
+
origLine += values[2];
|
|
81
|
+
origColumn += values[3];
|
|
82
|
+
segment.originalColumn = origColumn;
|
|
83
|
+
segment.originalLine = origLine;
|
|
84
|
+
segment.source = source;
|
|
85
|
+
if (values.length >= 5) {
|
|
86
|
+
name += values[4];
|
|
87
|
+
segment.name = name;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return segment;
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function resolveGeneration(anchors, offset) {
|
|
95
|
+
let found = anchors[0], hi = anchors.length - 1, lo = 0;
|
|
96
|
+
while (lo <= hi) {
|
|
97
|
+
let mid = (lo + hi) >> 1, anchor = anchors[mid];
|
|
98
|
+
if (offset < anchor.afterStart) {
|
|
99
|
+
hi = mid - 1;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
found = anchor;
|
|
103
|
+
lo = mid + 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (found.identity) {
|
|
107
|
+
return found.beforeStart + (offset - found.afterStart);
|
|
108
|
+
}
|
|
109
|
+
return found.beforeStart;
|
|
110
|
+
}
|
|
111
|
+
function resolveOffset(mapping, offset) {
|
|
112
|
+
let generations = mapping.generations, result = offset;
|
|
113
|
+
for (let i = generations.length - 1; i >= 0; i--) {
|
|
114
|
+
result = resolveGeneration(generations[i], result);
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
function resolveOffsets(mapping) {
|
|
119
|
+
const cursors = mapping.generations.map(() => 0);
|
|
120
|
+
return (offset) => {
|
|
121
|
+
let result = offset;
|
|
122
|
+
for (let i = mapping.generations.length - 1; i >= 0; i--) {
|
|
123
|
+
const anchors = mapping.generations[i];
|
|
124
|
+
while (cursors[i] + 1 < anchors.length &&
|
|
125
|
+
result >= anchors[cursors[i] + 1].afterStart) {
|
|
126
|
+
cursors[i] += 1;
|
|
127
|
+
}
|
|
128
|
+
const anchor = anchors[cursors[i]];
|
|
129
|
+
result = anchor.identity
|
|
130
|
+
? anchor.beforeStart + (result - anchor.afterStart)
|
|
131
|
+
: anchor.beforeStart;
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function segmentAt(starts, offset, genColumn) {
|
|
137
|
+
let position = offsetToLineCol(starts, offset);
|
|
138
|
+
return { genColumn, originalColumn: position.column, originalLine: position.line, source: 0 };
|
|
139
|
+
}
|
|
140
|
+
function segmentsToRaw(segments) {
|
|
141
|
+
let name = 0, origColumn = 0, origLine = 0, source = 0;
|
|
142
|
+
return segments.map((line) => {
|
|
143
|
+
let genColumn = 0;
|
|
144
|
+
return line.map((segment) => {
|
|
145
|
+
let values = [segment.genColumn - genColumn];
|
|
146
|
+
genColumn = segment.genColumn;
|
|
147
|
+
if (segment.source !== undefined && segment.originalLine !== undefined && segment.originalColumn !== undefined) {
|
|
148
|
+
values.push(segment.source - source, segment.originalLine - origLine, segment.originalColumn - origColumn);
|
|
149
|
+
origColumn = segment.originalColumn;
|
|
150
|
+
origLine = segment.originalLine;
|
|
151
|
+
source = segment.source;
|
|
152
|
+
if (segment.name !== undefined) {
|
|
153
|
+
values.push(segment.name - name);
|
|
154
|
+
name = segment.name;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return values;
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
const buildGeneration = (beforeText, edits) => {
|
|
162
|
+
let afterCursor = 0, anchors = [], beforeCursor = 0, ordered = [...edits].sort((a, b) => a.start - b.start);
|
|
163
|
+
for (let i = 0, n = ordered.length; i < n; i++) {
|
|
164
|
+
let edit = ordered[i];
|
|
165
|
+
if (edit.start > beforeCursor) {
|
|
166
|
+
let length = edit.start - beforeCursor;
|
|
167
|
+
anchors.push({ afterEnd: afterCursor + length, afterStart: afterCursor, beforeStart: beforeCursor, identity: true });
|
|
168
|
+
afterCursor += length;
|
|
169
|
+
}
|
|
170
|
+
let inserted = edit.newText.length;
|
|
171
|
+
if (inserted > 0) {
|
|
172
|
+
anchors.push({ afterEnd: afterCursor + inserted, afterStart: afterCursor, beforeStart: edit.start, identity: false });
|
|
173
|
+
afterCursor += inserted;
|
|
174
|
+
}
|
|
175
|
+
beforeCursor = edit.end;
|
|
176
|
+
}
|
|
177
|
+
if (beforeCursor < beforeText.length) {
|
|
178
|
+
anchors.push({ afterEnd: afterCursor + (beforeText.length - beforeCursor), afterStart: afterCursor, beforeStart: beforeCursor, identity: true });
|
|
179
|
+
}
|
|
180
|
+
if (anchors.length === 0) {
|
|
181
|
+
anchors.push({ afterEnd: 0, afterStart: 0, beforeStart: 0, identity: true });
|
|
182
|
+
}
|
|
183
|
+
return anchors;
|
|
184
|
+
};
|
|
185
|
+
const composeEmittedMap = (map, mapping, transformedText, originalText) => {
|
|
186
|
+
let oStarts = lineStarts(originalText), segments = rawToSegments(decode(map.mappings)), tStarts = lineStarts(transformedText);
|
|
187
|
+
for (let i = 0, n = segments.length; i < n; i++) {
|
|
188
|
+
let line = segments[i];
|
|
189
|
+
for (let j = 0, m = line.length; j < m; j++) {
|
|
190
|
+
let segment = line[j];
|
|
191
|
+
if (segment.originalLine === undefined || segment.originalColumn === undefined) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
let base = segment.originalLine < tStarts.length ? tStarts[segment.originalLine] : transformedText.length, position = offsetToLineCol(oStarts, resolveOffset(mapping, base + segment.originalColumn));
|
|
195
|
+
segment.originalColumn = position.column;
|
|
196
|
+
segment.originalLine = position.line;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
let composed = {
|
|
200
|
+
mappings: encode(segmentsToRaw(segments)),
|
|
201
|
+
names: map.names ?? [],
|
|
202
|
+
sources: map.sources,
|
|
203
|
+
version: 3
|
|
204
|
+
};
|
|
205
|
+
if (map.file !== undefined) {
|
|
206
|
+
composed.file = map.file;
|
|
207
|
+
}
|
|
208
|
+
if (map.sourceRoot !== undefined) {
|
|
209
|
+
composed.sourceRoot = map.sourceRoot;
|
|
210
|
+
}
|
|
211
|
+
return composed;
|
|
212
|
+
};
|
|
213
|
+
const decode = (mappings) => {
|
|
214
|
+
if (mappings === '') {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
217
|
+
return mappings.split(';').map((line) => {
|
|
218
|
+
if (line === '') {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
return line.split(',').map((segment) => decodeVlqArray(segment));
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
const encode = (decoded) => {
|
|
225
|
+
let lines = [];
|
|
226
|
+
for (let i = 0, n = decoded.length; i < n; i++) {
|
|
227
|
+
let parts = [], segments = decoded[i];
|
|
228
|
+
for (let j = 0, m = segments.length; j < m; j++) {
|
|
229
|
+
let encoded = '', values = segments[j];
|
|
230
|
+
for (let k = 0, o = values.length; k < o; k++) {
|
|
231
|
+
encoded += encodeVlq(values[k]);
|
|
232
|
+
}
|
|
233
|
+
parts.push(encoded);
|
|
234
|
+
}
|
|
235
|
+
lines.push(parts.join(','));
|
|
236
|
+
}
|
|
237
|
+
return lines.join(';');
|
|
238
|
+
};
|
|
239
|
+
const originalPositionFor = (mapping, transformedText, originalText, line, column) => {
|
|
240
|
+
let tStarts = lineStarts(transformedText), base = line < tStarts.length ? tStarts[line] : transformedText.length;
|
|
241
|
+
return offsetToLineCol(lineStarts(originalText), resolveOffset(mapping, base + column));
|
|
242
|
+
};
|
|
243
|
+
const toSourceMapV3 = (mapping, transformedText, originalText, source) => {
|
|
244
|
+
let oStarts = lineStarts(originalText), resolve = resolveOffsets(mapping), segments = [], tStarts = lineStarts(transformedText);
|
|
245
|
+
for (let line = 0, n = tStarts.length; line < n; line++) {
|
|
246
|
+
let end = line + 1 < n ? tStarts[line + 1] - 1 : transformedText.length, previous = resolve(tStarts[line]), start = tStarts[line];
|
|
247
|
+
let row = [segmentAt(oStarts, previous, 0)];
|
|
248
|
+
for (let offset = start + 1; offset < end; offset++) {
|
|
249
|
+
let current = charClass(transformedText.charCodeAt(offset));
|
|
250
|
+
if (current !== CLASS_OTHER && current === charClass(transformedText.charCodeAt(offset - 1))) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
let resolved = resolve(offset);
|
|
254
|
+
if (resolved === previous) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
previous = resolved;
|
|
258
|
+
row.push(segmentAt(oStarts, resolved, offset - start));
|
|
259
|
+
}
|
|
260
|
+
segments.push(row);
|
|
261
|
+
}
|
|
262
|
+
return { mappings: encode(segmentsToRaw(segments)), names: [], sources: [source], version: 3 };
|
|
263
|
+
};
|
|
264
|
+
export default { buildGeneration, composeEmittedMap, decode, encode, originalPositionFor, resolveOffset, toSourceMapV3 };
|
|
265
|
+
export { buildGeneration, composeEmittedMap, decode, encode, originalPositionFor, resolveOffset, toSourceMapV3 };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { Node, SourceFile } from 'typescript/unstable/ast';
|
|
2
|
+
import type { Checker, Program } from 'typescript/unstable/sync';
|
|
2
3
|
type ImportIntent = {
|
|
3
4
|
add?: string[];
|
|
4
5
|
namespace?: string;
|
|
@@ -18,16 +19,16 @@ type Replacement = Range & {
|
|
|
18
19
|
newText: string;
|
|
19
20
|
};
|
|
20
21
|
type ReplacementIntent = {
|
|
21
|
-
generate: (sourceFile:
|
|
22
|
-
node:
|
|
22
|
+
generate: (sourceFile: SourceFile) => string;
|
|
23
|
+
node: Node;
|
|
23
24
|
};
|
|
24
25
|
type SharedContext = Map<string, unknown>;
|
|
25
26
|
type TransformContext = {
|
|
26
|
-
checker:
|
|
27
|
+
checker: Checker;
|
|
27
28
|
code: string;
|
|
28
|
-
program:
|
|
29
|
+
program: Program;
|
|
29
30
|
shared: SharedContext;
|
|
30
|
-
sourceFile:
|
|
31
|
+
sourceFile: SourceFile;
|
|
31
32
|
};
|
|
32
33
|
type TransformResult = {
|
|
33
34
|
imports?: ImportIntent[];
|
package/build/compiler/uid.d.ts
CHANGED
package/build/compiler/uid.js
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import path from 'path';
|
|
2
|
+
const BACKSLASH_REGEX = /\\/g;
|
|
3
|
+
const FNV_OFFSET_BASIS = 2166136261;
|
|
4
|
+
const FNV_PRIME = 16777619;
|
|
5
|
+
const NAMESPACE_WIDTH = 7;
|
|
6
|
+
const UNSCOPED_NAMESPACE = 'u';
|
|
7
|
+
let counter = 0, namespace = UNSCOPED_NAMESPACE;
|
|
8
|
+
function derive(id, code) {
|
|
9
|
+
let candidate = format(id), salt = 0;
|
|
10
|
+
while (code.includes(candidate)) {
|
|
11
|
+
salt++;
|
|
12
|
+
candidate = format(id + '#' + salt);
|
|
13
|
+
}
|
|
14
|
+
return candidate;
|
|
15
|
+
}
|
|
16
|
+
function format(id) {
|
|
17
|
+
return hash(id).toString(36).padStart(NAMESPACE_WIDTH, '0');
|
|
18
|
+
}
|
|
19
|
+
function hash(value) {
|
|
20
|
+
let h = FNV_OFFSET_BASIS;
|
|
21
|
+
for (let i = 0, n = value.length; i < n; i++) {
|
|
22
|
+
h ^= value.charCodeAt(i);
|
|
23
|
+
h = Math.imul(h, FNV_PRIME);
|
|
24
|
+
}
|
|
25
|
+
return h >>> 0;
|
|
26
|
+
}
|
|
27
|
+
const uid = (name) => {
|
|
28
|
+
return name + '_' + namespace + (counter++).toString(36);
|
|
5
29
|
};
|
|
30
|
+
uid.scope = (root, fileName, code) => {
|
|
31
|
+
counter = 0;
|
|
32
|
+
namespace = derive(path.relative(root, fileName).replace(BACKSLASH_REGEX, '/') || fileName, code);
|
|
33
|
+
};
|
|
34
|
+
export default uid;
|
package/build/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * as ts from './ts.js';
|
package/build/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * as ts from './ts.js';
|
package/build/jsonc.d.ts
ADDED
package/build/jsonc.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const stripJsonc = (text) => {
|
|
2
|
+
let escaped = false, inBlockComment = false, inLineComment = false, inString = false, stripped = '';
|
|
3
|
+
for (let i = 0, n = text.length; i < n; i++) {
|
|
4
|
+
let char = text[i], next = text[i + 1];
|
|
5
|
+
if (inLineComment) {
|
|
6
|
+
if (char === '\n') {
|
|
7
|
+
inLineComment = false;
|
|
8
|
+
stripped += char;
|
|
9
|
+
}
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
if (inBlockComment) {
|
|
13
|
+
if (char === '*' && next === '/') {
|
|
14
|
+
inBlockComment = false;
|
|
15
|
+
i++;
|
|
16
|
+
}
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (inString) {
|
|
20
|
+
stripped += char;
|
|
21
|
+
if (escaped) {
|
|
22
|
+
escaped = false;
|
|
23
|
+
}
|
|
24
|
+
else if (char === '\\') {
|
|
25
|
+
escaped = true;
|
|
26
|
+
}
|
|
27
|
+
else if (char === '"') {
|
|
28
|
+
inString = false;
|
|
29
|
+
}
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (char === '"') {
|
|
33
|
+
inString = true;
|
|
34
|
+
stripped += char;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (char === '/' && next === '/') {
|
|
38
|
+
inLineComment = true;
|
|
39
|
+
i++;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (char === '/' && next === '*') {
|
|
43
|
+
inBlockComment = true;
|
|
44
|
+
i++;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
stripped += char;
|
|
48
|
+
}
|
|
49
|
+
escaped = false;
|
|
50
|
+
inString = false;
|
|
51
|
+
let result = '';
|
|
52
|
+
for (let i = 0, n = stripped.length; i < n; i++) {
|
|
53
|
+
let char = stripped[i];
|
|
54
|
+
if (inString) {
|
|
55
|
+
result += char;
|
|
56
|
+
if (escaped) {
|
|
57
|
+
escaped = false;
|
|
58
|
+
}
|
|
59
|
+
else if (char === '\\') {
|
|
60
|
+
escaped = true;
|
|
61
|
+
}
|
|
62
|
+
else if (char === '"') {
|
|
63
|
+
inString = false;
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (char === '"') {
|
|
68
|
+
inString = true;
|
|
69
|
+
result += char;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (char === ',') {
|
|
73
|
+
let j = i + 1;
|
|
74
|
+
while (j < n && /\s/.test(stripped[j])) {
|
|
75
|
+
j++;
|
|
76
|
+
}
|
|
77
|
+
if (stripped[j] === ']' || stripped[j] === '}') {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
result += char;
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
};
|
|
85
|
+
export { stripJsonc };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/build/lsp/bin.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DiagnosticSeverity } from 'vscode-languageserver/node';
|
|
2
|
+
import type { CodeAction, Diagnostic as LspDiagnostic, Hover } from 'vscode-languageserver/node';
|
|
3
|
+
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
|
4
|
+
import type { Diagnostic as AnalyzeDiagnostic } from '../probe/kernel/types.js';
|
|
5
|
+
export type DocumentResolver = (fileName: string) => TextDocument | undefined;
|
|
6
|
+
declare function toLspDiagnostic(diagnostic: AnalyzeDiagnostic, severity: DiagnosticSeverity, resolve: DocumentResolver, uriOf: (fileName: string) => string): LspDiagnostic;
|
|
7
|
+
declare function groupByFile(diagnostics: ReadonlyArray<AnalyzeDiagnostic>, severity: DiagnosticSeverity, resolve: DocumentResolver, uriOf: (fileName: string) => string): Map<string, LspDiagnostic[]>;
|
|
8
|
+
declare function hoverAt(diagnostics: ReadonlyArray<AnalyzeDiagnostic>, offset: number, document: TextDocument): Hover | undefined;
|
|
9
|
+
declare function codeActionsAt(diagnostics: ReadonlyArray<AnalyzeDiagnostic>, startOffset: number, endOffset: number, document: TextDocument, uriOf: (fileName: string) => string): CodeAction[];
|
|
10
|
+
export { codeActionsAt, DiagnosticSeverity, groupByFile, hoverAt, toLspDiagnostic };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { CodeActionKind, DiagnosticSeverity, MarkupKind } from 'vscode-languageserver/node';
|
|
2
|
+
function rangeOf(location, document) {
|
|
3
|
+
if (document) {
|
|
4
|
+
return { start: document.positionAt(location.pos), end: document.positionAt(location.end) };
|
|
5
|
+
}
|
|
6
|
+
let start = { line: Math.max(0, location.line - 1), character: Math.max(0, location.column - 1) };
|
|
7
|
+
return { start, end: { line: start.line, character: start.character + 1 } };
|
|
8
|
+
}
|
|
9
|
+
function relatedOf(diagnostic, resolve, uriOf) {
|
|
10
|
+
return diagnostic.related.map((related) => ({
|
|
11
|
+
location: { range: rangeOf(related.location, resolve(related.location.fileName)), uri: uriOf(related.location.fileName) },
|
|
12
|
+
message: related.message,
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
function toLspDiagnostic(diagnostic, severity, resolve, uriOf) {
|
|
16
|
+
return {
|
|
17
|
+
code: diagnostic.channel,
|
|
18
|
+
message: diagnostic.message,
|
|
19
|
+
range: rangeOf(diagnostic.location, resolve(diagnostic.location.fileName)),
|
|
20
|
+
relatedInformation: relatedOf(diagnostic, resolve, uriOf),
|
|
21
|
+
severity,
|
|
22
|
+
source: 'analyze',
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function groupByFile(diagnostics, severity, resolve, uriOf) {
|
|
26
|
+
let grouped = new Map();
|
|
27
|
+
for (let i = 0, n = diagnostics.length; i < n; i++) {
|
|
28
|
+
let diagnostic = diagnostics[i], fileName = diagnostic.location.fileName, list = grouped.get(fileName);
|
|
29
|
+
if (!list) {
|
|
30
|
+
list = [];
|
|
31
|
+
grouped.set(fileName, list);
|
|
32
|
+
}
|
|
33
|
+
list.push(toLspDiagnostic(diagnostic, severity, resolve, uriOf));
|
|
34
|
+
}
|
|
35
|
+
return grouped;
|
|
36
|
+
}
|
|
37
|
+
function hoverAt(diagnostics, offset, document) {
|
|
38
|
+
let hits = diagnostics.filter((diagnostic) => offset >= diagnostic.location.pos && offset <= diagnostic.location.end);
|
|
39
|
+
if (hits.length === 0) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
let lines = [];
|
|
43
|
+
for (let i = 0, n = hits.length; i < n; i++) {
|
|
44
|
+
let diagnostic = hits[i];
|
|
45
|
+
lines.push(`**${diagnostic.channel}** — ${diagnostic.message}`);
|
|
46
|
+
for (let related of diagnostic.related) {
|
|
47
|
+
lines.push(`- ${related.message}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { contents: { kind: MarkupKind.Markdown, value: lines.join('\n\n') }, range: rangeOf(hits[0].location, document) };
|
|
51
|
+
}
|
|
52
|
+
function codeActionsAt(diagnostics, startOffset, endOffset, document, uriOf) {
|
|
53
|
+
let actions = [];
|
|
54
|
+
for (let diagnostic of diagnostics) {
|
|
55
|
+
if (diagnostic.location.end < startOffset || diagnostic.location.pos > endOffset) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
for (let fix of diagnostic.fixes ?? []) {
|
|
59
|
+
let changes = {};
|
|
60
|
+
for (let edit of fix.edits) {
|
|
61
|
+
let uri = uriOf(edit.fileName), range = { start: document.positionAt(edit.pos), end: document.positionAt(edit.end) };
|
|
62
|
+
(changes[uri] ??= []).push({ newText: edit.newText, range });
|
|
63
|
+
}
|
|
64
|
+
actions.push({ edit: { changes }, kind: CodeActionKind.QuickFix, title: fix.title });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return actions;
|
|
68
|
+
}
|
|
69
|
+
export { codeActionsAt, DiagnosticSeverity, groupByFile, hoverAt, toLspDiagnostic };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import * as NodeFS from 'node:fs';
|
|
2
|
+
import * as NodePath from 'node:path';
|
|
3
|
+
import { CodeActionKind, createConnection, ProposedFeatures, StreamMessageReader, StreamMessageWriter, TextDocuments, TextDocumentSyncKind } from 'vscode-languageserver/node';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
+
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
6
|
+
import { codeActionsAt, DiagnosticSeverity, groupByFile, hoverAt } from './diagnostics.js';
|
|
7
|
+
import { AnalyzeWorkspace } from './workspace.js';
|
|
8
|
+
function pathKey(fileName) {
|
|
9
|
+
let resolved = NodePath.resolve(fileName);
|
|
10
|
+
return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
|
|
11
|
+
}
|
|
12
|
+
function findTsconfig(rootDir) {
|
|
13
|
+
let candidate = NodePath.join(rootDir, 'tsconfig.json');
|
|
14
|
+
return NodeFS.existsSync(candidate) ? candidate : undefined;
|
|
15
|
+
}
|
|
16
|
+
function rootFromInitialize(params) {
|
|
17
|
+
let folder = params.workspaceFolders?.[0]?.uri ?? params.rootUri ?? undefined;
|
|
18
|
+
return folder ? fileURLToPath(folder) : undefined;
|
|
19
|
+
}
|
|
20
|
+
function createServer(connection) {
|
|
21
|
+
let analyzed = new Map(), documents = new TextDocuments(TextDocument), pending = new Set(), published = new Set(), timer, workspace;
|
|
22
|
+
function runAnalysis() {
|
|
23
|
+
timer = undefined;
|
|
24
|
+
if (!workspace || !workspace.config) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let changed = [...pending];
|
|
28
|
+
pending.clear();
|
|
29
|
+
try {
|
|
30
|
+
workspace.refresh(changed);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
connection.console.error(`analyze: snapshot refresh failed — ${error.message}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
let result = workspace.analyze();
|
|
37
|
+
if (!result) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
analyzed = new Map();
|
|
41
|
+
for (let diagnostic of result.diagnostics) {
|
|
42
|
+
let key = pathKey(diagnostic.location.fileName), list = analyzed.get(key);
|
|
43
|
+
if (!list) {
|
|
44
|
+
list = [];
|
|
45
|
+
analyzed.set(key, list);
|
|
46
|
+
}
|
|
47
|
+
list.push(diagnostic);
|
|
48
|
+
}
|
|
49
|
+
let openByPath = new Map(documents.all().map((document) => [pathKey(fileURLToPath(document.uri)), document])), resolve = (fileName) => openByPath.get(pathKey(fileName)), severity = workspace.config.severity === 'warning' ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error, uriOf = (fileName) => openByPath.get(pathKey(fileName))?.uri ?? pathToFileURL(fileName).toString(), grouped = groupByFile(result.diagnostics, severity, resolve, uriOf), next = new Set();
|
|
50
|
+
for (let [fileName, diagnostics] of grouped) {
|
|
51
|
+
let uri = uriOf(fileName);
|
|
52
|
+
next.add(uri);
|
|
53
|
+
connection.sendDiagnostics({ diagnostics, uri });
|
|
54
|
+
}
|
|
55
|
+
for (let uri of published) {
|
|
56
|
+
if (!next.has(uri)) {
|
|
57
|
+
connection.sendDiagnostics({ diagnostics: [], uri });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
published = next;
|
|
61
|
+
}
|
|
62
|
+
function schedule(changed) {
|
|
63
|
+
for (let i = 0, n = changed.length; i < n; i++) {
|
|
64
|
+
pending.add(changed[i]);
|
|
65
|
+
}
|
|
66
|
+
if (timer !== undefined) {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
}
|
|
69
|
+
timer = setTimeout(runAnalysis, 300);
|
|
70
|
+
}
|
|
71
|
+
connection.onInitialize((params) => {
|
|
72
|
+
let root = rootFromInitialize(params);
|
|
73
|
+
if (root) {
|
|
74
|
+
let tsconfig = findTsconfig(root);
|
|
75
|
+
if (tsconfig) {
|
|
76
|
+
workspace = new AnalyzeWorkspace(tsconfig);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
capabilities: {
|
|
81
|
+
codeActionProvider: { codeActionKinds: [CodeActionKind.QuickFix] },
|
|
82
|
+
hoverProvider: true,
|
|
83
|
+
textDocumentSync: TextDocumentSyncKind.Incremental,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
connection.onInitialized(() => {
|
|
88
|
+
if (workspace) {
|
|
89
|
+
schedule([]);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
connection.onShutdown(() => {
|
|
93
|
+
workspace?.dispose();
|
|
94
|
+
workspace = undefined;
|
|
95
|
+
});
|
|
96
|
+
connection.onHover((params) => {
|
|
97
|
+
let document = documents.get(params.textDocument.uri);
|
|
98
|
+
if (!document) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
let diagnostics = analyzed.get(pathKey(fileURLToPath(params.textDocument.uri)));
|
|
102
|
+
return diagnostics ? hoverAt(diagnostics, document.offsetAt(params.position), document) ?? null : null;
|
|
103
|
+
});
|
|
104
|
+
connection.onCodeAction((params) => {
|
|
105
|
+
let document = documents.get(params.textDocument.uri);
|
|
106
|
+
if (!document) {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
let target = pathKey(fileURLToPath(params.textDocument.uri)), diagnostics = analyzed.get(target);
|
|
110
|
+
if (!diagnostics) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
let uriOf = (fileName) => (pathKey(fileName) === target ? params.textDocument.uri : pathToFileURL(fileName).toString());
|
|
114
|
+
return codeActionsAt(diagnostics, document.offsetAt(params.range.start), document.offsetAt(params.range.end), document, uriOf);
|
|
115
|
+
});
|
|
116
|
+
documents.onDidOpen((event) => schedule([fileURLToPath(event.document.uri)]));
|
|
117
|
+
documents.onDidSave((event) => {
|
|
118
|
+
let fileName = fileURLToPath(event.document.uri);
|
|
119
|
+
if (workspace && NodePath.basename(fileName) === 'tsconfig.json') {
|
|
120
|
+
workspace.reloadConfig();
|
|
121
|
+
}
|
|
122
|
+
schedule([fileName]);
|
|
123
|
+
});
|
|
124
|
+
documents.listen(connection);
|
|
125
|
+
connection.listen();
|
|
126
|
+
}
|
|
127
|
+
function startServer() {
|
|
128
|
+
createServer(createConnection(ProposedFeatures.all, new StreamMessageReader(process.stdin), new StreamMessageWriter(process.stdout)));
|
|
129
|
+
}
|
|
130
|
+
export { createServer, startServer };
|