@nestia/core 12.0.0-dev.20260521.6 → 12.0.0-dev.20260612.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/LICENSE +21 -21
- package/MIGRATION.md +169 -169
- package/README.md +93 -93
- package/lib/adaptors/McpAdaptor.d.ts +75 -0
- package/lib/adaptors/McpAdaptor.js +257 -0
- package/lib/adaptors/McpAdaptor.js.map +1 -0
- package/lib/adaptors/WebSocketAdaptor.js +4 -4
- package/lib/adaptors/WebSocketAdaptor.js.map +1 -1
- package/lib/decorators/McpRoute.d.ts +69 -0
- package/lib/decorators/McpRoute.js +58 -0
- package/lib/decorators/McpRoute.js.map +1 -0
- package/lib/decorators/TypedParam.js +4 -4
- package/lib/decorators/TypedParam.js.map +1 -1
- package/lib/decorators/TypedRoute.js +1 -1
- package/lib/decorators/TypedRoute.js.map +1 -1
- package/lib/decorators/internal/IMcpRouteReflect.d.ts +2 -0
- package/lib/decorators/internal/IMcpRouteReflect.js +3 -0
- package/lib/decorators/internal/IMcpRouteReflect.js.map +1 -0
- package/lib/decorators/internal/get_path_and_querify.js +4 -4
- package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
- package/lib/decorators/internal/get_path_and_stringify.js +4 -4
- package/lib/decorators/internal/get_path_and_stringify.js.map +1 -1
- package/lib/decorators/internal/load_controller.js +34 -65
- package/lib/decorators/internal/load_controller.js.map +1 -1
- package/lib/decorators/internal/validate_request_body.js +4 -4
- package/lib/decorators/internal/validate_request_body.js.map +1 -1
- package/lib/decorators/internal/validate_request_form_data.js +4 -4
- package/lib/decorators/internal/validate_request_form_data.js.map +1 -1
- package/lib/decorators/internal/validate_request_headers.js +4 -4
- package/lib/decorators/internal/validate_request_headers.js.map +1 -1
- package/lib/decorators/internal/validate_request_query.js +4 -4
- package/lib/decorators/internal/validate_request_query.js.map +1 -1
- package/lib/module.d.ts +2 -0
- package/lib/module.js +2 -0
- package/lib/module.js.map +1 -1
- package/native/cmd/ttsc-nestia/main.go +11 -11
- package/native/go.mod +32 -32
- package/native/go.sum +54 -54
- package/native/plugin/plan.go +102 -102
- package/native/transform/ast.go +32 -32
- package/native/transform/build.go +380 -437
- package/native/transform/cleanup.go +408 -408
- package/native/transform/contributor.go +97 -68
- package/native/transform/core_querify.go +231 -227
- package/native/transform/core_transform.go +1996 -1713
- package/native/transform/core_websocket.go +115 -115
- package/native/transform/exports.go +13 -13
- package/native/transform/mcp_transform.go +414 -0
- package/native/transform/node_transform.go +357 -0
- package/native/transform/path_rewrite.go +285 -285
- package/native/transform/printer.go +244 -244
- package/native/transform/rewrite.go +668 -662
- package/native/transform/run.go +73 -73
- package/native/transform/transform.go +336 -387
- package/native/transform/typia_fast.go +352 -326
- package/native/transform/typia_replacement.go +24 -24
- package/native/transform.cjs +43 -43
- package/package.json +15 -8
- package/src/adaptors/McpAdaptor.ts +276 -0
- package/src/adaptors/WebSocketAdaptor.ts +429 -429
- package/src/decorators/DynamicModule.ts +44 -44
- package/src/decorators/EncryptedBody.ts +97 -97
- package/src/decorators/EncryptedController.ts +40 -40
- package/src/decorators/EncryptedModule.ts +98 -98
- package/src/decorators/EncryptedRoute.ts +213 -213
- package/src/decorators/HumanRoute.ts +21 -21
- package/src/decorators/McpRoute.ts +154 -0
- package/src/decorators/NoTransformConfigurationError.ts +40 -40
- package/src/decorators/PlainBody.ts +76 -76
- package/src/decorators/SwaggerCustomizer.ts +97 -97
- package/src/decorators/SwaggerExample.ts +180 -180
- package/src/decorators/TypedBody.ts +57 -57
- package/src/decorators/TypedException.ts +147 -147
- package/src/decorators/TypedFormData.ts +187 -187
- package/src/decorators/TypedHeaders.ts +66 -66
- package/src/decorators/TypedParam.ts +77 -77
- package/src/decorators/TypedQuery.ts +234 -234
- package/src/decorators/TypedRoute.ts +198 -196
- package/src/decorators/WebSocketRoute.ts +242 -242
- package/src/decorators/doNotThrowTransformError.ts +5 -5
- package/src/decorators/internal/EncryptedConstant.ts +2 -2
- package/src/decorators/internal/IMcpRouteReflect.ts +40 -0
- package/src/decorators/internal/IWebSocketRouteReflect.ts +23 -23
- package/src/decorators/internal/get_path_and_querify.ts +94 -94
- package/src/decorators/internal/get_path_and_stringify.ts +110 -110
- package/src/decorators/internal/get_text_body.ts +16 -16
- package/src/decorators/internal/headers_to_object.ts +11 -11
- package/src/decorators/internal/is_request_body_undefined.ts +12 -12
- package/src/decorators/internal/load_controller.ts +91 -76
- package/src/decorators/internal/route_error.ts +43 -43
- package/src/decorators/internal/validate_request_body.ts +64 -64
- package/src/decorators/internal/validate_request_form_data.ts +67 -67
- package/src/decorators/internal/validate_request_headers.ts +76 -76
- package/src/decorators/internal/validate_request_query.ts +83 -83
- package/src/index.ts +5 -5
- package/src/module.ts +25 -23
- package/src/options/IRequestBodyValidator.ts +20 -20
- package/src/options/IRequestFormDataProps.ts +27 -27
- package/src/options/IRequestHeadersValidator.ts +22 -22
- package/src/options/IRequestQueryValidator.ts +20 -20
- package/src/options/IResponseBodyQuerifier.ts +25 -25
- package/src/options/IResponseBodyStringifier.ts +30 -30
- package/src/transform.ts +101 -101
- package/src/typings/Creator.ts +3 -3
- package/src/typings/get-function-location.d.ts +7 -7
- package/src/utils/ArrayUtil.ts +7 -7
- package/src/utils/ExceptionManager.ts +115 -115
- package/src/utils/Singleton.ts +16 -16
- package/src/utils/SourceFinder.ts +54 -54
- package/src/utils/VersioningStrategy.ts +27 -27
- package/native/transform/cleanup_test.go +0 -76
- package/native/transform/commonjs_import_alias_test.go +0 -49
- package/native/transform/core_dispatch_test.go +0 -127
- package/native/transform/path_rewrite_test.go +0 -243
- package/native/transform/rewrite_test.go +0 -118
- package/native/transform/rewrite_unique_base_test.go +0 -48
|
@@ -1,437 +1,380 @@
|
|
|
1
|
-
package transform
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"github.com/
|
|
17
|
-
"github.com/samchon/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
fs.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
plan.
|
|
96
|
-
plan.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
return len(sites), recognized, diagnostics
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
func typiaBuildRewriteSortKey(site typiaadapter.CallSite) int {
|
|
385
|
-
node := site.Call.AsNode()
|
|
386
|
-
if node == nil {
|
|
387
|
-
return 0
|
|
388
|
-
}
|
|
389
|
-
insideDecorator := false
|
|
390
|
-
classEnd := 0
|
|
391
|
-
for current := node.Parent; current != nil; current = current.Parent {
|
|
392
|
-
if current.Kind == NestiaCoreKindDecorator {
|
|
393
|
-
insideDecorator = true
|
|
394
|
-
}
|
|
395
|
-
if current.Kind == shimast.KindClassDeclaration || current.Kind == shimast.KindClassExpression {
|
|
396
|
-
classEnd = current.End()
|
|
397
|
-
break
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
if insideDecorator == false {
|
|
401
|
-
return node.Pos()
|
|
402
|
-
}
|
|
403
|
-
if classEnd != 0 {
|
|
404
|
-
return classEnd + node.Pos()
|
|
405
|
-
}
|
|
406
|
-
return node.Pos() + 1_000_000_000
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
func readTypiaPluginOptions(cwd, tsconfigPath string) typiaadapter.PluginOptions {
|
|
410
|
-
path := tsconfigPath
|
|
411
|
-
if !filepath.IsAbs(path) {
|
|
412
|
-
path = filepath.Join(cwd, path)
|
|
413
|
-
}
|
|
414
|
-
data, err := os.ReadFile(path)
|
|
415
|
-
if err != nil {
|
|
416
|
-
return typiaadapter.PluginOptions{}
|
|
417
|
-
}
|
|
418
|
-
text := string(data)
|
|
419
|
-
return typiaadapter.PluginOptions{
|
|
420
|
-
Functional: regexp.MustCompile(`(?s)"functional"\s*:\s*true`).MatchString(text),
|
|
421
|
-
Numeric: regexp.MustCompile(`(?s)"numeric"\s*:\s*true`).MatchString(text),
|
|
422
|
-
Finite: regexp.MustCompile(`(?s)"finite"\s*:\s*true`).MatchString(text),
|
|
423
|
-
Undefined: regexp.MustCompile(`(?s)"undefined"\s*:\s*true`).MatchString(text),
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
func resolveCWD(label string, cwdOverride string) (string, bool) {
|
|
428
|
-
if cwdOverride != "" {
|
|
429
|
-
return cwdOverride, true
|
|
430
|
-
}
|
|
431
|
-
cwd, err := os.Getwd()
|
|
432
|
-
if err != nil {
|
|
433
|
-
fmt.Fprintf(stderr, "%s: cwd: %v\n", label, err)
|
|
434
|
-
return "", false
|
|
435
|
-
}
|
|
436
|
-
return cwd, true
|
|
437
|
-
}
|
|
1
|
+
package transform
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"flag"
|
|
7
|
+
"fmt"
|
|
8
|
+
"io"
|
|
9
|
+
"os"
|
|
10
|
+
"path/filepath"
|
|
11
|
+
"regexp"
|
|
12
|
+
"time"
|
|
13
|
+
|
|
14
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
15
|
+
shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
|
|
16
|
+
shimscanner "github.com/microsoft/typescript-go/shim/scanner"
|
|
17
|
+
"github.com/samchon/nestia/packages/core/native/plugin"
|
|
18
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
19
|
+
typiaadapter "github.com/samchon/typia/packages/typia/native/adapter"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
func runBuild(args []string) int {
|
|
23
|
+
profile := os.Getenv("TTSC_NESTIA_PROFILE") != ""
|
|
24
|
+
var totalStarted time.Time
|
|
25
|
+
if profile {
|
|
26
|
+
totalStarted = time.Now()
|
|
27
|
+
}
|
|
28
|
+
fs := flag.NewFlagSet("build", flag.ContinueOnError)
|
|
29
|
+
fs.SetOutput(stderr)
|
|
30
|
+
tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
|
|
31
|
+
cwdOverride := fs.String("cwd", "", "override the working directory")
|
|
32
|
+
quiet := fs.Bool("quiet", true, "suppress the per-call diagnostic summary")
|
|
33
|
+
verbose := fs.Bool("verbose", false, "print the per-call diagnostic summary")
|
|
34
|
+
emit := fs.Bool("emit", false, "force emitted .js files")
|
|
35
|
+
noEmit := fs.Bool("noEmit", false, "force analysis-only run with no file writes")
|
|
36
|
+
outDir := fs.String("outDir", "", "override compilerOptions.outDir")
|
|
37
|
+
manifestPath := fs.String("manifest", "", "write emitted file list as JSON")
|
|
38
|
+
pluginsJSON := fs.String("plugins-json", "", "ordered ttsc plugin payload")
|
|
39
|
+
if err := fs.Parse(args); err != nil {
|
|
40
|
+
return 2
|
|
41
|
+
}
|
|
42
|
+
if *emit && *noEmit {
|
|
43
|
+
fmt.Fprintln(stderr, "ttsc-nestia build: --emit and --noEmit are mutually exclusive")
|
|
44
|
+
return 2
|
|
45
|
+
}
|
|
46
|
+
if *verbose {
|
|
47
|
+
*quiet = false
|
|
48
|
+
}
|
|
49
|
+
plan, err := plugin.ParsePlan(*pluginsJSON)
|
|
50
|
+
if err != nil {
|
|
51
|
+
fmt.Fprintf(stderr, "ttsc-nestia build: %v\n", err)
|
|
52
|
+
return 2
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
cwd, ok := resolveCWD("ttsc-nestia build", *cwdOverride)
|
|
56
|
+
if !ok {
|
|
57
|
+
return 2
|
|
58
|
+
}
|
|
59
|
+
var started time.Time
|
|
60
|
+
if profile {
|
|
61
|
+
started = time.Now()
|
|
62
|
+
}
|
|
63
|
+
prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
|
|
64
|
+
ForceEmit: *emit,
|
|
65
|
+
ForceNoEmit: *noEmit,
|
|
66
|
+
OutDir: *outDir,
|
|
67
|
+
})
|
|
68
|
+
profileBuildStep(profile, "load-program", started)
|
|
69
|
+
if err != nil {
|
|
70
|
+
fmt.Fprintf(stderr, "ttsc-nestia build: %v\n", err)
|
|
71
|
+
return 2
|
|
72
|
+
}
|
|
73
|
+
if len(diags) > 0 {
|
|
74
|
+
driver.WritePrettyDiagnostics(stderr, diags, cwd)
|
|
75
|
+
return 2
|
|
76
|
+
}
|
|
77
|
+
defer prog.Close()
|
|
78
|
+
if profile {
|
|
79
|
+
started = time.Now()
|
|
80
|
+
}
|
|
81
|
+
if diags := prog.Diagnostics(); len(diags) > 0 {
|
|
82
|
+
profileBuildStep(profile, "diagnostics", started)
|
|
83
|
+
driver.WritePrettyDiagnostics(stderr, diags, cwd)
|
|
84
|
+
return 2
|
|
85
|
+
}
|
|
86
|
+
profileBuildStep(profile, "diagnostics", started)
|
|
87
|
+
|
|
88
|
+
shouldEmit := !prog.ParsedConfig.ParsedConfig.CompilerOptions.NoEmit.IsTrue()
|
|
89
|
+
if !*quiet {
|
|
90
|
+
fmt.Fprintf(
|
|
91
|
+
stdout,
|
|
92
|
+
"// ttsc-nestia build: tsconfig=%s cwd=%s core=%v sdk=%v typia=%v emit=%v\n",
|
|
93
|
+
*tsconfigPath,
|
|
94
|
+
cwd,
|
|
95
|
+
plan.Core,
|
|
96
|
+
plan.SDK,
|
|
97
|
+
plan.Typia,
|
|
98
|
+
shouldEmit,
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
if !shouldEmit {
|
|
102
|
+
return 0
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// AST-integration emit: typia's per-file transformer and @nestia/core's own
|
|
106
|
+
// per-file transformer both run inside tsgo's emit pipeline (sharing the
|
|
107
|
+
// EmitContext), so they return AST and tsgo's module-transform aliases the
|
|
108
|
+
// namespace imports they inject. No text-splice RewriteSet, no cleanup pass.
|
|
109
|
+
transformDiags := []Diagnostic{}
|
|
110
|
+
addDiagnostic := func(diag Diagnostic) {
|
|
111
|
+
transformDiags = append(transformDiags, diag)
|
|
112
|
+
}
|
|
113
|
+
if profile {
|
|
114
|
+
started = time.Now()
|
|
115
|
+
}
|
|
116
|
+
newPathsRewriter(prog).applyAll(prog.SourceFiles())
|
|
117
|
+
profileBuildStep(profile, "paths-rewrite", started)
|
|
118
|
+
|
|
119
|
+
typiaTransform := nestiaTypiaNodeTransform(prog, readTypiaPluginOptions(cwd, *tsconfigPath), addDiagnostic)
|
|
120
|
+
coreTransform := nestiaCoreNodeTransform(prog, plan, addDiagnostic)
|
|
121
|
+
|
|
122
|
+
// Statically linked contributors (e.g. the @nestia/sdk OperationMetadata
|
|
123
|
+
// pass) run their per-file emit transformer in the same EmitContext after
|
|
124
|
+
// typia and core, mirroring the `transform` subcommand. Without this the
|
|
125
|
+
// build/emit path silently drops a contributor that opted in through its own
|
|
126
|
+
// flag (NESTIA_SDK_TRANSFORM) rather than the ttsc linked-plugin registry, so
|
|
127
|
+
// its metadata never reaches the emitted JavaScript.
|
|
128
|
+
contributorTransforms, contributorDiags := collectContributorEmitTransforms(prog, plan)
|
|
129
|
+
if len(contributorDiags) > 0 {
|
|
130
|
+
WriteTypiaTransformDiagnostics(stderr, contributorDiags, cwd)
|
|
131
|
+
return 3
|
|
132
|
+
}
|
|
133
|
+
transforms := append([]driver.PluginTransform{typiaTransform, coreTransform}, contributorTransforms...)
|
|
134
|
+
|
|
135
|
+
emitted := []string{}
|
|
136
|
+
writeFile := shimcompiler.WriteFile(func(fileName, text string, data *shimcompiler.WriteFileData) error {
|
|
137
|
+
_ = data
|
|
138
|
+
emitted = append(emitted, fileName)
|
|
139
|
+
return driver.DefaultWriteFile(fileName, text)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
// Declaration emit: ttsc delegates the whole emit of a transform-plugin
|
|
143
|
+
// package to this host, but EmitWithPluginTransformers writes only .js. A
|
|
144
|
+
// library package (e.g. @nestia/core itself) ships .d.ts, so emit the
|
|
145
|
+
// declarations here with tsgo's standard declaration emitter. The typia /
|
|
146
|
+
// core runtime transforms never change the public type surface, so the
|
|
147
|
+
// declarations are taken from the pristine program — done before the JS
|
|
148
|
+
// transform runs so it reads the un-mutated AST.
|
|
149
|
+
if prog.ParsedConfig.ParsedConfig.CompilerOptions.Declaration.IsTrue() {
|
|
150
|
+
if profile {
|
|
151
|
+
started = time.Now()
|
|
152
|
+
}
|
|
153
|
+
emitDeclarations(prog, writeFile)
|
|
154
|
+
profileBuildStep(profile, "declaration-emit", started)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if profile {
|
|
158
|
+
started = time.Now()
|
|
159
|
+
}
|
|
160
|
+
eDiags, err := prog.EmitWithPluginTransformers(transforms, writeFile)
|
|
161
|
+
profileBuildStep(profile, "emit-total", started)
|
|
162
|
+
if err != nil {
|
|
163
|
+
fmt.Fprintf(stderr, "ttsc-nestia build: emit failed: %v\n", err)
|
|
164
|
+
return 3
|
|
165
|
+
}
|
|
166
|
+
if len(transformDiags) > 0 {
|
|
167
|
+
WriteTypiaTransformDiagnostics(stderr, transformDiags, cwd)
|
|
168
|
+
return 3
|
|
169
|
+
}
|
|
170
|
+
emitHasError := false
|
|
171
|
+
for _, d := range eDiags {
|
|
172
|
+
fmt.Fprintln(stderr, " -", d.String())
|
|
173
|
+
if d.IsError() {
|
|
174
|
+
emitHasError = true
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if emitHasError {
|
|
178
|
+
return 3
|
|
179
|
+
}
|
|
180
|
+
if *manifestPath != "" {
|
|
181
|
+
data, err := json.Marshal(emitted)
|
|
182
|
+
if err != nil {
|
|
183
|
+
fmt.Fprintf(stderr, "ttsc-nestia build: manifest marshal failed: %v\n", err)
|
|
184
|
+
return 3
|
|
185
|
+
}
|
|
186
|
+
if err := os.MkdirAll(filepath.Dir(*manifestPath), 0o755); err != nil {
|
|
187
|
+
fmt.Fprintf(stderr, "ttsc-nestia build: manifest mkdir failed: %v\n", err)
|
|
188
|
+
return 3
|
|
189
|
+
}
|
|
190
|
+
if err := os.WriteFile(*manifestPath, data, 0o644); err != nil {
|
|
191
|
+
fmt.Fprintf(stderr, "ttsc-nestia build: manifest write failed: %v\n", err)
|
|
192
|
+
return 3
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if !*quiet {
|
|
196
|
+
fmt.Fprintf(stdout, "// ttsc-nestia build: emitted=%d files\n", len(emitted))
|
|
197
|
+
}
|
|
198
|
+
profileBuildStep(profile, "total", totalStarted)
|
|
199
|
+
return 0
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// emitDeclarations runs tsgo's standard declaration emitter for the program.
|
|
203
|
+
// tsgo's MarkLinkedReferences pass can nil-panic on some cross-module reference
|
|
204
|
+
// shapes (e.g. a nestia.config.ts that calls NestFactory.create, compiled by the
|
|
205
|
+
// SDK config loader only to be require()d). The .js the caller needs is emitted
|
|
206
|
+
// separately by EmitWithPluginTransformers, so recover and skip the .d.ts for
|
|
207
|
+
// this run instead of aborting the whole build.
|
|
208
|
+
func emitDeclarations(prog *driver.Program, writeFile shimcompiler.WriteFile) {
|
|
209
|
+
defer func() {
|
|
210
|
+
if r := recover(); r != nil {
|
|
211
|
+
fmt.Fprintf(stderr, "ttsc-nestia build: declaration emit skipped (%v)\n", r)
|
|
212
|
+
}
|
|
213
|
+
}()
|
|
214
|
+
dts := prog.TSProgram.Emit(context.Background(), shimcompiler.EmitOptions{
|
|
215
|
+
EmitOnly: shimcompiler.EmitOnlyDts,
|
|
216
|
+
WriteFile: writeFile,
|
|
217
|
+
})
|
|
218
|
+
if dts != nil && dts.EmitSkipped {
|
|
219
|
+
fmt.Fprintln(stderr, "ttsc-nestia build: declaration emit skipped")
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
func runCheck(args []string) int {
|
|
224
|
+
fs := flag.NewFlagSet("check", flag.ContinueOnError)
|
|
225
|
+
fs.SetOutput(stderr)
|
|
226
|
+
tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
|
|
227
|
+
cwdOverride := fs.String("cwd", "", "override the working directory")
|
|
228
|
+
pluginsJSON := fs.String("plugins-json", "", "ordered ttsc plugin payload")
|
|
229
|
+
if err := fs.Parse(args); err != nil {
|
|
230
|
+
return 2
|
|
231
|
+
}
|
|
232
|
+
if _, err := plugin.ParsePlan(*pluginsJSON); err != nil {
|
|
233
|
+
fmt.Fprintf(stderr, "ttsc-nestia check: %v\n", err)
|
|
234
|
+
return 2
|
|
235
|
+
}
|
|
236
|
+
cwd, ok := resolveCWD("ttsc-nestia check", *cwdOverride)
|
|
237
|
+
if !ok {
|
|
238
|
+
return 2
|
|
239
|
+
}
|
|
240
|
+
prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
|
|
241
|
+
ForceNoEmit: true,
|
|
242
|
+
})
|
|
243
|
+
if err != nil {
|
|
244
|
+
fmt.Fprintf(stderr, "ttsc-nestia check: %v\n", err)
|
|
245
|
+
return 2
|
|
246
|
+
}
|
|
247
|
+
if len(diags) > 0 {
|
|
248
|
+
driver.WritePrettyDiagnostics(stderr, diags, cwd)
|
|
249
|
+
return 2
|
|
250
|
+
}
|
|
251
|
+
defer prog.Close()
|
|
252
|
+
if diags := prog.Diagnostics(); len(diags) > 0 {
|
|
253
|
+
driver.WritePrettyDiagnostics(stderr, diags, cwd)
|
|
254
|
+
return 2
|
|
255
|
+
}
|
|
256
|
+
return 0
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
type Diagnostic struct {
|
|
260
|
+
File string
|
|
261
|
+
Line int
|
|
262
|
+
Column int
|
|
263
|
+
Code string
|
|
264
|
+
Message string
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
func (d Diagnostic) String(cwd string) string {
|
|
268
|
+
file := d.File
|
|
269
|
+
if rel, err := filepath.Rel(cwd, file); err == nil {
|
|
270
|
+
file = rel
|
|
271
|
+
}
|
|
272
|
+
if d.Line > 0 {
|
|
273
|
+
return fmt.Sprintf("%s:%d:%d - error TS(%s): %s", file, d.Line, d.Column, d.Code, d.Message)
|
|
274
|
+
}
|
|
275
|
+
return fmt.Sprintf("%s - error TS(%s): %s", file, d.Code, d.Message)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
func WriteTypiaTransformDiagnostics(out io.Writer, diagnostics []Diagnostic, cwd string) {
|
|
279
|
+
for _, diag := range diagnostics {
|
|
280
|
+
fmt.Fprintln(out, diag.String(cwd))
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
func profileBuildStep(enabled bool, name string, started time.Time) {
|
|
285
|
+
if enabled {
|
|
286
|
+
profileBuildDuration(enabled, name, time.Since(started))
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
func profileBuildStepCount(enabled bool, name string, started time.Time, count int) {
|
|
291
|
+
if enabled {
|
|
292
|
+
fmt.Fprintf(stderr, "ttsc-nestia profile: %s=%s count=%d\n", name, time.Since(started), count)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
func profileBuildDuration(enabled bool, name string, elapsed time.Duration) {
|
|
297
|
+
if enabled {
|
|
298
|
+
fmt.Fprintf(stderr, "ttsc-nestia profile: %s=%s\n", name, elapsed)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
func NewDiagnostic(site typiaadapter.CallSite, message string) Diagnostic {
|
|
303
|
+
line, column := 0, 0
|
|
304
|
+
if site.File != nil && site.Call != nil {
|
|
305
|
+
pos := site.Call.AsNode().Pos()
|
|
306
|
+
if pos >= 0 {
|
|
307
|
+
l, c := shimscanner.GetECMALineAndByteOffsetOfPosition(site.File, pos)
|
|
308
|
+
line, column = l+1, c+1
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return Diagnostic{
|
|
312
|
+
File: site.FilePath,
|
|
313
|
+
Line: line,
|
|
314
|
+
Column: column,
|
|
315
|
+
Code: "typia." + site.Module + "." + site.Method,
|
|
316
|
+
Message: message,
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
func typiaBuildRewriteSortKey(site typiaadapter.CallSite) int {
|
|
321
|
+
node := site.Call.AsNode()
|
|
322
|
+
if node == nil {
|
|
323
|
+
return 0
|
|
324
|
+
}
|
|
325
|
+
insideDecorator := false
|
|
326
|
+
classEnd := 0
|
|
327
|
+
for current := node.Parent; current != nil; current = current.Parent {
|
|
328
|
+
if current.Kind == NestiaCoreKindDecorator {
|
|
329
|
+
insideDecorator = true
|
|
330
|
+
}
|
|
331
|
+
if current.Kind == shimast.KindClassDeclaration || current.Kind == shimast.KindClassExpression {
|
|
332
|
+
classEnd = current.End()
|
|
333
|
+
break
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if insideDecorator == false {
|
|
337
|
+
return node.Pos()
|
|
338
|
+
}
|
|
339
|
+
if classEnd != 0 {
|
|
340
|
+
return classEnd + node.Pos()
|
|
341
|
+
}
|
|
342
|
+
return node.Pos() + 1_000_000_000
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
func readTypiaPluginOptions(cwd, tsconfigPath string) typiaadapter.PluginOptions {
|
|
346
|
+
path := tsconfigPath
|
|
347
|
+
if !filepath.IsAbs(path) {
|
|
348
|
+
path = filepath.Join(cwd, path)
|
|
349
|
+
}
|
|
350
|
+
data, err := os.ReadFile(path)
|
|
351
|
+
if err != nil {
|
|
352
|
+
return typiaadapter.PluginOptions{}
|
|
353
|
+
}
|
|
354
|
+
text := string(data)
|
|
355
|
+
return typiaadapter.PluginOptions{
|
|
356
|
+
Functional: typiaOptionFunctionalPattern.MatchString(text),
|
|
357
|
+
Numeric: typiaOptionNumericPattern.MatchString(text),
|
|
358
|
+
Finite: typiaOptionFinitePattern.MatchString(text),
|
|
359
|
+
Undefined: typiaOptionUndefinedPattern.MatchString(text),
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
var (
|
|
364
|
+
typiaOptionFunctionalPattern = regexp.MustCompile(`(?s)"functional"\s*:\s*true`)
|
|
365
|
+
typiaOptionNumericPattern = regexp.MustCompile(`(?s)"numeric"\s*:\s*true`)
|
|
366
|
+
typiaOptionFinitePattern = regexp.MustCompile(`(?s)"finite"\s*:\s*true`)
|
|
367
|
+
typiaOptionUndefinedPattern = regexp.MustCompile(`(?s)"undefined"\s*:\s*true`)
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
func resolveCWD(label string, cwdOverride string) (string, bool) {
|
|
371
|
+
if cwdOverride != "" {
|
|
372
|
+
return cwdOverride, true
|
|
373
|
+
}
|
|
374
|
+
cwd, err := os.Getwd()
|
|
375
|
+
if err != nil {
|
|
376
|
+
fmt.Fprintf(stderr, "%s: cwd: %v\n", label, err)
|
|
377
|
+
return "", false
|
|
378
|
+
}
|
|
379
|
+
return cwd, true
|
|
380
|
+
}
|