@esportsplus/typescript 0.28.5 → 0.29.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/.claude/skills/code-audit/registry-typescript.json +326 -0
- package/.github/workflows/publish.yml +1 -1
- package/build/cli/tsc.d.ts +10 -1
- package/build/cli/tsc.js +8 -5
- package/build/compiler/ast.d.ts +2 -5
- package/build/compiler/ast.js +1 -1
- package/build/compiler/coordinator.d.ts +1 -2
- package/build/compiler/coordinator.js +48 -30
- package/build/compiler/imports.js +7 -3
- package/build/compiler/language-service.d.ts +9 -0
- package/build/compiler/language-service.js +73 -0
- package/build/compiler/plugins/vite.js +11 -11
- package/package.json +10 -7
- package/src/cli/tsc.ts +12 -6
- package/src/compiler/ast.ts +2 -7
- package/src/compiler/coordinator.ts +63 -45
- package/src/compiler/imports.ts +11 -3
- package/src/compiler/language-service.ts +121 -0
- package/src/compiler/plugins/vite.ts +17 -15
- package/tests/cli/tsc.test.ts +155 -0
- package/tests/compiler/ast.test.ts +131 -0
- package/tests/compiler/code.test.ts +73 -0
- package/tests/compiler/coordinator.bench.ts +101 -0
- package/tests/compiler/coordinator.test.ts +855 -0
- package/tests/compiler/imports.test.ts +167 -0
- package/tests/compiler/language-service.test.ts +90 -0
- package/tests/compiler/plugins.test.ts +172 -0
- package/tests/compiler/uid.test.ts +70 -0
- package/tsconfig.base.json +0 -1
- package/vitest.config.ts +14 -0
- package/build/compiler/program.d.ts +0 -6
- package/build/compiler/program.js +0 -34
- package/src/compiler/program.ts +0 -55
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": "@esportsplus/typescript",
|
|
3
|
+
"version": "0.29.0",
|
|
4
|
+
"target": "src/ tests/",
|
|
5
|
+
"runs": [
|
|
6
|
+
{
|
|
7
|
+
"date": "2026-04-11",
|
|
8
|
+
"commit": "e0657fe",
|
|
9
|
+
"mode": "full",
|
|
10
|
+
"files_audited": 13,
|
|
11
|
+
"files_skipped": 0,
|
|
12
|
+
"findings_new": 2,
|
|
13
|
+
"findings_recurring": 0,
|
|
14
|
+
"sqale_rating": "A",
|
|
15
|
+
"agent_results": {
|
|
16
|
+
"correctness": { "status": "ok", "symbols": 26, "sub_targets": 1, "findings": 1 },
|
|
17
|
+
"security": { "status": "ok", "symbols": 14, "sub_targets": 1, "findings": 0 },
|
|
18
|
+
"performance": { "status": "ok", "symbols": 15, "sub_targets": 1, "findings": 1 },
|
|
19
|
+
"architecture": { "status": "ok", "symbols": 32, "sub_targets": 1, "findings": 0 },
|
|
20
|
+
"testing": { "status": "ok", "symbols": 16, "sub_targets": 1, "findings": 1 }
|
|
21
|
+
},
|
|
22
|
+
"agent_overlap": {},
|
|
23
|
+
"estimated_remaining": null
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"date": "2026-04-11",
|
|
27
|
+
"commit": "e0657fe",
|
|
28
|
+
"mode": "incremental",
|
|
29
|
+
"files_audited": 13,
|
|
30
|
+
"files_skipped": 0,
|
|
31
|
+
"findings_new": 0,
|
|
32
|
+
"findings_recurring": 1,
|
|
33
|
+
"sqale_rating": "A",
|
|
34
|
+
"agent_results": {
|
|
35
|
+
"correctness": { "status": "ok", "symbols": 26, "sub_targets": 1, "findings": 0 },
|
|
36
|
+
"security": { "status": "ok", "symbols": 14, "sub_targets": 1, "findings": 0 },
|
|
37
|
+
"performance": { "status": "ok", "symbols": 15, "sub_targets": 1, "findings": 0 },
|
|
38
|
+
"architecture": { "status": "ok", "symbols": 32, "sub_targets": 1, "findings": 0 },
|
|
39
|
+
"testing": { "status": "ok", "symbols": 16, "sub_targets": 1, "findings": 1 }
|
|
40
|
+
},
|
|
41
|
+
"agent_overlap": {},
|
|
42
|
+
"estimated_remaining": null
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"date": "2026-04-11",
|
|
46
|
+
"commit": "e0657fe",
|
|
47
|
+
"mode": "incremental",
|
|
48
|
+
"files_audited": 13,
|
|
49
|
+
"files_skipped": 0,
|
|
50
|
+
"findings_new": 0,
|
|
51
|
+
"findings_recurring": 0,
|
|
52
|
+
"sqale_rating": "A",
|
|
53
|
+
"agent_results": {
|
|
54
|
+
"correctness": { "status": "ok", "symbols": 26, "sub_targets": 1, "findings": 0 },
|
|
55
|
+
"security": { "status": "ok", "symbols": 14, "sub_targets": 1, "findings": 0 },
|
|
56
|
+
"performance": { "status": "ok", "symbols": 15, "sub_targets": 1, "findings": 0 },
|
|
57
|
+
"architecture": { "status": "ok", "symbols": 32, "sub_targets": 1, "findings": 0 },
|
|
58
|
+
"testing": { "status": "ok", "symbols": 16, "sub_targets": 1, "findings": 0 }
|
|
59
|
+
},
|
|
60
|
+
"agent_overlap": {},
|
|
61
|
+
"estimated_remaining": null
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"date": "2026-04-11",
|
|
65
|
+
"commit": "59ea7a3",
|
|
66
|
+
"mode": "incremental",
|
|
67
|
+
"files_audited": 19,
|
|
68
|
+
"files_skipped": 0,
|
|
69
|
+
"findings_new": 9,
|
|
70
|
+
"findings_recurring": 1,
|
|
71
|
+
"sqale_rating": "B",
|
|
72
|
+
"agent_results": {
|
|
73
|
+
"correctness": { "status": "ok", "symbols": 26, "sub_targets": 1, "findings": 0 },
|
|
74
|
+
"security": { "status": "ok", "symbols": 14, "sub_targets": 1, "findings": 0 },
|
|
75
|
+
"performance": { "status": "ok", "symbols": 15, "sub_targets": 1, "findings": 0 },
|
|
76
|
+
"architecture": { "status": "ok", "symbols": 32, "sub_targets": 1, "findings": 2 },
|
|
77
|
+
"testing": { "status": "ok", "symbols": 35, "sub_targets": 1, "findings": 7 }
|
|
78
|
+
},
|
|
79
|
+
"agent_overlap": {},
|
|
80
|
+
"estimated_remaining": null
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"date": "2026-04-11",
|
|
84
|
+
"commit": "59ea7a3",
|
|
85
|
+
"mode": "incremental",
|
|
86
|
+
"files_audited": 21,
|
|
87
|
+
"files_skipped": 0,
|
|
88
|
+
"findings_new": 0,
|
|
89
|
+
"findings_recurring": 0,
|
|
90
|
+
"sqale_rating": "A",
|
|
91
|
+
"agent_results": {
|
|
92
|
+
"correctness": { "status": "ok", "symbols": 24, "sub_targets": 1, "findings": 0 },
|
|
93
|
+
"security": { "status": "ok", "symbols": 14, "sub_targets": 1, "findings": 0 },
|
|
94
|
+
"performance": { "status": "ok", "symbols": 13, "sub_targets": 1, "findings": 0 },
|
|
95
|
+
"architecture": { "status": "ok", "symbols": 30, "sub_targets": 1, "findings": 0 },
|
|
96
|
+
"testing": { "status": "ok", "symbols": 35, "sub_targets": 1, "findings": 0 }
|
|
97
|
+
},
|
|
98
|
+
"agent_overlap": {},
|
|
99
|
+
"estimated_remaining": null
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"date": "2026-04-11",
|
|
103
|
+
"commit": "59ea7a3",
|
|
104
|
+
"mode": "incremental",
|
|
105
|
+
"files_audited": 21,
|
|
106
|
+
"files_skipped": 0,
|
|
107
|
+
"findings_new": 0,
|
|
108
|
+
"findings_recurring": 0,
|
|
109
|
+
"sqale_rating": "A",
|
|
110
|
+
"agent_results": {
|
|
111
|
+
"correctness": { "status": "ok", "symbols": 24, "sub_targets": 1, "findings": 0 },
|
|
112
|
+
"security": { "status": "ok", "symbols": 14, "sub_targets": 1, "findings": 0 },
|
|
113
|
+
"performance": { "status": "ok", "symbols": 13, "sub_targets": 1, "findings": 0 },
|
|
114
|
+
"architecture": { "status": "ok", "symbols": 30, "sub_targets": 1, "findings": 0 },
|
|
115
|
+
"testing": { "status": "ok", "symbols": 35, "sub_targets": 1, "findings": 0 }
|
|
116
|
+
},
|
|
117
|
+
"agent_overlap": {},
|
|
118
|
+
"estimated_remaining": null
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"findings": {
|
|
122
|
+
"F-001": {
|
|
123
|
+
"status": "implemented",
|
|
124
|
+
"file": "src/compiler/coordinator.ts",
|
|
125
|
+
"symbol": "transform",
|
|
126
|
+
"category": "correctness",
|
|
127
|
+
"title": "AST Position Staleness After Code Modification",
|
|
128
|
+
"content_hash": "ast-position-staleness-coordinator-transform",
|
|
129
|
+
"file_hash": "",
|
|
130
|
+
"first_seen": "2026-04-11",
|
|
131
|
+
"last_seen": "2026-04-11",
|
|
132
|
+
"found_by": ["correctness"],
|
|
133
|
+
"priority_score": 66
|
|
134
|
+
},
|
|
135
|
+
"F-002": {
|
|
136
|
+
"status": "deferred",
|
|
137
|
+
"file": "src/compiler/coordinator.ts",
|
|
138
|
+
"symbol": "applyImports",
|
|
139
|
+
"category": "optimize",
|
|
140
|
+
"title": "Redundant SourceFile Recreation in applyImports Loop",
|
|
141
|
+
"content_hash": "redundant-sourcefile-recreation-applyimports",
|
|
142
|
+
"file_hash": "",
|
|
143
|
+
"first_seen": "2026-04-11",
|
|
144
|
+
"last_seen": "2026-04-11",
|
|
145
|
+
"found_by": ["performance"],
|
|
146
|
+
"priority_score": 44
|
|
147
|
+
},
|
|
148
|
+
"F-003": {
|
|
149
|
+
"status": "implemented",
|
|
150
|
+
"file": "src/",
|
|
151
|
+
"symbol": "*",
|
|
152
|
+
"category": "coverage",
|
|
153
|
+
"title": "Complete Absence of Test Infrastructure",
|
|
154
|
+
"content_hash": "missing-test-infrastructure",
|
|
155
|
+
"file_hash": "",
|
|
156
|
+
"first_seen": "2026-04-11",
|
|
157
|
+
"last_seen": "2026-04-11",
|
|
158
|
+
"found_by": ["testing"],
|
|
159
|
+
"priority_score": 114
|
|
160
|
+
},
|
|
161
|
+
"F-004": {
|
|
162
|
+
"status": "implemented",
|
|
163
|
+
"file": "src/compiler/language-service.ts",
|
|
164
|
+
"symbol": "get",
|
|
165
|
+
"category": "loc",
|
|
166
|
+
"title": "languageService.get() is dead code",
|
|
167
|
+
"content_hash": "dead-code-language-service-get",
|
|
168
|
+
"file_hash": "",
|
|
169
|
+
"first_seen": "2026-04-11",
|
|
170
|
+
"last_seen": "2026-04-11",
|
|
171
|
+
"found_by": ["architecture"],
|
|
172
|
+
"priority_score": 45
|
|
173
|
+
},
|
|
174
|
+
"F-005": {
|
|
175
|
+
"status": "implemented",
|
|
176
|
+
"file": "src/compiler/language-service.ts",
|
|
177
|
+
"symbol": "delete",
|
|
178
|
+
"category": "loc",
|
|
179
|
+
"title": "languageService.delete() is dead code",
|
|
180
|
+
"content_hash": "dead-code-language-service-delete",
|
|
181
|
+
"file_hash": "",
|
|
182
|
+
"first_seen": "2026-04-11",
|
|
183
|
+
"last_seen": "2026-04-11",
|
|
184
|
+
"found_by": ["architecture"],
|
|
185
|
+
"priority_score": 45
|
|
186
|
+
},
|
|
187
|
+
"F-006": {
|
|
188
|
+
"status": "implemented",
|
|
189
|
+
"file": "src/compiler/language-service.ts",
|
|
190
|
+
"symbol": "*",
|
|
191
|
+
"category": "coverage",
|
|
192
|
+
"title": "language-service.ts has 0 test coverage",
|
|
193
|
+
"content_hash": "no-test-coverage-language-service",
|
|
194
|
+
"file_hash": "",
|
|
195
|
+
"first_seen": "2026-04-11",
|
|
196
|
+
"last_seen": "2026-04-11",
|
|
197
|
+
"found_by": ["testing"],
|
|
198
|
+
"priority_score": 50
|
|
199
|
+
},
|
|
200
|
+
"F-007": {
|
|
201
|
+
"status": "open",
|
|
202
|
+
"file": "src/cli/tsc.ts",
|
|
203
|
+
"symbol": "*",
|
|
204
|
+
"category": "coverage",
|
|
205
|
+
"title": "cli/tsc.ts has 0 test coverage",
|
|
206
|
+
"content_hash": "no-test-coverage-cli-tsc",
|
|
207
|
+
"file_hash": "",
|
|
208
|
+
"first_seen": "2026-04-11",
|
|
209
|
+
"last_seen": "2026-04-11",
|
|
210
|
+
"found_by": ["testing"],
|
|
211
|
+
"priority_score": 35
|
|
212
|
+
},
|
|
213
|
+
"F-008": {
|
|
214
|
+
"status": "implemented",
|
|
215
|
+
"file": "src/compiler/coordinator.ts",
|
|
216
|
+
"symbol": "transform",
|
|
217
|
+
"category": "test-quality",
|
|
218
|
+
"title": "coordinator plugin.transform() throw path untested",
|
|
219
|
+
"content_hash": "test-quality-coordinator-throw-path",
|
|
220
|
+
"file_hash": "",
|
|
221
|
+
"first_seen": "2026-04-11",
|
|
222
|
+
"last_seen": "2026-04-11",
|
|
223
|
+
"found_by": ["testing"],
|
|
224
|
+
"priority_score": 48
|
|
225
|
+
},
|
|
226
|
+
"F-009": {
|
|
227
|
+
"status": "implemented",
|
|
228
|
+
"file": "src/compiler/coordinator.ts",
|
|
229
|
+
"symbol": "transform",
|
|
230
|
+
"category": "test-quality",
|
|
231
|
+
"title": "coordinator null sourceFile fallback path untested",
|
|
232
|
+
"content_hash": "test-quality-coordinator-null-sourcefile",
|
|
233
|
+
"file_hash": "",
|
|
234
|
+
"first_seen": "2026-04-11",
|
|
235
|
+
"last_seen": "2026-04-11",
|
|
236
|
+
"found_by": ["testing"],
|
|
237
|
+
"priority_score": 48
|
|
238
|
+
},
|
|
239
|
+
"F-010": {
|
|
240
|
+
"status": "implemented",
|
|
241
|
+
"file": "src/compiler/plugins/vite.ts",
|
|
242
|
+
"symbol": "transform",
|
|
243
|
+
"category": "test-quality",
|
|
244
|
+
"title": "vite plugin error catch path untested",
|
|
245
|
+
"content_hash": "test-quality-vite-error-catch",
|
|
246
|
+
"file_hash": "",
|
|
247
|
+
"first_seen": "2026-04-11",
|
|
248
|
+
"last_seen": "2026-04-11",
|
|
249
|
+
"found_by": ["testing"],
|
|
250
|
+
"priority_score": 48
|
|
251
|
+
},
|
|
252
|
+
"F-011": {
|
|
253
|
+
"status": "implemented",
|
|
254
|
+
"file": "src/compiler/plugins/vite.ts",
|
|
255
|
+
"symbol": "transform",
|
|
256
|
+
"category": "test-quality",
|
|
257
|
+
"title": "vite plugin sourceFile undefined fallback untested",
|
|
258
|
+
"content_hash": "test-quality-vite-sourcefile-fallback",
|
|
259
|
+
"file_hash": "",
|
|
260
|
+
"first_seen": "2026-04-11",
|
|
261
|
+
"last_seen": "2026-04-11",
|
|
262
|
+
"found_by": ["testing"],
|
|
263
|
+
"priority_score": 45
|
|
264
|
+
},
|
|
265
|
+
"F-012": {
|
|
266
|
+
"status": "implemented",
|
|
267
|
+
"file": "src/compiler/imports.ts",
|
|
268
|
+
"symbol": "includes",
|
|
269
|
+
"category": "test-quality",
|
|
270
|
+
"title": "imports.includes() getAliasedSymbol catch block untested",
|
|
271
|
+
"content_hash": "test-quality-imports-aliased-catch",
|
|
272
|
+
"file_hash": "",
|
|
273
|
+
"first_seen": "2026-04-11",
|
|
274
|
+
"last_seen": "2026-04-11",
|
|
275
|
+
"found_by": ["testing"],
|
|
276
|
+
"priority_score": 42
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
"clean_symbols": {},
|
|
280
|
+
"convergence": {
|
|
281
|
+
"per_category": {
|
|
282
|
+
"correctness": {
|
|
283
|
+
"findings_per_run": [1, 0, 0, 0, 0, 0],
|
|
284
|
+
"successful_runs": 6,
|
|
285
|
+
"consecutive_zero": 5,
|
|
286
|
+
"last_agent_success": true,
|
|
287
|
+
"status": "CONVERGED",
|
|
288
|
+
"reason": "0 new findings on 5 consecutive successful runs"
|
|
289
|
+
},
|
|
290
|
+
"security": {
|
|
291
|
+
"findings_per_run": [0, 0, 0, 0, 0, 0],
|
|
292
|
+
"successful_runs": 6,
|
|
293
|
+
"consecutive_zero": 6,
|
|
294
|
+
"last_agent_success": true,
|
|
295
|
+
"status": "CONVERGED",
|
|
296
|
+
"reason": "0 new findings on 6 consecutive successful runs"
|
|
297
|
+
},
|
|
298
|
+
"performance": {
|
|
299
|
+
"findings_per_run": [1, 0, 0, 0, 0, 0],
|
|
300
|
+
"successful_runs": 6,
|
|
301
|
+
"consecutive_zero": 5,
|
|
302
|
+
"last_agent_success": true,
|
|
303
|
+
"status": "CONVERGED",
|
|
304
|
+
"reason": "0 new findings on 5 consecutive successful runs"
|
|
305
|
+
},
|
|
306
|
+
"architecture": {
|
|
307
|
+
"findings_per_run": [0, 0, 0, 2, 0, 0],
|
|
308
|
+
"successful_runs": 6,
|
|
309
|
+
"consecutive_zero": 2,
|
|
310
|
+
"last_agent_success": true,
|
|
311
|
+
"status": "CONVERGED",
|
|
312
|
+
"reason": "0 new findings on 2 consecutive runs after fixes"
|
|
313
|
+
},
|
|
314
|
+
"testing": {
|
|
315
|
+
"findings_per_run": [1, 1, 0, 7, 0, 0],
|
|
316
|
+
"successful_runs": 6,
|
|
317
|
+
"consecutive_zero": 2,
|
|
318
|
+
"last_agent_success": true,
|
|
319
|
+
"status": "CONVERGED",
|
|
320
|
+
"reason": "0 new findings on 2 consecutive runs after fixes"
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
"overall": "CONVERGED",
|
|
324
|
+
"reason": "all 5 categories converged with 0 findings on 2+ consecutive runs"
|
|
325
|
+
}
|
|
326
|
+
}
|
package/build/cli/tsc.d.ts
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Plugin } from '../compiler/types.js';
|
|
2
|
+
type PluginConfig = {
|
|
3
|
+
transform: string;
|
|
4
|
+
};
|
|
5
|
+
declare function build(config: object, tsconfig: string, pluginConfigs: PluginConfig[]): Promise<void>;
|
|
6
|
+
declare function isPlugin(value: unknown): value is Plugin;
|
|
7
|
+
declare function loadPlugins(configs: PluginConfig[], root: string): Promise<Plugin[]>;
|
|
8
|
+
declare function normalizePath(fileName: string): string;
|
|
9
|
+
declare function runTscAlias(args: string[]): Promise<number>;
|
|
10
|
+
export { build, isPlugin, loadPlugins, normalizePath, runTscAlias };
|
package/build/cli/tsc.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
1
|
import { createRequire } from 'module';
|
|
2
|
+
import { PACKAGE_NAME } from '../constants.js';
|
|
3
3
|
import { pathToFileURL } from 'url';
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
import coordinator from '../compiler/coordinator.js';
|
|
4
6
|
import path from 'path';
|
|
5
7
|
import ts from 'typescript';
|
|
6
|
-
import coordinator from '../compiler/coordinator.js';
|
|
7
|
-
import { PACKAGE_NAME } from '../constants.js';
|
|
8
8
|
const BACKSLASH_REGEX = /\\/g;
|
|
9
9
|
let require = createRequire(import.meta.url), skipFlags = new Set(['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v']);
|
|
10
10
|
async function build(config, tsconfig, pluginConfigs) {
|
|
@@ -22,7 +22,7 @@ async function build(config, tsconfig, pluginConfigs) {
|
|
|
22
22
|
if (!sourceFile) {
|
|
23
23
|
continue;
|
|
24
24
|
}
|
|
25
|
-
let result = coordinator.transform(plugins, sourceFile.getFullText(), sourceFile, program, shared);
|
|
25
|
+
let result = coordinator.transform(plugins, sourceFile.getFullText(), sourceFile, program, root, shared);
|
|
26
26
|
if (result.changed) {
|
|
27
27
|
transformedFiles.set(normalizePath(fileName), result.code);
|
|
28
28
|
}
|
|
@@ -137,4 +137,7 @@ function runTscAlias(args) {
|
|
|
137
137
|
child.on('exit', (code) => resolve(code ?? 0));
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
if (process.env.VITEST === undefined) {
|
|
141
|
+
main();
|
|
142
|
+
}
|
|
143
|
+
export { build, isPlugin, loadPlugins, normalizePath, runTscAlias };
|
package/build/compiler/ast.d.ts
CHANGED
package/build/compiler/ast.js
CHANGED
|
@@ -6,8 +6,7 @@ type CoordinatorResult = {
|
|
|
6
6
|
sourceFile: ts.SourceFile;
|
|
7
7
|
};
|
|
8
8
|
declare const _default: {
|
|
9
|
-
|
|
10
|
-
transform: (plugins: Plugin[], code: string, file: ts.SourceFile, program: ts.Program, shared: SharedContext) => {
|
|
9
|
+
transform: (plugins: Plugin[], code: string, file: ts.SourceFile, program: ts.Program, root: string, shared: SharedContext) => {
|
|
11
10
|
changed: boolean;
|
|
12
11
|
code: string;
|
|
13
12
|
sourceFile: ts.SourceFile;
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { ts } from '../index.js';
|
|
2
2
|
import imports from './imports.js';
|
|
3
|
+
import languageService from './language-service.js';
|
|
3
4
|
function applyImports(code, file, intents) {
|
|
5
|
+
let merged = new Map();
|
|
4
6
|
for (let i = 0, n = intents.length; i < n; i++) {
|
|
5
|
-
let intent = intents[i];
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
let intent = intents[i], existing = merged.get(intent.package);
|
|
8
|
+
if (existing) {
|
|
9
|
+
if (intent.add) {
|
|
10
|
+
(existing.add ??= []).push(...intent.add);
|
|
11
|
+
}
|
|
12
|
+
if (intent.namespace) {
|
|
13
|
+
existing.namespace = intent.namespace;
|
|
14
|
+
}
|
|
15
|
+
if (intent.remove) {
|
|
16
|
+
(existing.remove ??= []).push(...intent.remove);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
merged.set(intent.package, {
|
|
21
|
+
add: intent.add ? [...intent.add] : undefined,
|
|
22
|
+
namespace: intent.namespace,
|
|
23
|
+
remove: intent.remove ? [...intent.remove] : undefined
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
let keys = [...merged.keys()];
|
|
28
|
+
for (let i = 0, n = keys.length; i < n; i++) {
|
|
29
|
+
code = modify(code, file, keys[i], merged.get(keys[i]));
|
|
11
30
|
if (i < n - 1) {
|
|
12
31
|
file = ts.createSourceFile(file.fileName, code, file.languageVersion, true);
|
|
13
32
|
}
|
|
@@ -39,9 +58,9 @@ function applyPrepend(code, file, prepend) {
|
|
|
39
58
|
}
|
|
40
59
|
}
|
|
41
60
|
if (position === 0) {
|
|
42
|
-
return prepend.join('\n') + code;
|
|
61
|
+
return prepend.join('\n') + '\n' + code;
|
|
43
62
|
}
|
|
44
|
-
return code.slice(0, position) + prepend.join('\n') + code.slice(position);
|
|
63
|
+
return code.slice(0, position) + '\n' + prepend.join('\n') + '\n' + code.slice(position);
|
|
45
64
|
}
|
|
46
65
|
function hasPattern(code, patterns) {
|
|
47
66
|
for (let i = 0, n = patterns.length; i < n; i++) {
|
|
@@ -104,32 +123,25 @@ function replaceReverse(code, replacements) {
|
|
|
104
123
|
return code;
|
|
105
124
|
}
|
|
106
125
|
replacements.sort((a, b) => b.start - a.start);
|
|
107
|
-
let
|
|
126
|
+
let parts = [], pos = code.length;
|
|
108
127
|
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
109
128
|
let r = replacements[i];
|
|
110
|
-
|
|
129
|
+
if (r.end < pos) {
|
|
130
|
+
parts.push(code.substring(r.end, pos));
|
|
131
|
+
}
|
|
132
|
+
parts.push(r.newText);
|
|
133
|
+
pos = r.start;
|
|
134
|
+
}
|
|
135
|
+
if (pos > 0) {
|
|
136
|
+
parts.push(code.substring(0, pos));
|
|
111
137
|
}
|
|
112
|
-
return
|
|
138
|
+
return parts.reverse().join('');
|
|
113
139
|
}
|
|
114
|
-
const
|
|
115
|
-
let baseHost = ts.createCompilerHost(baseProgram.getCompilerOptions()), options = baseProgram.getCompilerOptions();
|
|
116
|
-
return ts.createProgram(baseProgram.getRootFileNames(), options, {
|
|
117
|
-
...baseHost,
|
|
118
|
-
getSourceFile: (name, languageVersion) => {
|
|
119
|
-
if (name === fileName || name === fileName.replace(/\\/g, '/')) {
|
|
120
|
-
return ts.createSourceFile(name, newContent, languageVersion, true);
|
|
121
|
-
}
|
|
122
|
-
return baseProgram.getSourceFile(name) ?? baseHost.getSourceFile(name, languageVersion);
|
|
123
|
-
},
|
|
124
|
-
fileExists: (name) => baseHost.fileExists(name),
|
|
125
|
-
readFile: (name) => name === fileName ? newContent : baseHost.readFile(name)
|
|
126
|
-
}, baseProgram);
|
|
127
|
-
};
|
|
128
|
-
const transform = (plugins, code, file, program, shared) => {
|
|
140
|
+
const transform = (plugins, code, file, program, root, shared) => {
|
|
129
141
|
if (plugins.length === 0) {
|
|
130
142
|
return { changed: false, code, sourceFile: file };
|
|
131
143
|
}
|
|
132
|
-
let changed = false, currentCode = code, currentFile = file, currentProgram = program, fileName = file.fileName;
|
|
144
|
+
let changed = false, currentCode = code, currentFile = file, currentProgram = program, fileName = file.fileName, last = plugins.length - 1;
|
|
133
145
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
134
146
|
let plugin = plugins[i];
|
|
135
147
|
if (plugin.patterns && !hasPattern(currentCode, plugin.patterns)) {
|
|
@@ -147,17 +159,23 @@ const transform = (plugins, code, file, program, shared) => {
|
|
|
147
159
|
pluginChanged = true;
|
|
148
160
|
}
|
|
149
161
|
if (prepend?.length) {
|
|
162
|
+
if (pluginChanged) {
|
|
163
|
+
currentFile = ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
164
|
+
}
|
|
150
165
|
currentCode = applyPrepend(currentCode, currentFile, prepend);
|
|
151
166
|
pluginChanged = true;
|
|
152
167
|
}
|
|
153
168
|
if (imports?.length) {
|
|
169
|
+
if (pluginChanged) {
|
|
170
|
+
currentFile = ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
171
|
+
}
|
|
154
172
|
currentCode = applyImports(currentCode, currentFile, imports);
|
|
155
173
|
pluginChanged = true;
|
|
156
174
|
}
|
|
157
175
|
if (pluginChanged) {
|
|
158
176
|
changed = true;
|
|
159
|
-
if (i <
|
|
160
|
-
currentProgram =
|
|
177
|
+
if (i < last) {
|
|
178
|
+
currentProgram = languageService.update(root, fileName, currentCode);
|
|
161
179
|
currentFile = currentProgram.getSourceFile(fileName) ||
|
|
162
180
|
ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
163
181
|
}
|
|
@@ -168,4 +186,4 @@ const transform = (plugins, code, file, program, shared) => {
|
|
|
168
186
|
}
|
|
169
187
|
return { changed, code: currentCode, sourceFile: currentFile };
|
|
170
188
|
};
|
|
171
|
-
export default {
|
|
189
|
+
export default { transform };
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { ts } from '../index.js';
|
|
2
2
|
let cache = new WeakMap();
|
|
3
|
+
function fileNameMatchesPackage(fileName, pkg) {
|
|
4
|
+
let normalized = fileName.replace(/\\/g, '/'), marker = `/node_modules/${pkg}/`;
|
|
5
|
+
return normalized.includes(marker);
|
|
6
|
+
}
|
|
3
7
|
const all = (file, pkg) => {
|
|
4
8
|
let imports = [];
|
|
5
9
|
for (let i = 0, n = file.statements.length; i < n; i++) {
|
|
@@ -60,7 +64,7 @@ const includes = (checker, node, pkg, symbolName) => {
|
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
}
|
|
63
|
-
if (decl.getSourceFile().fileName
|
|
67
|
+
if (fileNameMatchesPackage(decl.getSourceFile().fileName, pkg)) {
|
|
64
68
|
return true;
|
|
65
69
|
}
|
|
66
70
|
}
|
|
@@ -76,7 +80,7 @@ const includes = (checker, node, pkg, symbolName) => {
|
|
|
76
80
|
if (declarations && declarations.length > 0) {
|
|
77
81
|
for (let i = 0, n = declarations.length; i < n; i++) {
|
|
78
82
|
let decl = declarations[i];
|
|
79
|
-
if (decl.getSourceFile().fileName
|
|
83
|
+
if (fileNameMatchesPackage(decl.getSourceFile().fileName, pkg)) {
|
|
80
84
|
return true;
|
|
81
85
|
}
|
|
82
86
|
}
|
|
@@ -87,7 +91,7 @@ const includes = (checker, node, pkg, symbolName) => {
|
|
|
87
91
|
let aliasedDecls = aliased.getDeclarations();
|
|
88
92
|
if (aliasedDecls) {
|
|
89
93
|
for (let i = 0, n = aliasedDecls.length; i < n; i++) {
|
|
90
|
-
if (aliasedDecls[i].getSourceFile().fileName
|
|
94
|
+
if (fileNameMatchesPackage(aliasedDecls[i].getSourceFile().fileName, pkg)) {
|
|
91
95
|
return true;
|
|
92
96
|
}
|
|
93
97
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ts } from '../index.js';
|
|
2
|
+
declare const invalidate: (root: string, fileName: string) => void;
|
|
3
|
+
declare const update: (root: string, fileName: string, content: string) => ts.Program;
|
|
4
|
+
declare const _default: {
|
|
5
|
+
invalidate: (root: string, fileName: string) => void;
|
|
6
|
+
update: (root: string, fileName: string, content: string) => ts.Program;
|
|
7
|
+
};
|
|
8
|
+
export default _default;
|
|
9
|
+
export { invalidate, update };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { PACKAGE_NAME } from '../constants.js';
|
|
2
|
+
import { ts } from '../index.js';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
let cache = new Map();
|
|
5
|
+
function create(root) {
|
|
6
|
+
let tsconfig = ts.findConfigFile(root, ts.sys.fileExists, 'tsconfig.json');
|
|
7
|
+
if (!tsconfig) {
|
|
8
|
+
throw new Error(`${PACKAGE_NAME}: tsconfig.json not found`);
|
|
9
|
+
}
|
|
10
|
+
let file = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
11
|
+
if (file.error) {
|
|
12
|
+
throw new Error(`${PACKAGE_NAME}: error reading tsconfig.json ${file.error.messageText}`);
|
|
13
|
+
}
|
|
14
|
+
let parsed = ts.parseJsonConfigFileContent(file.config, ts.sys, path.dirname(tsconfig));
|
|
15
|
+
if (parsed.errors.length > 0) {
|
|
16
|
+
throw new Error(`${PACKAGE_NAME}: error parsing tsconfig.json ${parsed.errors[0].messageText}`);
|
|
17
|
+
}
|
|
18
|
+
let contents = new Map(), rootFiles = new Set(parsed.fileNames.map(f => f.replace(/\\/g, '/'))), versions = new Map();
|
|
19
|
+
for (let fileName of rootFiles) {
|
|
20
|
+
versions.set(fileName, 0);
|
|
21
|
+
}
|
|
22
|
+
let host = {
|
|
23
|
+
fileExists: ts.sys.fileExists,
|
|
24
|
+
getCompilationSettings: () => parsed.options,
|
|
25
|
+
getCurrentDirectory: () => root,
|
|
26
|
+
getDefaultLibFileName: ts.getDefaultLibFilePath,
|
|
27
|
+
getScriptFileNames: () => [...rootFiles],
|
|
28
|
+
getScriptSnapshot: (fileName) => {
|
|
29
|
+
let content = contents.get(fileName);
|
|
30
|
+
if (content !== undefined) {
|
|
31
|
+
return ts.ScriptSnapshot.fromString(content);
|
|
32
|
+
}
|
|
33
|
+
if (!ts.sys.fileExists(fileName)) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return ts.ScriptSnapshot.fromString(ts.sys.readFile(fileName) || '');
|
|
37
|
+
},
|
|
38
|
+
getScriptVersion: (fileName) => String(versions.get(fileName) || 0),
|
|
39
|
+
readFile: ts.sys.readFile
|
|
40
|
+
};
|
|
41
|
+
return { contents, host, rootFiles, service: ts.createLanguageService(host), versions };
|
|
42
|
+
}
|
|
43
|
+
function getEntry(root) {
|
|
44
|
+
let entry = cache.get(root);
|
|
45
|
+
if (!entry) {
|
|
46
|
+
entry = create(root);
|
|
47
|
+
cache.set(root, entry);
|
|
48
|
+
}
|
|
49
|
+
return entry;
|
|
50
|
+
}
|
|
51
|
+
const invalidate = (root, fileName) => {
|
|
52
|
+
let entry = cache.get(root);
|
|
53
|
+
if (entry) {
|
|
54
|
+
let normalized = fileName.replace(/\\/g, '/');
|
|
55
|
+
entry.contents.delete(normalized);
|
|
56
|
+
entry.versions.set(normalized, (entry.versions.get(normalized) || 0) + 1);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const update = (root, fileName, content) => {
|
|
60
|
+
let entry = getEntry(root), normalized = fileName.replace(/\\/g, '/');
|
|
61
|
+
if (!entry.rootFiles.has(normalized)) {
|
|
62
|
+
entry.rootFiles.add(normalized);
|
|
63
|
+
}
|
|
64
|
+
entry.contents.set(normalized, content);
|
|
65
|
+
entry.versions.set(normalized, (entry.versions.get(normalized) || 0) + 1);
|
|
66
|
+
let program = entry.service.getProgram();
|
|
67
|
+
if (!program) {
|
|
68
|
+
throw new Error(`${PACKAGE_NAME}: failed to get program from language service`);
|
|
69
|
+
}
|
|
70
|
+
return program;
|
|
71
|
+
};
|
|
72
|
+
export default { invalidate, update };
|
|
73
|
+
export { invalidate, update };
|