@nestia/core 12.0.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/lib/adaptors/McpAdaptor.js +21 -18
  2. package/lib/adaptors/McpAdaptor.js.map +1 -1
  3. package/lib/decorators/EncryptedBody.js +2 -7
  4. package/lib/decorators/EncryptedBody.js.map +1 -1
  5. package/lib/decorators/EncryptedRoute.js +1 -1
  6. package/lib/decorators/EncryptedRoute.js.map +1 -1
  7. package/lib/decorators/McpRoute.js +1 -1
  8. package/lib/decorators/McpRoute.js.map +1 -1
  9. package/lib/decorators/NoTransformConfigurationError.js +2 -2
  10. package/lib/decorators/PlainBody.js +2 -7
  11. package/lib/decorators/PlainBody.js.map +1 -1
  12. package/lib/decorators/SwaggerCustomizer.js +2 -2
  13. package/lib/decorators/SwaggerCustomizer.js.map +1 -1
  14. package/lib/decorators/SwaggerExample.d.ts +37 -40
  15. package/lib/decorators/SwaggerExample.js +24 -26
  16. package/lib/decorators/SwaggerExample.js.map +1 -1
  17. package/lib/decorators/TypedBody.js +3 -7
  18. package/lib/decorators/TypedBody.js.map +1 -1
  19. package/lib/decorators/TypedException.d.ts +1 -1
  20. package/lib/decorators/TypedFormData.js +2 -7
  21. package/lib/decorators/TypedFormData.js.map +1 -1
  22. package/lib/decorators/TypedQuery.js +2 -9
  23. package/lib/decorators/TypedQuery.js.map +1 -1
  24. package/lib/decorators/WebSocketRoute.js +1 -1
  25. package/lib/decorators/WebSocketRoute.js.map +1 -1
  26. package/lib/decorators/internal/get_path_and_querify.js +1 -1
  27. package/lib/decorators/internal/get_path_and_querify.js.map +1 -1
  28. package/lib/decorators/internal/is_media_type.d.ts +1 -0
  29. package/lib/decorators/internal/is_media_type.js +11 -0
  30. package/lib/decorators/internal/is_media_type.js.map +1 -0
  31. package/lib/decorators/internal/validate_request_query.js.map +1 -1
  32. package/native/plugin/plan.go +17 -0
  33. package/native/transform/build.go +39 -80
  34. package/native/transform/contributor.go +4 -64
  35. package/native/transform/core_transform.go +42 -705
  36. package/native/transform/node_transform.go +3 -5
  37. package/native/transform/printer.go +0 -217
  38. package/native/transform/transform.go +2 -91
  39. package/native/transform/typia_fast.go +0 -320
  40. package/package.json +8 -8
  41. package/src/adaptors/McpAdaptor.ts +29 -21
  42. package/src/decorators/EncryptedBody.ts +2 -9
  43. package/src/decorators/EncryptedRoute.ts +1 -1
  44. package/src/decorators/McpRoute.ts +6 -5
  45. package/src/decorators/NoTransformConfigurationError.ts +2 -2
  46. package/src/decorators/PlainBody.ts +2 -9
  47. package/src/decorators/SwaggerCustomizer.ts +8 -2
  48. package/src/decorators/SwaggerExample.ts +43 -45
  49. package/src/decorators/TypedBody.ts +5 -9
  50. package/src/decorators/TypedException.ts +1 -1
  51. package/src/decorators/TypedFormData.ts +7 -9
  52. package/src/decorators/TypedQuery.ts +7 -12
  53. package/src/decorators/WebSocketRoute.ts +1 -1
  54. package/src/decorators/internal/get_path_and_querify.ts +1 -1
  55. package/src/decorators/internal/is_media_type.ts +10 -0
  56. package/src/decorators/internal/validate_request_query.ts +2 -1
  57. package/native/transform/cleanup.go +0 -408
  58. package/native/transform/exports.go +0 -13
  59. package/native/transform/rewrite.go +0 -668
  60. package/native/transform/typia_replacement.go +0 -24
@@ -1,668 +0,0 @@
1
- package transform
2
-
3
- import (
4
- "fmt"
5
- "path/filepath"
6
- "sort"
7
- "strings"
8
- "unicode"
9
- )
10
-
11
- type nativeRewrite struct {
12
- FilePath string
13
- RootName string
14
- Namespaces []string
15
- Method string
16
- Replacement string
17
- ConsumeParens bool
18
- AppendArguments []string
19
- ReplaceArguments bool
20
- TargetExpressionCandidates []string
21
- SourceStart int
22
- ExpectedArgumentCount *int
23
- ExpectedArgumentsText string
24
- }
25
-
26
- type nativeRewriteSet struct {
27
- byPath map[string][]nativeRewrite
28
- aliasesByPath map[string]map[string]bool
29
- sortedAliasesByPath map[string][]string
30
- }
31
-
32
- func newNativeRewriteSet() *nativeRewriteSet {
33
- return &nativeRewriteSet{
34
- byPath: map[string][]nativeRewrite{},
35
- aliasesByPath: map[string]map[string]bool{},
36
- sortedAliasesByPath: map[string][]string{},
37
- }
38
- }
39
-
40
- func (rs *nativeRewriteSet) Add(r nativeRewrite) {
41
- if r.FilePath == "" {
42
- return
43
- }
44
- path := filepath.ToSlash(r.FilePath)
45
- rs.byPath[path] = append(rs.byPath[path], r)
46
- rs.addRuntimeAliases(path, r.Replacement)
47
- for _, argument := range r.AppendArguments {
48
- rs.addRuntimeAliases(path, argument)
49
- }
50
- }
51
-
52
- func (rs *nativeRewriteSet) addRuntimeAliases(path string, text string) {
53
- for _, alias := range collectCleanupRuntimeAliases(text) {
54
- if rs.aliasesByPath[path] == nil {
55
- rs.aliasesByPath[path] = map[string]bool{}
56
- }
57
- rs.aliasesByPath[path][alias] = true
58
- delete(rs.sortedAliasesByPath, path)
59
- }
60
- }
61
-
62
- func (rs *nativeRewriteSet) Len() int {
63
- if rs == nil {
64
- return 0
65
- }
66
- n := 0
67
- for _, rewrites := range rs.byPath {
68
- n += len(rewrites)
69
- }
70
- return n
71
- }
72
-
73
- func (rs *nativeRewriteSet) Apply(outputName string, text string, cursors map[string]int) (string, error) {
74
- if rs == nil || len(rs.byPath) == 0 {
75
- return text, nil
76
- }
77
- if strings.Contains(text, "/* @ttsc-rewritten */") {
78
- return text, nil
79
- }
80
- srcPath, ok := rs.findSourceForOutput(outputName)
81
- if !ok || len(rs.byPath[srcPath]) == 0 {
82
- return text, nil
83
- }
84
- rewrites := rs.byPath[srcPath]
85
- sort.SliceStable(rewrites, func(i, j int) bool {
86
- left, leftOK := nativeRewriteFirstIndex(text, rewrites[i])
87
- right, rightOK := nativeRewriteFirstIndex(text, rewrites[j])
88
- if leftOK && rightOK && left != right {
89
- return left < right
90
- }
91
- if leftOK != rightOK {
92
- return leftOK
93
- }
94
- return rewrites[i].SourceStart < rewrites[j].SourceStart
95
- })
96
- pos := cursors[srcPath]
97
- out := text
98
- for pos < len(rewrites) {
99
- rewrite := rewrites[pos]
100
- replaced, ok, err := spliceNativeCall(out, rewrite)
101
- if err != nil {
102
- return "", err
103
- }
104
- if !ok {
105
- preview := out
106
- if len(preview) > 400 {
107
- preview = preview[:400] + "..."
108
- }
109
- return "", fmt.Errorf(
110
- "native rewrite: could not locate %s.%s(...) call in %s (tried roots %v; preview: %q)",
111
- joinNativeRootAndNamespaces(rewrite),
112
- rewrite.Method,
113
- outputName,
114
- candidateNativeRoots(rewrite.RootName),
115
- preview,
116
- )
117
- }
118
- out = replaced
119
- pos++
120
- }
121
- cursors[srcPath] = pos
122
- if out != text {
123
- out = insertNativeRewriteSentinel(out)
124
- }
125
- return out, nil
126
- }
127
-
128
- func (rs *nativeRewriteSet) RuntimeAliasesForOutput(outputName string) []string {
129
- if rs == nil || len(rs.aliasesByPath) == 0 || isJavaScriptOutput(outputName) == false {
130
- return nil
131
- }
132
- srcPath, ok := rs.findSourceForOutput(outputName)
133
- if !ok {
134
- return nil
135
- }
136
- if aliases, ok := rs.sortedAliasesByPath[srcPath]; ok {
137
- return aliases
138
- }
139
- seen := rs.aliasesByPath[srcPath]
140
- if len(seen) == 0 {
141
- rs.sortedAliasesByPath[srcPath] = []string{}
142
- return rs.sortedAliasesByPath[srcPath]
143
- }
144
- aliases := sortCleanupRuntimeAliases(seen)
145
- rs.sortedAliasesByPath[srcPath] = aliases
146
- return aliases
147
- }
148
-
149
- func nativeRewriteFirstIndex(text string, rewrite nativeRewrite) (int, bool) {
150
- best := -1
151
- for _, target := range candidateNativeTargets(rewrite) {
152
- hit, ok := indexNativeFlexibleCall(text, target, rewrite, 0)
153
- if ok == false {
154
- continue
155
- }
156
- if best < 0 || hit.start < best {
157
- best = hit.start
158
- }
159
- }
160
- return best, best >= 0
161
- }
162
-
163
- func (rs *nativeRewriteSet) findSourceForOutput(outputName string) (string, bool) {
164
- outSlash := strings.TrimSuffix(filepath.ToSlash(outputName), filepath.Ext(outputName))
165
- for path := range rs.byPath {
166
- srcStem := strings.TrimSuffix(filepath.ToSlash(path), filepath.Ext(path))
167
- if OutputMatchesSourceStem(outSlash, srcStem) {
168
- return path, true
169
- }
170
- }
171
- return rs.findSourceByUniqueBase(outSlash)
172
- }
173
-
174
- func (rs *nativeRewriteSet) findSourceByUniqueBase(outputStem string) (string, bool) {
175
- // Only fall back to basename matching when the output looks like an actual
176
- // build product (sits inside lib/dist/bin/build). If the output lives in
177
- // the source tree (e.g. ttsc's virtual filesystem mirroring src/), basename
178
- // matching crosses unrelated files — `src/index.ts` would silently absorb
179
- // the rewrite intended for every `src/.../index.ts` sibling.
180
- if outputHasBuildMarker(outputStem) == false {
181
- return "", false
182
- }
183
- base := pathBase(outputStem)
184
- if base == "" {
185
- return "", false
186
- }
187
- matched := ""
188
- count := 0
189
- for path := range rs.byPath {
190
- srcStem := strings.TrimSuffix(filepath.ToSlash(path), filepath.Ext(path))
191
- if pathBase(srcStem) != base {
192
- continue
193
- }
194
- matched = path
195
- count++
196
- if count > 1 {
197
- return "", false
198
- }
199
- }
200
- return matched, count == 1
201
- }
202
-
203
- func outputHasBuildMarker(stem string) bool {
204
- for _, marker := range []string{"lib", "dist", "bin", "build"} {
205
- if _, ok := suffixAfterPathMarker(stem, []string{marker}, false); ok {
206
- return true
207
- }
208
- }
209
- return false
210
- }
211
-
212
- func OutputMatchesSourceStem(outputStem string, sourceStem string) bool {
213
- if outputStem == sourceStem {
214
- return true
215
- }
216
- for _, sourceRel := range sourceOutputCandidates(sourceStem) {
217
- for _, outputRel := range outputSourceCandidates(outputStem) {
218
- if sourceRel == outputRel {
219
- return true
220
- }
221
- }
222
- // Suffix-only matching is a fallback for paths that don't share a
223
- // recognized build marker (e.g. ttsc's virtual filesystem mirroring
224
- // the source tree). Require the relative path to span at least two
225
- // segments so a top-level source like `src/index.ts` does not match
226
- // every output file that happens to end in `/index.js`.
227
- if strings.Contains(sourceRel, "/") && strings.HasSuffix(outputStem, "/"+sourceRel) {
228
- return true
229
- }
230
- }
231
- return false
232
- }
233
-
234
- func pathBase(stem string) string {
235
- stem = strings.TrimSuffix(filepath.ToSlash(stem), "/")
236
- if stem == "" {
237
- return ""
238
- }
239
- if idx := strings.LastIndexByte(stem, '/'); idx >= 0 {
240
- return stem[idx+1:]
241
- }
242
- return stem
243
- }
244
-
245
- func isJavaScriptOutput(fileName string) bool {
246
- switch strings.ToLower(filepath.Ext(fileName)) {
247
- case ".js", ".mjs", ".cjs":
248
- return true
249
- default:
250
- return false
251
- }
252
- }
253
-
254
- func sourceOutputCandidates(stem string) []string {
255
- candidates := []string{}
256
- if rel, ok := suffixAfterPathMarker(stem, []string{"src", "api"}, false); ok {
257
- candidates = append(candidates, rel)
258
- }
259
- if rel, ok := suffixAfterPathMarker(stem, []string{"src"}, false); ok {
260
- candidates = append(candidates, rel)
261
- }
262
- if rel, ok := suffixAfterPathMarker(stem, []string{"test"}, true); ok {
263
- candidates = append(candidates, rel)
264
- }
265
- return candidates
266
- }
267
-
268
- func outputSourceCandidates(stem string) []string {
269
- candidates := []string{}
270
- // Mirror sourceOutputCandidates so paths whose source and output trees
271
- // share the same `src/` (or `test/`) root — e.g. ttsc's virtual filesystem
272
- // emits next to the source — can intersect on the same relative tail.
273
- // We intentionally do NOT include the {"src","api"} marker here: that
274
- // marker exists on the source side to let a source under `src/api/`
275
- // pretend its rel is the leaf only (so it matches an output that lacks
276
- // the `api/` segment); mirroring it on the output side would let two
277
- // unrelated files (e.g. `src/index.ts` and `src/api/index.ts`) collide
278
- // on the rel "index".
279
- for _, marker := range [][]string{{"lib"}, {"bin"}, {"dist"}, {"build"}, {"src"}} {
280
- if rel, ok := suffixAfterPathMarker(stem, marker, false); ok {
281
- candidates = append(candidates, rel)
282
- }
283
- }
284
- if rel, ok := suffixAfterPathMarker(stem, []string{"test"}, true); ok {
285
- candidates = append(candidates, rel)
286
- }
287
- return append(candidates, stem)
288
- }
289
-
290
- func suffixAfterPathMarker(stem string, marker []string, includeMarker bool) (string, bool) {
291
- segments := strings.Split(filepath.ToSlash(stem), "/")
292
- for i := len(segments) - len(marker); i >= 0; i-- {
293
- matched := true
294
- for j := range marker {
295
- if segments[i+j] != marker[j] {
296
- matched = false
297
- break
298
- }
299
- }
300
- if !matched {
301
- continue
302
- }
303
- start := i + len(marker)
304
- if includeMarker {
305
- start = i
306
- }
307
- if start >= len(segments) {
308
- return "", false
309
- }
310
- return strings.Join(segments[start:], "/"), true
311
- }
312
- return "", false
313
- }
314
-
315
- func spliceNativeCall(text string, r nativeRewrite) (string, bool, error) {
316
- for _, target := range candidateNativeTargets(r) {
317
- searchFrom := 0
318
- for {
319
- hit, ok := indexNativeFlexibleCall(text, target, r, searchFrom)
320
- if !ok {
321
- break
322
- }
323
- closePos, ok := matchNativeParen(text, hit.paren)
324
- if !ok {
325
- searchFrom = advanceNativeSearch(searchFrom, hit)
326
- continue
327
- }
328
- if r.ExpectedArgumentCount != nil &&
329
- countNativeArguments(text[hit.paren+1:closePos]) != *r.ExpectedArgumentCount {
330
- searchFrom = advanceNativeSearch(searchFrom, hit)
331
- continue
332
- }
333
- current := strings.TrimSpace(text[hit.paren+1 : closePos])
334
- if r.ExpectedArgumentsText != "" && compactNativeArgumentText(current) != compactNativeArgumentText(r.ExpectedArgumentsText) {
335
- searchFrom = advanceNativeSearch(searchFrom, hit)
336
- continue
337
- }
338
- if r.ReplaceArguments {
339
- next := strings.Join(r.AppendArguments, ", ")
340
- replaced := text[:hit.paren+1] + next + text[closePos:]
341
- return replaced, true, nil
342
- }
343
- if len(r.AppendArguments) != 0 {
344
- next := strings.Join(r.AppendArguments, ", ")
345
- if current != "" {
346
- next = current + ", " + next
347
- }
348
- replaced := text[:hit.paren+1] + next + text[closePos:]
349
- return replaced, true, nil
350
- }
351
- if r.ConsumeParens {
352
- replaced := text[:hit.start] + r.Replacement + text[closePos+1:]
353
- return replaced, true, nil
354
- }
355
- replaced := text[:hit.start] + r.Replacement + text[hit.paren:]
356
- return replaced, true, nil
357
- }
358
- }
359
- return text, false, nil
360
- }
361
-
362
- func advanceNativeSearch(current int, hit nativeCallHit) int {
363
- next := hit.paren + 1
364
- if next <= current {
365
- return current + 1
366
- }
367
- return next
368
- }
369
-
370
- func compactNativeArgumentText(text string) string {
371
- var builder strings.Builder
372
- inString := byte(0)
373
- escaped := false
374
- for i := 0; i < len(text); i++ {
375
- ch := text[i]
376
- if inString != 0 {
377
- builder.WriteByte(ch)
378
- if escaped {
379
- escaped = false
380
- } else if ch == '\\' {
381
- escaped = true
382
- } else if ch == inString {
383
- inString = 0
384
- }
385
- continue
386
- }
387
- switch ch {
388
- case '"', '\'', '`':
389
- inString = ch
390
- builder.WriteByte(ch)
391
- case ' ', '\t', '\r', '\n':
392
- continue
393
- default:
394
- builder.WriteByte(ch)
395
- }
396
- }
397
- return builder.String()
398
- }
399
-
400
- type nativeCallHit struct {
401
- start int
402
- paren int
403
- }
404
-
405
- func indexNativeFlexibleCall(text string, target string, r nativeRewrite, searchFrom int) (nativeCallHit, bool) {
406
- parts := strings.Split(target, ".")
407
- if len(parts) == 0 || parts[0] == "" {
408
- return nativeCallHit{}, false
409
- }
410
- root := parts[0]
411
- parts = parts[1:]
412
- start := searchFrom
413
- if start < 0 {
414
- start = 0
415
- }
416
- for {
417
- hit := strings.Index(text[start:], root)
418
- if hit < 0 {
419
- return nativeCallHit{}, false
420
- }
421
- pos := start + hit
422
- if pos > 0 && isNativeIdentifierPart(rune(text[pos-1])) {
423
- start = pos + 1
424
- continue
425
- }
426
- cursor := pos + len(root)
427
- ok := true
428
- for _, part := range parts {
429
- cursor = skipNativeWhitespace(text, cursor)
430
- if cursor >= len(text) || text[cursor] != '.' {
431
- ok = false
432
- break
433
- }
434
- cursor++
435
- cursor = skipNativeWhitespace(text, cursor)
436
- if !strings.HasPrefix(text[cursor:], part) {
437
- ok = false
438
- break
439
- }
440
- cursor += len(part)
441
- }
442
- cursor = skipNativeWhitespace(text, cursor)
443
- if ok && cursor < len(text) && text[cursor] == '(' {
444
- return nativeCallHit{start: pos, paren: cursor}, true
445
- }
446
- if ok {
447
- if wrappedStart, paren, wrapped := matchNativeCommaWrappedCall(text, pos, cursor); wrapped {
448
- return nativeCallHit{start: wrappedStart, paren: paren}, true
449
- }
450
- }
451
- start = pos + 1
452
- }
453
- }
454
-
455
- func skipNativeWhitespace(text string, pos int) int {
456
- for pos < len(text) {
457
- switch text[pos] {
458
- case ' ', '\t', '\r', '\n':
459
- pos++
460
- default:
461
- return pos
462
- }
463
- }
464
- return pos
465
- }
466
-
467
- func countNativeArguments(text string) int {
468
- text = strings.TrimSpace(text)
469
- if text == "" {
470
- return 0
471
- }
472
- count := 1
473
- depth := 0
474
- // templateDepths records the bracket depth at which each currently-open
475
- // `${...}` substitution started. When depth drops back to that level on a
476
- // '}' token, we pop and re-enter template-string mode.
477
- templateDepths := []int{}
478
- i := 0
479
- for i < len(text) {
480
- ch := text[i]
481
- switch ch {
482
- case '(', '[', '{':
483
- depth++
484
- case ')', ']':
485
- if depth > 0 {
486
- depth--
487
- }
488
- case '}':
489
- if depth > 0 {
490
- depth--
491
- }
492
- if n := len(templateDepths); n > 0 && templateDepths[n-1] == depth {
493
- templateDepths = templateDepths[:n-1]
494
- i++
495
- skipTemplateLiteral(text, &i, &templateDepths, &depth)
496
- continue
497
- }
498
- case '"', '\'':
499
- i++
500
- for i < len(text) && text[i] != ch {
501
- if text[i] == '\\' && i+1 < len(text) {
502
- i++
503
- }
504
- i++
505
- }
506
- case '`':
507
- i++
508
- skipTemplateLiteral(text, &i, &templateDepths, &depth)
509
- continue
510
- case ',':
511
- if depth == 0 {
512
- count++
513
- }
514
- }
515
- i++
516
- }
517
- return count
518
- }
519
-
520
- // skipTemplateLiteral advances i through a template-literal body. It exits
521
- // either at the matching closing backtick (consuming it) or at the opening
522
- // of a `${...}` substitution, in which case the caller resumes regular
523
- // expression parsing and templateDepths records that we owe a return to
524
- // template-string mode on the matching '}'.
525
- func skipTemplateLiteral(text string, i *int, templateDepths *[]int, depth *int) {
526
- for *i < len(text) {
527
- c := text[*i]
528
- if c == '\\' && *i+1 < len(text) {
529
- *i += 2
530
- continue
531
- }
532
- if c == '`' {
533
- *i++
534
- return
535
- }
536
- if c == '$' && *i+1 < len(text) && text[*i+1] == '{' {
537
- *templateDepths = append(*templateDepths, *depth)
538
- *depth++
539
- *i += 2
540
- return
541
- }
542
- *i++
543
- }
544
- }
545
-
546
- func candidateNativeRoots(root string) []string {
547
- return []string{
548
- root,
549
- root + "_1.default",
550
- root + "_2.default",
551
- root + ".default",
552
- root + "_1",
553
- root + "_2",
554
- }
555
- }
556
-
557
- func candidateNativeTargets(r nativeRewrite) []string {
558
- seen := map[string]bool{}
559
- output := []string{}
560
- add := func(value string) {
561
- value = strings.TrimSpace(value)
562
- if value == "" || seen[value] {
563
- return
564
- }
565
- seen[value] = true
566
- output = append(output, value)
567
- }
568
- for _, candidate := range r.TargetExpressionCandidates {
569
- add(candidate)
570
- }
571
- if r.Method == "" && len(r.Namespaces) == 0 {
572
- for _, root := range candidateNativeRoots(r.RootName) {
573
- add(root)
574
- }
575
- return output
576
- }
577
- for _, root := range candidateNativeRoots(r.RootName) {
578
- parts := []string{root}
579
- parts = append(parts, r.Namespaces...)
580
- if r.Method != "" {
581
- parts = append(parts, r.Method)
582
- }
583
- add(strings.Join(parts, "."))
584
- }
585
- return output
586
- }
587
-
588
- func matchNativeCommaWrappedCall(text string, exprStart int, exprEnd int) (int, int, bool) {
589
- left := exprStart - 1
590
- for left >= 0 && (text[left] == ' ' || text[left] == '\t' || text[left] == '\r' || text[left] == '\n') {
591
- left--
592
- }
593
- if left < 0 || text[left] != ',' {
594
- return 0, 0, false
595
- }
596
- left--
597
- for left >= 0 && (text[left] == ' ' || text[left] == '\t' || text[left] == '\r' || text[left] == '\n') {
598
- left--
599
- }
600
- if left < 0 || text[left] != '0' {
601
- return 0, 0, false
602
- }
603
- left--
604
- for left >= 0 && (text[left] == ' ' || text[left] == '\t' || text[left] == '\r' || text[left] == '\n') {
605
- left--
606
- }
607
- if left < 0 || text[left] != '(' {
608
- return 0, 0, false
609
- }
610
- right := skipNativeWhitespace(text, exprEnd)
611
- if right >= len(text) || text[right] != ')' {
612
- return 0, 0, false
613
- }
614
- paren := skipNativeWhitespace(text, right+1)
615
- if paren >= len(text) || text[paren] != '(' {
616
- return 0, 0, false
617
- }
618
- return left, paren, true
619
- }
620
-
621
- func joinNativeRootAndNamespaces(r nativeRewrite) string {
622
- if len(r.Namespaces) == 0 {
623
- return r.RootName
624
- }
625
- return r.RootName + "." + strings.Join(r.Namespaces, ".")
626
- }
627
-
628
- func matchNativeParen(text string, pos int) (int, bool) {
629
- if pos >= len(text) || text[pos] != '(' {
630
- return 0, false
631
- }
632
- depth := 1
633
- for i := pos + 1; i < len(text); i++ {
634
- switch text[i] {
635
- case '(':
636
- depth++
637
- case ')':
638
- depth--
639
- if depth == 0 {
640
- return i, true
641
- }
642
- case '"', '\'', '`':
643
- q := text[i]
644
- j := i + 1
645
- for j < len(text) && text[j] != q {
646
- if text[j] == '\\' {
647
- j++
648
- }
649
- j++
650
- }
651
- i = j
652
- }
653
- }
654
- return 0, false
655
- }
656
-
657
- func isNativeIdentifierPart(r rune) bool {
658
- return r == '_' || r == '$' || unicode.IsLetter(r) || unicode.IsDigit(r)
659
- }
660
-
661
- func insertNativeRewriteSentinel(text string) string {
662
- for _, prefix := range []string{"\"use strict\";\n", "'use strict';\n"} {
663
- if strings.HasPrefix(text, prefix) {
664
- return prefix + "/* @ttsc-rewritten */\n" + text[len(prefix):]
665
- }
666
- }
667
- return "/* @ttsc-rewritten */\n" + text
668
- }
@@ -1,24 +0,0 @@
1
- package transform
2
-
3
- import (
4
- "strings"
5
-
6
- shimast "github.com/microsoft/typescript-go/shim/ast"
7
- typiaadapter "github.com/samchon/typia/packages/typia/native/adapter"
8
- )
9
-
10
- func parenthesizeTypiaReplacement(
11
- site typiaadapter.CallSite,
12
- expr string,
13
- ) string {
14
- text := strings.TrimSpace(expr)
15
- if strings.HasPrefix(text, "{") == false {
16
- return expr
17
- }
18
- node := site.Call.AsNode()
19
- if node == nil || node.Parent == nil ||
20
- node.Parent.Kind != shimast.KindExpressionStatement {
21
- return expr
22
- }
23
- return "(" + expr + ")"
24
- }