@esportsplus/typescript 0.29.0 → 0.29.5
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/bump.yml +1 -1
- package/.github/workflows/dependabot.yml +4 -4
- package/.github/workflows/publish.yml +4 -5
- package/README.md +146 -0
- package/build/cli/tsc.d.ts +10 -1
- package/build/cli/tsc.js +7 -4
- package/build/compiler/ast.d.ts +2 -5
- package/build/compiler/ast.js +1 -1
- package/build/compiler/coordinator.js +42 -11
- package/build/compiler/imports.js +7 -3
- package/build/compiler/language-service.d.ts +2 -5
- package/build/compiler/language-service.js +4 -14
- package/build/compiler/plugins/vite.js +7 -2
- package/package.json +14 -8
- package/src/cli/tsc.ts +11 -6
- package/src/compiler/ast.ts +2 -7
- package/src/compiler/coordinator.ts +55 -18
- package/src/compiler/imports.ts +11 -3
- package/src/compiler/language-service.ts +5 -19
- package/src/compiler/plugins/vite.ts +13 -4
- 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/tsconfig.node.json +3 -0
- package/vitest.config.ts +14 -0
|
@@ -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
|
+
}
|
|
@@ -20,13 +20,13 @@ jobs:
|
|
|
20
20
|
build:
|
|
21
21
|
runs-on: ubuntu-latest
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
24
|
-
- uses: pnpm/action-setup@
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
- uses: pnpm/action-setup@v6
|
|
25
25
|
name: Install pnpm
|
|
26
26
|
with:
|
|
27
27
|
run_install: false
|
|
28
28
|
version: latest
|
|
29
|
-
- uses: actions/setup-node@
|
|
29
|
+
- uses: actions/setup-node@v6
|
|
30
30
|
with:
|
|
31
31
|
cache: 'pnpm'
|
|
32
32
|
node-version: 'latest'
|
|
@@ -43,7 +43,7 @@ jobs:
|
|
|
43
43
|
runs-on: ubuntu-latest
|
|
44
44
|
if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request' }}
|
|
45
45
|
steps:
|
|
46
|
-
- uses: dependabot/fetch-metadata@
|
|
46
|
+
- uses: dependabot/fetch-metadata@v3
|
|
47
47
|
id: metadata
|
|
48
48
|
with:
|
|
49
49
|
alert-lookup: true
|
|
@@ -24,20 +24,19 @@ jobs:
|
|
|
24
24
|
contents: read
|
|
25
25
|
id-token: write
|
|
26
26
|
steps:
|
|
27
|
-
- uses: actions/checkout@
|
|
28
|
-
- uses: pnpm/action-setup@
|
|
27
|
+
- uses: actions/checkout@v7
|
|
28
|
+
- uses: pnpm/action-setup@v6
|
|
29
29
|
name: Install pnpm
|
|
30
30
|
with:
|
|
31
31
|
run_install: false
|
|
32
32
|
version: latest
|
|
33
|
-
- uses: actions/setup-node@
|
|
33
|
+
- uses: actions/setup-node@v6
|
|
34
34
|
with:
|
|
35
35
|
cache: 'pnpm'
|
|
36
36
|
node-version: 'latest'
|
|
37
37
|
registry-url: 'https://registry.npmjs.org'
|
|
38
|
-
- run: pnpm config delete always-auth
|
|
39
38
|
- run: pnpm i
|
|
40
39
|
env:
|
|
41
40
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
42
41
|
- run: pnpm build
|
|
43
|
-
- run: pnpm publish --
|
|
42
|
+
- run: pnpm publish --no-git-checks
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @esportsplus/typescript
|
|
2
|
+
|
|
3
|
+
TypeScript compiler plugin framework with coordinated AST transformations, import management, and build tool integration.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @esportsplus/typescript
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Extends the TypeScript compiler with a plugin architecture for custom AST transformations. Plugins receive type-checked AST nodes with accurate positions at every stage, return declarative intents (replacements, imports, prepends), and the coordinator applies them in the correct order.
|
|
14
|
+
|
|
15
|
+
**Key features:**
|
|
16
|
+
- Multi-plugin coordination with fresh AST positions between stages
|
|
17
|
+
- Declarative import management (add/remove specifiers, namespace imports)
|
|
18
|
+
- Vite plugin for dev/build integration
|
|
19
|
+
- CLI wrapper for `tsc` with automatic plugin detection
|
|
20
|
+
- Language service caching for incremental compilation
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Plugin
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import type { Plugin } from '@esportsplus/typescript/compiler';
|
|
28
|
+
|
|
29
|
+
let plugin: Plugin = {
|
|
30
|
+
// Optional: skip files that don't contain these strings
|
|
31
|
+
patterns: ['myFunction'],
|
|
32
|
+
|
|
33
|
+
transform({ checker, code, sourceFile, shared }) {
|
|
34
|
+
// Return declarative transformation intents
|
|
35
|
+
return {
|
|
36
|
+
imports: [
|
|
37
|
+
{ package: 'my-lib', add: ['helper'], remove: ['deprecated'] }
|
|
38
|
+
],
|
|
39
|
+
prepend: [
|
|
40
|
+
'let __cache = new Map();'
|
|
41
|
+
],
|
|
42
|
+
replacements: [
|
|
43
|
+
{
|
|
44
|
+
node: someAstNode,
|
|
45
|
+
generate: (sf) => `transformedCode()`
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Vite
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { plugin } from '@esportsplus/typescript/compiler';
|
|
57
|
+
|
|
58
|
+
export default defineConfig({
|
|
59
|
+
plugins: [
|
|
60
|
+
plugin.vite({
|
|
61
|
+
name: 'my-transforms',
|
|
62
|
+
plugins: [myPlugin]
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### CLI
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Compiles with plugins from tsconfig.json, then resolves path aliases
|
|
72
|
+
tsc
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The CLI detects plugins in `tsconfig.json` `compilerOptions.plugins`, loads them, runs coordinated compilation, and automatically calls `tsc-alias` afterward.
|
|
76
|
+
|
|
77
|
+
## API
|
|
78
|
+
|
|
79
|
+
### `@esportsplus/typescript`
|
|
80
|
+
|
|
81
|
+
Re-exports the TypeScript compiler API (`ts`).
|
|
82
|
+
|
|
83
|
+
### `@esportsplus/typescript/compiler`
|
|
84
|
+
|
|
85
|
+
| Export | Description |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `ast` | AST utilities — expression names, property paths, node testing |
|
|
88
|
+
| `code` | Template literal code generation with escaping |
|
|
89
|
+
| `coordinator` | Multi-plugin transformation orchestrator |
|
|
90
|
+
| `imports` | Import detection and modification (WeakMap cached) |
|
|
91
|
+
| `plugin` | Built-in plugins (`tsc`, `vite`) |
|
|
92
|
+
| `uid` | Unique identifier generation |
|
|
93
|
+
| `languageService` | Cached TypeScript language service |
|
|
94
|
+
|
|
95
|
+
### Types
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
type Plugin = {
|
|
99
|
+
patterns?: string[];
|
|
100
|
+
transform: (ctx: TransformContext) => TransformResult;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
type TransformContext = {
|
|
104
|
+
checker: ts.TypeChecker;
|
|
105
|
+
code: string;
|
|
106
|
+
program: ts.Program;
|
|
107
|
+
shared: SharedContext;
|
|
108
|
+
sourceFile: ts.SourceFile;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
type TransformResult = {
|
|
112
|
+
imports?: ImportIntent[];
|
|
113
|
+
prepend?: string[];
|
|
114
|
+
replacements?: ReplacementIntent[];
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
type ImportIntent = {
|
|
118
|
+
add?: string[];
|
|
119
|
+
namespace?: string;
|
|
120
|
+
package: string;
|
|
121
|
+
remove?: string[];
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
type ReplacementIntent = {
|
|
125
|
+
generate: (sourceFile: ts.SourceFile) => string;
|
|
126
|
+
node: ts.Node;
|
|
127
|
+
};
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Shared Config
|
|
131
|
+
|
|
132
|
+
Importable base tsconfig files:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{ "extends": "@esportsplus/typescript/tsconfig.browser.json" }
|
|
136
|
+
{ "extends": "@esportsplus/typescript/tsconfig.node.json" }
|
|
137
|
+
{ "extends": "@esportsplus/typescript/tsconfig.package.json" }
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Scripts
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pnpm build # tsc && tsc-alias
|
|
144
|
+
pnpm test # vitest run
|
|
145
|
+
pnpm bench:run # vitest bench --run
|
|
146
|
+
```
|
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) {
|
|
@@ -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
|
@@ -2,13 +2,31 @@ import { ts } from '../index.js';
|
|
|
2
2
|
import imports from './imports.js';
|
|
3
3
|
import languageService from './language-service.js';
|
|
4
4
|
function applyImports(code, file, intents) {
|
|
5
|
+
let merged = new Map();
|
|
5
6
|
for (let i = 0, n = intents.length; i < n; i++) {
|
|
6
|
-
let intent = intents[i];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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]));
|
|
12
30
|
if (i < n - 1) {
|
|
13
31
|
file = ts.createSourceFile(file.fileName, code, file.languageVersion, true);
|
|
14
32
|
}
|
|
@@ -40,9 +58,9 @@ function applyPrepend(code, file, prepend) {
|
|
|
40
58
|
}
|
|
41
59
|
}
|
|
42
60
|
if (position === 0) {
|
|
43
|
-
return prepend.join('\n') + code;
|
|
61
|
+
return prepend.join('\n') + '\n' + code;
|
|
44
62
|
}
|
|
45
|
-
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);
|
|
46
64
|
}
|
|
47
65
|
function hasPattern(code, patterns) {
|
|
48
66
|
for (let i = 0, n = patterns.length; i < n; i++) {
|
|
@@ -105,12 +123,19 @@ function replaceReverse(code, replacements) {
|
|
|
105
123
|
return code;
|
|
106
124
|
}
|
|
107
125
|
replacements.sort((a, b) => b.start - a.start);
|
|
108
|
-
let
|
|
126
|
+
let parts = [], pos = code.length;
|
|
109
127
|
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
110
128
|
let r = replacements[i];
|
|
111
|
-
|
|
129
|
+
if (r.end < pos) {
|
|
130
|
+
parts.push(code.substring(r.end, pos));
|
|
131
|
+
}
|
|
132
|
+
parts.push(r.newText);
|
|
133
|
+
pos = r.start;
|
|
112
134
|
}
|
|
113
|
-
|
|
135
|
+
if (pos > 0) {
|
|
136
|
+
parts.push(code.substring(0, pos));
|
|
137
|
+
}
|
|
138
|
+
return parts.reverse().join('');
|
|
114
139
|
}
|
|
115
140
|
const transform = (plugins, code, file, program, root, shared) => {
|
|
116
141
|
if (plugins.length === 0) {
|
|
@@ -134,10 +159,16 @@ const transform = (plugins, code, file, program, root, shared) => {
|
|
|
134
159
|
pluginChanged = true;
|
|
135
160
|
}
|
|
136
161
|
if (prepend?.length) {
|
|
162
|
+
if (pluginChanged) {
|
|
163
|
+
currentFile = ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
164
|
+
}
|
|
137
165
|
currentCode = applyPrepend(currentCode, currentFile, prepend);
|
|
138
166
|
pluginChanged = true;
|
|
139
167
|
}
|
|
140
168
|
if (imports?.length) {
|
|
169
|
+
if (pluginChanged) {
|
|
170
|
+
currentFile = ts.createSourceFile(fileName, currentCode, file.languageVersion, true);
|
|
171
|
+
}
|
|
141
172
|
currentCode = applyImports(currentCode, currentFile, imports);
|
|
142
173
|
pluginChanged = true;
|
|
143
174
|
}
|