@zyno-io/ts-reflection 26.803.2224

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 (61) hide show
  1. package/README.md +13 -0
  2. package/dist/index.cjs +1 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +966 -0
  6. package/dist/reflection/annotations.d.ts +15 -0
  7. package/dist/reflection/annotations.d.ts.map +1 -0
  8. package/dist/reflection/compact-metadata.d.ts +18 -0
  9. package/dist/reflection/compact-metadata.d.ts.map +1 -0
  10. package/dist/reflection/conversion.d.ts +15 -0
  11. package/dist/reflection/conversion.d.ts.map +1 -0
  12. package/dist/reflection/deserializer.d.ts +15 -0
  13. package/dist/reflection/deserializer.d.ts.map +1 -0
  14. package/dist/reflection/errors.d.ts +8 -0
  15. package/dist/reflection/errors.d.ts.map +1 -0
  16. package/dist/reflection/index.d.ts +10 -0
  17. package/dist/reflection/index.d.ts.map +1 -0
  18. package/dist/reflection/metadata-store.d.ts +20 -0
  19. package/dist/reflection/metadata-store.d.ts.map +1 -0
  20. package/dist/reflection/model.d.ts +273 -0
  21. package/dist/reflection/model.d.ts.map +1 -0
  22. package/dist/reflection/primitive-conversion.d.ts +2 -0
  23. package/dist/reflection/primitive-conversion.d.ts.map +1 -0
  24. package/dist/reflection/reflection-class.d.ts +60 -0
  25. package/dist/reflection/reflection-class.d.ts.map +1 -0
  26. package/dist/reflection/type-utils.d.ts +34 -0
  27. package/dist/reflection/type-utils.d.ts.map +1 -0
  28. package/dist/type-compiler/download-prebuilt.cjs +114 -0
  29. package/dist/type-compiler/go/ast_expression.go +187 -0
  30. package/dist/type-compiler/go/ast_metadata.go +388 -0
  31. package/dist/type-compiler/go/collect.go +963 -0
  32. package/dist/type-compiler/go/compact_metadata.go +553 -0
  33. package/dist/type-compiler/go/emission_plan.go +340 -0
  34. package/dist/type-compiler/go/emit_ast.go +557 -0
  35. package/dist/type-compiler/go/emit_ast_test.go +558 -0
  36. package/dist/type-compiler/go/go.mod +10 -0
  37. package/dist/type-compiler/go/plugin.go +359 -0
  38. package/dist/type-compiler/go/plugin_test.go +1206 -0
  39. package/dist/type-compiler/go/precompute.go +86 -0
  40. package/dist/type-compiler/go/receive_type.go +912 -0
  41. package/dist/type-compiler/go/resolve.go +265 -0
  42. package/dist/type-compiler/go/source_scan.go +51 -0
  43. package/dist/type-compiler/go/text_parse.go +734 -0
  44. package/dist/type-compiler/go/type_expr.go +1291 -0
  45. package/dist/type-compiler/go/typia_expr.go +2316 -0
  46. package/dist/type-compiler/index.cjs +43 -0
  47. package/dist/type-compiler/pnp.cjs +474 -0
  48. package/dist/type-compiler/prebuilt.cjs +324 -0
  49. package/dist/type-metadata-runtime.cjs +1 -0
  50. package/dist/type-metadata-runtime.d.ts +2 -0
  51. package/dist/type-metadata-runtime.d.ts.map +1 -0
  52. package/dist/type-metadata-runtime.js +107 -0
  53. package/dist/types/index.d.ts +4 -0
  54. package/dist/types/index.d.ts.map +1 -0
  55. package/dist/types/primitives.d.ts +33 -0
  56. package/dist/types/primitives.d.ts.map +1 -0
  57. package/dist/types/runtime.d.ts +2 -0
  58. package/dist/types/runtime.d.ts.map +1 -0
  59. package/dist/types/type-annotations.d.ts +28 -0
  60. package/dist/types/type-annotations.d.ts.map +1 -0
  61. package/package.json +47 -0
@@ -0,0 +1,734 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "regexp"
6
+ "strconv"
7
+ "strings"
8
+ )
9
+
10
+ func plainValue(raw string) string {
11
+ raw = strings.TrimSpace(raw)
12
+ if raw == "" {
13
+ return "{}"
14
+ }
15
+ raw = trimParens(raw)
16
+ if isObjectLiteralTypeText(raw) {
17
+ inner := strings.TrimSpace(raw[1 : len(raw)-1])
18
+ fields := splitTop(inner, ";")
19
+ if len(fields) == 1 {
20
+ fields = splitTop(inner, ",")
21
+ }
22
+ props := []string{}
23
+ for _, field := range fields {
24
+ field = strings.TrimSpace(field)
25
+ if field == "" {
26
+ continue
27
+ }
28
+ name, value, ok := strings.Cut(field, ":")
29
+ if !ok {
30
+ continue
31
+ }
32
+ props = append(props, strings.TrimSpace(name)+": "+plainValue(value))
33
+ }
34
+ return "{" + strings.Join(props, ", ") + "}"
35
+ }
36
+ if strings.HasPrefix(raw, "\"") || strings.HasPrefix(raw, "'") {
37
+ return normalizeStringLiteral(raw)
38
+ }
39
+ if raw == "true" || raw == "false" || raw == "null" || raw == "undefined" {
40
+ return raw
41
+ }
42
+ if _, err := strconv.ParseFloat(raw, 64); err == nil {
43
+ return raw
44
+ }
45
+ return typeExpr(&fileInfo{aliases: map[string]aliasInfo{}, imports: map[string]importRef{}}, &registry{byPath: map[string]*fileInfo{}}, raw)
46
+ }
47
+
48
+ func literalArg(raw string) string {
49
+ raw = strings.TrimSpace(raw)
50
+ if strings.HasPrefix(raw, "\"") || strings.HasPrefix(raw, "'") {
51
+ return "{kind: 10, literal: " + normalizeStringLiteral(raw) + "}"
52
+ }
53
+ return "{kind: 10, literal: " + raw + "}"
54
+ }
55
+
56
+ func splitTop(input string, sep string) []string {
57
+ input = stripTypeComments(input)
58
+ parts := []string{}
59
+ start, depthAngle, depthBrace, depthParen, depthBracket, quote := 0, 0, 0, 0, 0, byte(0)
60
+ for i := 0; i < len(input); i++ {
61
+ c := input[i]
62
+ if quote != 0 {
63
+ if c == '\\' {
64
+ i++
65
+ continue
66
+ }
67
+ if c == quote {
68
+ quote = 0
69
+ }
70
+ continue
71
+ }
72
+ switch c {
73
+ case '\'', '"':
74
+ quote = c
75
+ case '`':
76
+ i = skipTemplateLiteral(input, i)
77
+ case '<':
78
+ depthAngle++
79
+ case '>':
80
+ if depthAngle > 0 {
81
+ depthAngle--
82
+ }
83
+ case '{':
84
+ depthBrace++
85
+ case '}':
86
+ if depthBrace > 0 {
87
+ depthBrace--
88
+ }
89
+ case '(':
90
+ depthParen++
91
+ case ')':
92
+ if depthParen > 0 {
93
+ depthParen--
94
+ }
95
+ case '[':
96
+ depthBracket++
97
+ case ']':
98
+ if depthBracket > 0 {
99
+ depthBracket--
100
+ }
101
+ default:
102
+ if strings.HasPrefix(input[i:], sep) && depthAngle == 0 && depthBrace == 0 && depthParen == 0 && depthBracket == 0 {
103
+ parts = append(parts, strings.TrimSpace(input[start:i]))
104
+ start = i + len(sep)
105
+ i += len(sep) - 1
106
+ }
107
+ }
108
+ }
109
+ parts = append(parts, strings.TrimSpace(input[start:]))
110
+ return parts
111
+ }
112
+
113
+ func nonEmptyParts(parts []string) []string {
114
+ out := make([]string, 0, len(parts))
115
+ for _, part := range parts {
116
+ part = strings.TrimSpace(part)
117
+ if part != "" {
118
+ out = append(out, part)
119
+ }
120
+ }
121
+ return out
122
+ }
123
+
124
+ func skipTemplateLiteral(text string, start int) int {
125
+ for i := start + 1; i < len(text); i++ {
126
+ c := text[i]
127
+ next := byte(0)
128
+ if i+1 < len(text) {
129
+ next = text[i+1]
130
+ }
131
+ if c == '\\' {
132
+ i++
133
+ continue
134
+ }
135
+ if c == '`' {
136
+ return i
137
+ }
138
+ if c == '$' && next == '{' {
139
+ end := findTemplateExpressionEnd(text, i+2)
140
+ if end < 0 {
141
+ return len(text) - 1
142
+ }
143
+ i = end
144
+ }
145
+ }
146
+ return len(text) - 1
147
+ }
148
+
149
+ func findTemplateExpressionEnd(text string, start int) int {
150
+ depth := 1
151
+ quote := byte(0)
152
+ lineComment := false
153
+ blockComment := false
154
+ for i := start; i < len(text); i++ {
155
+ c := text[i]
156
+ next := byte(0)
157
+ if i+1 < len(text) {
158
+ next = text[i+1]
159
+ }
160
+ if lineComment {
161
+ if c == '\n' || c == '\r' {
162
+ lineComment = false
163
+ }
164
+ continue
165
+ }
166
+ if blockComment {
167
+ if c == '*' && next == '/' {
168
+ blockComment = false
169
+ i++
170
+ }
171
+ continue
172
+ }
173
+ if quote != 0 {
174
+ if c == '\\' {
175
+ i++
176
+ continue
177
+ }
178
+ if c == quote {
179
+ quote = 0
180
+ }
181
+ continue
182
+ }
183
+ if c == '/' && next == '/' {
184
+ lineComment = true
185
+ i++
186
+ continue
187
+ }
188
+ if c == '/' && next == '*' {
189
+ blockComment = true
190
+ i++
191
+ continue
192
+ }
193
+ if c == '\'' || c == '"' {
194
+ quote = c
195
+ continue
196
+ }
197
+ if c == '`' {
198
+ i = skipTemplateLiteral(text, i)
199
+ continue
200
+ }
201
+ if c == '{' {
202
+ depth++
203
+ } else if c == '}' {
204
+ depth--
205
+ if depth == 0 {
206
+ return i
207
+ }
208
+ }
209
+ }
210
+ return -1
211
+ }
212
+
213
+ func generic(raw string) (string, []string, bool) {
214
+ raw = strings.TrimSpace(raw)
215
+ idx := strings.Index(raw, "<")
216
+ if idx < 0 || !strings.HasSuffix(raw, ">") {
217
+ return raw, nil, false
218
+ }
219
+ name := strings.TrimSpace(raw[:idx])
220
+ args := splitTop(raw[idx+1:len(raw)-1], ",")
221
+ return name, args, true
222
+ }
223
+
224
+ func splitInterfaceFields(body string) []string {
225
+ body = stripTypeComments(body)
226
+ body = strings.ReplaceAll(body, "\r\n", "\n")
227
+ body = strings.ReplaceAll(body, "\r", "\n")
228
+ parts := []string{}
229
+ start, depthAngle, depthBrace, depthParen, depthBracket, quote := 0, 0, 0, 0, 0, rune(0)
230
+ for i, r := range body {
231
+ if quote != 0 {
232
+ if r == quote {
233
+ quote = 0
234
+ }
235
+ continue
236
+ }
237
+ switch r {
238
+ case '\'', '"', '`':
239
+ quote = r
240
+ case '<':
241
+ depthAngle++
242
+ case '>':
243
+ if depthAngle > 0 {
244
+ depthAngle--
245
+ }
246
+ case '{':
247
+ depthBrace++
248
+ case '}':
249
+ if depthBrace > 0 {
250
+ depthBrace--
251
+ }
252
+ case '(':
253
+ depthParen++
254
+ case ')':
255
+ if depthParen > 0 {
256
+ depthParen--
257
+ }
258
+ case '[':
259
+ depthBracket++
260
+ case ']':
261
+ if depthBracket > 0 {
262
+ depthBracket--
263
+ }
264
+ case ';', ',', '\n':
265
+ if depthAngle == 0 && depthBrace == 0 && depthParen == 0 && depthBracket == 0 {
266
+ if r == '\n' && isTypeContinuationNewline(body, start, i) {
267
+ continue
268
+ }
269
+ parts = append(parts, strings.TrimSpace(body[start:i]))
270
+ start = i + len(string(r))
271
+ }
272
+ }
273
+ }
274
+ parts = append(parts, strings.TrimSpace(body[start:]))
275
+ return parts
276
+ }
277
+
278
+ func isTypeContinuationNewline(body string, start int, newline int) bool {
279
+ before := strings.TrimSpace(body[start:newline])
280
+ if before == "" {
281
+ return false
282
+ }
283
+ if strings.HasSuffix(before, "&") || strings.HasSuffix(before, "|") {
284
+ return true
285
+ }
286
+ after := strings.TrimLeft(body[newline+1:], " \t\n")
287
+ return strings.HasPrefix(after, "&") || strings.HasPrefix(after, "|")
288
+ }
289
+
290
+ func stripTypeComments(body string) string {
291
+ if !strings.Contains(body, "/") {
292
+ return body
293
+ }
294
+ var out strings.Builder
295
+ out.Grow(len(body))
296
+ for i := 0; i < len(body); i++ {
297
+ current := body[i]
298
+ next := byte(0)
299
+ if i+1 < len(body) {
300
+ next = body[i+1]
301
+ }
302
+ if current == '\'' || current == '"' {
303
+ quote := current
304
+ out.WriteByte(current)
305
+ for i++; i < len(body); i++ {
306
+ out.WriteByte(body[i])
307
+ if body[i] == '\\' && i+1 < len(body) {
308
+ i++
309
+ out.WriteByte(body[i])
310
+ continue
311
+ }
312
+ if body[i] == quote {
313
+ break
314
+ }
315
+ }
316
+ continue
317
+ }
318
+ if current == '`' {
319
+ end := skipTemplateLiteral(body, i)
320
+ out.WriteString(body[i : end+1])
321
+ i = end
322
+ continue
323
+ }
324
+ if current == '/' && next == '/' {
325
+ out.WriteString(" ")
326
+ i += 2
327
+ for ; i < len(body) && body[i] != '\n' && body[i] != '\r'; i++ {
328
+ out.WriteByte(' ')
329
+ }
330
+ if i < len(body) {
331
+ out.WriteByte(body[i])
332
+ }
333
+ continue
334
+ }
335
+ if current == '/' && next == '*' {
336
+ out.WriteString(" ")
337
+ i += 2
338
+ for ; i < len(body); i++ {
339
+ if body[i] == '*' && i+1 < len(body) && body[i+1] == '/' {
340
+ out.WriteString(" ")
341
+ i++
342
+ break
343
+ }
344
+ if body[i] == '\n' || body[i] == '\r' {
345
+ out.WriteByte(body[i])
346
+ } else {
347
+ out.WriteByte(' ')
348
+ }
349
+ }
350
+ continue
351
+ }
352
+ out.WriteByte(current)
353
+ }
354
+ return out.String()
355
+ }
356
+
357
+ func parseField(field string) (string, string, bool, bool) {
358
+ field = strings.TrimSpace(field)
359
+ if field == "" {
360
+ return "", "", false, false
361
+ }
362
+ if strings.HasPrefix(field, "[") || strings.HasPrefix(field, "new ") || strings.HasPrefix(field, "abstract new ") || strings.HasPrefix(field, "(") {
363
+ return "", "", false, false
364
+ }
365
+ name, rest, ok := strings.Cut(field, ":")
366
+ if !ok {
367
+ return "", "", false, false
368
+ }
369
+ name = strings.TrimSpace(name)
370
+ if strings.Contains(name, "(") || strings.Contains(name, ")") {
371
+ return "", "", false, false
372
+ }
373
+ optional := strings.HasSuffix(name, "?")
374
+ name = strings.TrimSuffix(name, "?")
375
+ if (strings.HasPrefix(name, "'") && strings.HasSuffix(name, "'")) || (strings.HasPrefix(name, "\"") && strings.HasSuffix(name, "\"")) {
376
+ name = literalStringValue(name)
377
+ }
378
+ return name, strings.TrimSpace(rest), optional, true
379
+ }
380
+
381
+ func indexSignatureType(body string) (string, bool) {
382
+ for _, field := range splitInterfaceFields(body) {
383
+ field = strings.TrimSpace(field)
384
+ if !strings.HasPrefix(field, "[") {
385
+ continue
386
+ }
387
+ close := strings.Index(field, "]")
388
+ if close < 0 {
389
+ continue
390
+ }
391
+ rest := strings.TrimSpace(field[close+1:])
392
+ if !strings.HasPrefix(rest, ":") {
393
+ continue
394
+ }
395
+ indexType := strings.TrimSpace(rest[1:])
396
+ if indexType != "" {
397
+ return indexType, true
398
+ }
399
+ }
400
+ return "", false
401
+ }
402
+
403
+ func isFunctionTypeSyntax(raw string) bool {
404
+ raw = strings.TrimSpace(raw)
405
+ return strings.Contains(raw, "=>") || strings.HasPrefix(raw, "new ") || strings.HasPrefix(raw, "abstract new ")
406
+ }
407
+
408
+ func isUnsupportedTypeSyntax(raw string) bool {
409
+ raw = strings.TrimSpace(raw)
410
+ if raw == "" {
411
+ return false
412
+ }
413
+ if len(raw) == 1 && raw[0] >= 'A' && raw[0] <= 'Z' {
414
+ return true
415
+ }
416
+ if containsUnsupportedSyntaxMarker(raw) {
417
+ return true
418
+ }
419
+ if strings.HasPrefix(raw, "keyof ") || strings.Contains(raw, " keyof ") || strings.Contains(raw, " in ") || strings.Contains(raw, " infer ") {
420
+ return true
421
+ }
422
+ return false
423
+ }
424
+
425
+ func containsUnsupportedSyntaxMarker(raw string) bool {
426
+ quote := byte(0)
427
+ for i := 0; i < len(raw); i++ {
428
+ c := raw[i]
429
+ if quote != 0 {
430
+ if c == '\\' {
431
+ i++
432
+ continue
433
+ }
434
+ if c == quote {
435
+ quote = 0
436
+ }
437
+ continue
438
+ }
439
+ switch c {
440
+ case '\'', '"':
441
+ quote = c
442
+ case '`':
443
+ i = skipTemplateLiteral(raw, i)
444
+ case '[', ']', ':', '?':
445
+ return true
446
+ }
447
+ }
448
+ return false
449
+ }
450
+
451
+ func hasUnresolvedTypeParameters(raw string, params []string) bool {
452
+ for _, param := range params {
453
+ param = strings.TrimSpace(param)
454
+ if param == "" {
455
+ continue
456
+ }
457
+ if regexp.MustCompile(`\b` + regexp.QuoteMeta(param) + `\b`).MatchString(raw) {
458
+ return true
459
+ }
460
+ }
461
+ return false
462
+ }
463
+
464
+ func findBalanced(text string, open int, left byte, right byte) int {
465
+ depth := 0
466
+ quote := byte(0)
467
+ lineComment := false
468
+ blockComment := false
469
+ for i := open; i < len(text); i++ {
470
+ c := text[i]
471
+ next := byte(0)
472
+ if i+1 < len(text) {
473
+ next = text[i+1]
474
+ }
475
+ if lineComment {
476
+ if c == '\n' || c == '\r' {
477
+ lineComment = false
478
+ }
479
+ continue
480
+ }
481
+ if blockComment {
482
+ if c == '*' && next == '/' {
483
+ blockComment = false
484
+ i++
485
+ }
486
+ continue
487
+ }
488
+ if quote != 0 {
489
+ if c == '\\' {
490
+ i++
491
+ continue
492
+ }
493
+ if c == quote {
494
+ quote = 0
495
+ }
496
+ continue
497
+ }
498
+ if c == '\'' || c == '"' {
499
+ quote = c
500
+ continue
501
+ }
502
+ if c == '`' {
503
+ i = skipTemplateLiteral(text, i)
504
+ continue
505
+ }
506
+ if c == '/' && next == '/' {
507
+ lineComment = true
508
+ i++
509
+ continue
510
+ }
511
+ if c == '/' && next == '*' {
512
+ blockComment = true
513
+ i++
514
+ continue
515
+ }
516
+ if c == left {
517
+ depth++
518
+ } else if c == right {
519
+ depth--
520
+ if depth == 0 {
521
+ return i
522
+ }
523
+ }
524
+ }
525
+ return -1
526
+ }
527
+
528
+ func skipSpace(text string, pos int) int {
529
+ for pos < len(text) && (text[pos] == ' ' || text[pos] == '\n' || text[pos] == '\r' || text[pos] == '\t') {
530
+ pos++
531
+ }
532
+ return pos
533
+ }
534
+
535
+ func isIdent(c byte) bool {
536
+ return c == '_' || c == '$' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9'
537
+ }
538
+
539
+ func isIdentifierName(value string) bool {
540
+ if value == "" {
541
+ return false
542
+ }
543
+ for i := 0; i < len(value); i++ {
544
+ c := value[i]
545
+ if !isIdent(c) || (i == 0 && c >= '0' && c <= '9') {
546
+ return false
547
+ }
548
+ }
549
+ return true
550
+ }
551
+
552
+ func trimParens(raw string) string {
553
+ for strings.HasPrefix(raw, "(") && strings.HasSuffix(raw, ")") {
554
+ end := findBalanced(raw, 0, '(', ')')
555
+ if end != len(raw)-1 {
556
+ break
557
+ }
558
+ raw = strings.TrimSpace(raw[1 : len(raw)-1])
559
+ }
560
+ return raw
561
+ }
562
+
563
+ func isObjectLiteralTypeText(raw string) bool {
564
+ raw = strings.TrimSpace(raw)
565
+ return strings.HasPrefix(raw, "{") &&
566
+ strings.HasSuffix(raw, "}") &&
567
+ findBalanced(raw, 0, '{', '}') == len(raw)-1
568
+ }
569
+
570
+ func firstArg(args []string) string {
571
+ if len(args) == 0 {
572
+ return "unknown"
573
+ }
574
+ return args[0]
575
+ }
576
+
577
+ func firstOptionArg(args []string) string {
578
+ if len(args) == 0 {
579
+ return ""
580
+ }
581
+ return args[0]
582
+ }
583
+
584
+ func optionArg(args []string, index int) string {
585
+ if index < len(args) && strings.TrimSpace(args[index]) != "" {
586
+ return args[index]
587
+ }
588
+ return "{}"
589
+ }
590
+
591
+ func aliasParamName(alias aliasInfo, index int) string {
592
+ if index < len(alias.params) && alias.params[index] != "" {
593
+ return alias.params[index]
594
+ }
595
+ return fmt.Sprintf("T%d", index)
596
+ }
597
+
598
+ func aliasArg(alias aliasInfo, args []string, index int) string {
599
+ if index < len(args) && strings.TrimSpace(args[index]) != "" {
600
+ return args[index]
601
+ }
602
+ if index < len(alias.defaults) && strings.TrimSpace(alias.defaults[index]) != "" {
603
+ return alias.defaults[index]
604
+ }
605
+ return "unknown"
606
+ }
607
+
608
+ func replaceTypeParameter(input string, name string, value string) string {
609
+ re := regexp.MustCompile(`\b` + regexp.QuoteMeta(name) + `\b`)
610
+ return re.ReplaceAllString(input, value)
611
+ }
612
+
613
+ func normalizeStringLiteral(raw string) string {
614
+ if value, ok := tsStringLiteralValue(raw); ok {
615
+ return strconv.Quote(value)
616
+ }
617
+ return strings.TrimSpace(raw)
618
+ }
619
+
620
+ func literalStringValue(raw string) string {
621
+ if value, ok := tsStringLiteralValue(raw); ok {
622
+ return value
623
+ }
624
+ raw = strings.TrimSpace(raw)
625
+ value, err := strconv.Unquote(raw)
626
+ if err == nil {
627
+ return value
628
+ }
629
+ return raw
630
+ }
631
+
632
+ func tsStringLiteralValue(raw string) (string, bool) {
633
+ raw = strings.TrimSpace(raw)
634
+ if len(raw) < 2 {
635
+ return "", false
636
+ }
637
+ quote := raw[0]
638
+ if (quote != '\'' && quote != '"' && quote != '`') || raw[len(raw)-1] != quote {
639
+ return "", false
640
+ }
641
+ return decodeTsStringEscapes(raw[1 : len(raw)-1]), true
642
+ }
643
+
644
+ func decodeTsStringEscapes(value string) string {
645
+ var out strings.Builder
646
+ out.Grow(len(value))
647
+ for i := 0; i < len(value); i++ {
648
+ ch := value[i]
649
+ if ch != '\\' || i+1 >= len(value) {
650
+ out.WriteByte(ch)
651
+ continue
652
+ }
653
+ i++
654
+ switch next := value[i]; next {
655
+ case '0':
656
+ out.WriteByte(0)
657
+ case 'b':
658
+ out.WriteByte('\b')
659
+ case 'f':
660
+ out.WriteByte('\f')
661
+ case 'n':
662
+ out.WriteByte('\n')
663
+ case 'r':
664
+ out.WriteByte('\r')
665
+ case 't':
666
+ out.WriteByte('\t')
667
+ case 'v':
668
+ out.WriteByte('\v')
669
+ case '\n':
670
+ continue
671
+ case '\r':
672
+ if i+1 < len(value) && value[i+1] == '\n' {
673
+ i++
674
+ }
675
+ continue
676
+ case 'x':
677
+ if i+2 < len(value) {
678
+ if parsed, err := strconv.ParseInt(value[i+1:i+3], 16, 32); err == nil {
679
+ out.WriteRune(rune(parsed))
680
+ i += 2
681
+ continue
682
+ }
683
+ }
684
+ out.WriteByte(next)
685
+ case 'u':
686
+ if i+1 < len(value) && value[i+1] == '{' {
687
+ end := strings.IndexByte(value[i+2:], '}')
688
+ if end >= 0 {
689
+ digits := value[i+2 : i+2+end]
690
+ if parsed, err := strconv.ParseInt(digits, 16, 32); err == nil {
691
+ out.WriteRune(rune(parsed))
692
+ i += end + 2
693
+ continue
694
+ }
695
+ }
696
+ }
697
+ if i+4 < len(value) {
698
+ if parsed, err := strconv.ParseInt(value[i+1:i+5], 16, 32); err == nil {
699
+ out.WriteRune(rune(parsed))
700
+ i += 4
701
+ continue
702
+ }
703
+ }
704
+ out.WriteByte(next)
705
+ default:
706
+ out.WriteByte(next)
707
+ }
708
+ }
709
+ return out.String()
710
+ }
711
+
712
+ func isLiteralStringType(raw string) bool {
713
+ raw = strings.TrimSpace(raw)
714
+ return len(raw) >= 2 && ((raw[0] == '\'' && raw[len(raw)-1] == '\'') || (raw[0] == '"' && raw[len(raw)-1] == '"'))
715
+ }
716
+
717
+ func quote(value string) string {
718
+ return strconv.Quote(value)
719
+ }
720
+
721
+ func boolLit(value bool) string {
722
+ if value {
723
+ return "true"
724
+ }
725
+ return "false"
726
+ }
727
+
728
+ func mapJoin(values []string, mapper func(string) string) string {
729
+ out := make([]string, 0, len(values))
730
+ for _, value := range values {
731
+ out = append(out, mapper(value))
732
+ }
733
+ return strings.Join(out, ", ")
734
+ }