@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,2316 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "math"
6
+ "sort"
7
+ "strconv"
8
+ "strings"
9
+
10
+ shimast "github.com/microsoft/typescript-go/shim/ast"
11
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
12
+ typiafactories "github.com/samchon/typia/packages/typia/native/core/factories"
13
+ schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
14
+ )
15
+
16
+ func typeExprForNode(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) string {
17
+ return typeExprForNodePreferred(info, reg, raw, node, pos, false)
18
+ }
19
+
20
+ func typeExprForNodePreferred(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int, preferTypia bool) string {
21
+ raw = strings.TrimSpace(stripTypeComments(raw))
22
+ checkerAlgebra := shouldResolveTypeAlgebraWithChecker(reg, raw, node)
23
+ if preferTypia {
24
+ if expr, ok := preferredWrapperTypeExprForNode(info, reg, raw, node, pos); ok {
25
+ return expr
26
+ }
27
+ if expr, ok := preferredCachedAliasTypeExpr(info, reg, raw, pos); ok {
28
+ return expr
29
+ }
30
+ if expr, ok := preferredNullishAliasTypeExpr(info, reg, raw, node, pos); ok {
31
+ return expr
32
+ }
33
+ if expr, ok := preferredDateRootTypeExpr(info, reg, raw, node, pos); ok {
34
+ return expr
35
+ }
36
+ if expr, ok := preferredExternalImportedTypeExpr(info, raw); ok {
37
+ return expr
38
+ }
39
+ if expr, ok := preferredExternalImportedCompositeTypeExpr(info, reg, raw, node, pos); ok {
40
+ return expr
41
+ }
42
+ if expr, ok := preferredNamedInterfaceTypeExpr(info, reg, raw, pos); ok {
43
+ return expr
44
+ }
45
+ canUseTypia := canPreferTypiaTypeOnPreferredSurfaceAt(info, reg, raw, pos)
46
+ if checkerAlgebra {
47
+ // Conditional and mapped aliases are already resolved by the checker.
48
+ // Their source arguments can contain literal unions whose ordering makes
49
+ // the general preferred-surface policy conservative, but that should not
50
+ // force a type-only helper such as Exclude into the runtime-value fallback.
51
+ canUseTypia = canResolveTypeAlgebraWithChecker(info, reg, raw)
52
+ }
53
+ if canUseTypia {
54
+ if expr, ok := typiaTypeExprForNode(info, reg, raw, node, pos); ok {
55
+ return typiaSourceNamedExpr(info, reg, expr, raw)
56
+ }
57
+ }
58
+ if checkerAlgebra {
59
+ return unresolvedTypeAlgebraExpr(info, reg, raw)
60
+ }
61
+ }
62
+ if checkerAlgebra {
63
+ if canResolveTypeAlgebraWithChecker(info, reg, raw) {
64
+ if expr, ok := typiaTypeExprForNode(info, reg, raw, node, pos); ok {
65
+ return typiaSourceNamedExpr(info, reg, expr, raw)
66
+ }
67
+ }
68
+ return unresolvedTypeAlgebraExpr(info, reg, raw)
69
+ }
70
+ if shouldUseTextTypeExpr(raw) {
71
+ return internalTypeExprForNode(info, reg, raw, node, pos)
72
+ }
73
+ if shouldUseTypiaType(info, reg, raw) && canPreferTypiaType(info, reg, raw) {
74
+ if expr, ok := typiaTypeExprForNode(info, reg, raw, node, pos); ok {
75
+ return typiaSourceNamedExpr(info, reg, expr, raw)
76
+ }
77
+ }
78
+ return internalTypeExprForNode(info, reg, raw, node, pos)
79
+ }
80
+
81
+ func internalTypeExprForNode(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) string {
82
+ return internalTypeExprForNodeCtx(info, reg, raw, node, &typeContext{seen: map[string]bool{}, pos: pos})
83
+ }
84
+
85
+ func internalTypeExprForNodeCtx(info *fileInfo, reg *registry, raw string, node *shimast.Node, ctx *typeContext) string {
86
+ if ctx == nil {
87
+ ctx = &typeContext{seen: map[string]bool{}}
88
+ }
89
+ if node == nil {
90
+ return typeExprCtx(info, reg, raw, ctx)
91
+ }
92
+ if node.Kind == shimast.KindParenthesizedType {
93
+ inner := node.AsParenthesizedTypeNode().Type
94
+ if innerRaw, ok := sourceTypeNodeText(info, inner); ok {
95
+ return internalTypeExprForNodeCtx(info, reg, innerRaw, inner, ctx)
96
+ }
97
+ return typeExprCtx(info, reg, raw, ctx)
98
+ }
99
+
100
+ var kind int
101
+ var nodes []*shimast.Node
102
+ switch node.Kind {
103
+ case shimast.KindUnionType:
104
+ kind = 12
105
+ if types := node.AsUnionTypeNode().Types; types != nil {
106
+ nodes = types.Nodes
107
+ }
108
+ case shimast.KindIntersectionType:
109
+ kind = 13
110
+ if types := node.AsIntersectionTypeNode().Types; types != nil {
111
+ nodes = types.Nodes
112
+ }
113
+ default:
114
+ return typeExprCtx(info, reg, raw, ctx)
115
+ }
116
+ if len(nodes) < 2 {
117
+ return typeExprCtx(info, reg, raw, ctx)
118
+ }
119
+
120
+ types := make([]string, 0, len(nodes))
121
+ for _, child := range nodes {
122
+ childRaw, ok := sourceTypeNodeText(info, child)
123
+ if !ok {
124
+ return typeExprCtx(info, reg, raw, ctx)
125
+ }
126
+ types = append(types, internalTypeExprForNodeCtx(info, reg, childRaw, child, ctx))
127
+ }
128
+ return "{kind: " + strconv.Itoa(kind) + ", types: [" + strings.Join(types, ", ") + "]}"
129
+ }
130
+
131
+ func sourceTypeNodeText(info *fileInfo, node *shimast.Node) (string, bool) {
132
+ if node == nil {
133
+ return "", false
134
+ }
135
+ file := shimast.GetSourceFileOfNode(node)
136
+ if file == nil && info != nil {
137
+ file = info.file
138
+ }
139
+ if file == nil {
140
+ return "", false
141
+ }
142
+ return nodeText(file, node), true
143
+ }
144
+
145
+ func preferredCachedAliasTypeExpr(info *fileInfo, reg *registry, raw string, pos int) (string, bool) {
146
+ raw = strings.TrimSpace(trimParens(raw))
147
+ if !isIdentifierName(raw) {
148
+ return "", false
149
+ }
150
+ alias, owner, ref, ok := resolveAliasRef(info, reg, raw)
151
+ if !ok || len(alias.params) != 0 {
152
+ return "", false
153
+ }
154
+ aliasName := raw
155
+ if ref != nil {
156
+ aliasName = ref.exportName
157
+ }
158
+ alias = ensureAliasMetadata(owner, reg, aliasName, alias)
159
+ if strings.TrimSpace(alias.metadataText) == "" {
160
+ return "", false
161
+ }
162
+ return aliasTypeExprCtx(owner, reg, alias, raw, &typeContext{seen: map[string]bool{}, pos: pos}), true
163
+ }
164
+
165
+ func preferredNullishAliasTypeExpr(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
166
+ types := []string{}
167
+ aliasCount, ok := collectNullishAliasTypeExprs(info, reg, raw, node, pos, &types)
168
+ if !ok || aliasCount != 1 || len(types) <= 1 {
169
+ return "", false
170
+ }
171
+ return "{kind: 12, types: [" + strings.Join(types, ", ") + "]}", true
172
+ }
173
+
174
+ func collectNullishAliasTypeExprs(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int, types *[]string) (int, bool) {
175
+ raw = strings.TrimSpace(trimParens(raw))
176
+ if node != nil && node.Kind == shimast.KindParenthesizedType {
177
+ inner := node.AsParenthesizedTypeNode().Type
178
+ if innerRaw, ok := sourceTypeNodeText(info, inner); ok {
179
+ return collectNullishAliasTypeExprs(info, reg, innerRaw, inner, pos, types)
180
+ }
181
+ }
182
+ if node != nil && node.Kind == shimast.KindUnionType {
183
+ union := node.AsUnionTypeNode()
184
+ if union.Types != nil && len(union.Types.Nodes) > 1 {
185
+ aliasCount := 0
186
+ for _, child := range union.Types.Nodes {
187
+ childRaw, ok := sourceTypeNodeText(info, child)
188
+ if !ok {
189
+ return 0, false
190
+ }
191
+ count, ok := collectNullishAliasTypeExprs(info, reg, childRaw, child, pos, types)
192
+ if !ok {
193
+ return 0, false
194
+ }
195
+ aliasCount += count
196
+ }
197
+ return aliasCount, true
198
+ }
199
+ }
200
+ parts := nonEmptyParts(splitTop(raw, "|"))
201
+ if len(parts) > 1 {
202
+ aliasCount := 0
203
+ for _, part := range parts {
204
+ count, ok := collectNullishAliasTypeExprs(info, reg, part, nil, pos, types)
205
+ if !ok {
206
+ return 0, false
207
+ }
208
+ aliasCount += count
209
+ }
210
+ return aliasCount, true
211
+ }
212
+ switch raw {
213
+ case "null":
214
+ *types = append(*types, "{kind: 5}")
215
+ return 0, true
216
+ case "undefined":
217
+ *types = append(*types, "{kind: 4}")
218
+ return 0, true
219
+ default:
220
+ expr, ok := preferredCachedAliasTypeExpr(info, reg, raw, pos)
221
+ if !ok {
222
+ return 0, false
223
+ }
224
+ *types = append(*types, expr)
225
+ return 1, true
226
+ }
227
+ }
228
+
229
+ func preferredDateRootTypeExpr(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
230
+ if !sourceTypeIsDateRootType(info, reg, raw, &typeContext{seen: map[string]bool{}, pos: pos}, map[string]bool{}) {
231
+ return "", false
232
+ }
233
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
234
+ }
235
+
236
+ func preferredExternalImportedTypeExpr(info *fileInfo, raw string) (string, bool) {
237
+ raw = strings.TrimSpace(trimParens(raw))
238
+ if !isIdentifierName(raw) {
239
+ return "", false
240
+ }
241
+ ref, ok := info.imports[raw]
242
+ if !ok || !isExternalImportRef(ref) {
243
+ return "", false
244
+ }
245
+ return externalImportedTypeExpr(ref, raw), true
246
+ }
247
+
248
+ func preferredExternalImportedCompositeTypeExpr(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
249
+ raw = strings.TrimSpace(trimParens(raw))
250
+ if raw == "" || isIdentifierName(raw) {
251
+ return "", false
252
+ }
253
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
254
+ if typeContainsExternalImportReferenceInParts(info, reg, parts, map[string]bool{}) {
255
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
256
+ }
257
+ }
258
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
259
+ if typeContainsExternalImportReferenceInParts(info, reg, parts, map[string]bool{}) {
260
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
261
+ }
262
+ }
263
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
264
+ parts := nonEmptyParts(splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","))
265
+ if typeContainsExternalImportReferenceInParts(info, reg, parts, map[string]bool{}) {
266
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
267
+ }
268
+ }
269
+ return "", false
270
+ }
271
+
272
+ func preferredNamedInterfaceTypeExpr(info *fileInfo, reg *registry, raw string, pos int) (string, bool) {
273
+ raw = strings.TrimSpace(trimParens(raw))
274
+ if !isIdentifierName(raw) {
275
+ return "", false
276
+ }
277
+ decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, raw, pos)
278
+ if !ok {
279
+ return "", false
280
+ }
281
+ if !interfaceNeedsPreferredSourceMetadata(owner, reg, decl, map[string]bool{}) {
282
+ return "", false
283
+ }
284
+ return interfaceObjectLiteralExprPreferred(owner, reg, raw, decl, &typeContext{seen: map[string]bool{}, pos: pos}), true
285
+ }
286
+
287
+ func interfaceNeedsPreferredSourceMetadata(info *fileInfo, reg *registry, decl interfaceInfo, seen map[string]bool) bool {
288
+ key := info.moduleKey + "\x00" + strconv.Itoa(decl.pos)
289
+ if seen[key] {
290
+ return false
291
+ }
292
+ seen[key] = true
293
+ for _, prop := range interfaceFullProperties(info, reg, decl, map[string]bool{}) {
294
+ owner := info
295
+ if prop.owner != nil {
296
+ owner = prop.owner
297
+ }
298
+ if typeContainsAliasReference(owner, reg, prop.typeText, map[string]bool{}) {
299
+ return true
300
+ }
301
+ if typeContainsExternalImportReference(owner, reg, prop.typeText, map[string]bool{}) {
302
+ return true
303
+ }
304
+ if sourceTypeContainsDateType(owner, reg, prop.typeText, &typeContext{seen: map[string]bool{}, pos: decl.pos}, map[string]bool{}) {
305
+ return true
306
+ }
307
+ if sourceTypeNeedsInternalPropertyMetadata(owner, reg, prop.typeText, &typeContext{seen: map[string]bool{}, pos: decl.pos}, map[string]bool{}) {
308
+ return true
309
+ }
310
+ }
311
+ return false
312
+ }
313
+
314
+ func typeContainsAliasReference(info *fileInfo, reg *registry, raw string, seen map[string]bool) bool {
315
+ raw = strings.TrimSpace(trimParens(raw))
316
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
317
+ if raw == "" {
318
+ return false
319
+ }
320
+ key := info.moduleKey + "\x00alias-boundary\x00" + raw
321
+ if seen[key] {
322
+ return false
323
+ }
324
+ seen[key] = true
325
+ if isIdentifierName(raw) {
326
+ _, _, _, ok := resolveAliasRef(info, reg, raw)
327
+ return ok
328
+ }
329
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
330
+ return typeContainsAliasReferenceInParts(info, reg, parts, seen)
331
+ }
332
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
333
+ return typeContainsAliasReferenceInParts(info, reg, parts, seen)
334
+ }
335
+ if strings.HasSuffix(raw, "[]") {
336
+ return typeContainsAliasReference(info, reg, strings.TrimSuffix(raw, "[]"), seen)
337
+ }
338
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
339
+ return typeContainsAliasReferenceInParts(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), seen)
340
+ }
341
+ if isObjectLiteralTypeText(raw) {
342
+ for _, prop := range propertiesFromBody(strings.TrimSpace(raw[1 : len(raw)-1])) {
343
+ if typeContainsAliasReference(info, reg, prop.typeText, seen) {
344
+ return true
345
+ }
346
+ }
347
+ return false
348
+ }
349
+ if name, args, ok := generic(raw); ok {
350
+ if _, _, _, ok := resolveAliasRef(info, reg, name); ok {
351
+ return true
352
+ }
353
+ for _, arg := range args {
354
+ if typeContainsAliasReference(info, reg, arg, seen) {
355
+ return true
356
+ }
357
+ }
358
+ }
359
+ return false
360
+ }
361
+
362
+ func typeContainsAliasReferenceInParts(info *fileInfo, reg *registry, parts []string, seen map[string]bool) bool {
363
+ for _, part := range parts {
364
+ if typeContainsAliasReference(info, reg, part, seen) {
365
+ return true
366
+ }
367
+ }
368
+ return false
369
+ }
370
+
371
+ func typeContainsExternalImportReference(info *fileInfo, reg *registry, raw string, seen map[string]bool) bool {
372
+ raw = strings.TrimSpace(trimParens(raw))
373
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
374
+ if raw == "" {
375
+ return false
376
+ }
377
+ key := info.moduleKey + "\x00external-boundary\x00" + raw
378
+ if seen[key] {
379
+ return false
380
+ }
381
+ seen[key] = true
382
+ if isIdentifierName(raw) {
383
+ if ref, ok := info.imports[raw]; ok && isExternalImportRef(ref) && !isFoundationImportRef(ref) {
384
+ return true
385
+ }
386
+ }
387
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
388
+ return typeContainsExternalImportReferenceInParts(info, reg, parts, seen)
389
+ }
390
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
391
+ return typeContainsExternalImportReferenceInParts(info, reg, parts, seen)
392
+ }
393
+ if strings.HasSuffix(raw, "[]") {
394
+ return typeContainsExternalImportReference(info, reg, strings.TrimSuffix(raw, "[]"), seen)
395
+ }
396
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
397
+ return typeContainsExternalImportReferenceInParts(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), seen)
398
+ }
399
+ if isObjectLiteralTypeText(raw) {
400
+ for _, prop := range propertiesFromBody(strings.TrimSpace(raw[1 : len(raw)-1])) {
401
+ if typeContainsExternalImportReference(info, reg, prop.typeText, seen) {
402
+ return true
403
+ }
404
+ }
405
+ return false
406
+ }
407
+ if name, args, ok := generic(raw); ok {
408
+ if ref, ok := info.imports[name]; ok && isExternalImportRef(ref) && !isFoundationImportRef(ref) {
409
+ return true
410
+ }
411
+ for _, arg := range args {
412
+ if typeContainsExternalImportReference(info, reg, arg, seen) {
413
+ return true
414
+ }
415
+ }
416
+ }
417
+ return false
418
+ }
419
+
420
+ func typeContainsExternalImportReferenceInParts(info *fileInfo, reg *registry, parts []string, seen map[string]bool) bool {
421
+ for _, part := range parts {
422
+ if typeContainsExternalImportReference(info, reg, part, seen) {
423
+ return true
424
+ }
425
+ }
426
+ return false
427
+ }
428
+
429
+ func shouldUseTextTypeExpr(raw string) bool {
430
+ name, _, ok := generic(strings.TrimSpace(trimParens(raw)))
431
+ return ok && name == "FileUpload"
432
+ }
433
+
434
+ func typiaSourceNamedExpr(info *fileInfo, reg *registry, expr string, raw string) string {
435
+ raw = strings.TrimSpace(trimParens(raw))
436
+ if isIdentifierName(raw) {
437
+ if _, _, _, ok := resolveAliasRef(info, reg, raw); ok {
438
+ return withTypeName(expr, raw)
439
+ }
440
+ if ref, ok := info.imports[raw]; ok && isFoundationImportRef(ref) {
441
+ return withTypeName(expr, raw)
442
+ }
443
+ }
444
+ return expr
445
+ }
446
+
447
+ func cachedTypeExpr(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int, cached string) string {
448
+ if strings.TrimSpace(cached) != "" {
449
+ return cached
450
+ }
451
+ return typeExprForNode(info, reg, raw, node, pos)
452
+ }
453
+
454
+ func preferredWrapperTypeExprForNode(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
455
+ raw = strings.TrimSpace(trimParens(raw))
456
+ if strings.HasSuffix(raw, "[]") {
457
+ element := strings.TrimSpace(strings.TrimSuffix(raw, "[]"))
458
+ return "{kind: 14, type: " + typeExprForNodePreferred(info, reg, element, nil, pos, true) + "}", true
459
+ }
460
+ name, args, ok := generic(raw)
461
+ if !ok {
462
+ return "", false
463
+ }
464
+ argExpr := func(index int) string {
465
+ return preferredTypeArgExpr(info, reg, args, node, index, pos)
466
+ }
467
+ argRaw := func(index int) string {
468
+ if index < len(args) {
469
+ return args[index]
470
+ }
471
+ return "unknown"
472
+ }
473
+ argNode := func(index int) *shimast.Node {
474
+ typeArgs := typeNodeArgs(node)
475
+ if index < len(typeArgs) {
476
+ return typeArgs[index]
477
+ }
478
+ return nil
479
+ }
480
+
481
+ switch name {
482
+ case "Array", "ReadonlyArray":
483
+ return "{kind: 14, type: " + argExpr(0) + "}", true
484
+ case "Promise":
485
+ return "{kind: 22, type: " + argExpr(0) + "}", true
486
+ case "ApiResponse":
487
+ body := argExpr(0)
488
+ status := literalArg("200")
489
+ if len(args) > 1 {
490
+ status = literalArg(args[1])
491
+ }
492
+ return "{kind: 22, typeName: \"ApiResponse\", type: " + body + ", typeArguments: [" + body + ", " + status + "]}", true
493
+ case "HttpBody":
494
+ return httpMarkerTypePreferred(info, reg, "HttpBody", "httpBody", argRaw(0), argNode(0), "{}", nil, pos), true
495
+ case "HttpQueries":
496
+ return httpMarkerTypePreferred(info, reg, "HttpQueries", "httpQueries", argRaw(0), argNode(0), "{}", nil, pos), true
497
+ case "HttpQuery":
498
+ return httpMarkerTypePreferred(info, reg, "HttpQuery", "httpQuery", argRaw(0), argNode(0), optionArg(args, 1), argNode(1), pos), true
499
+ case "HttpPath":
500
+ return httpMarkerTypePreferred(info, reg, "HttpPath", "httpPath", argRaw(0), argNode(0), optionArg(args, 1), argNode(1), pos), true
501
+ case "HttpHeader":
502
+ return httpMarkerTypePreferred(info, reg, "HttpHeader", "httpHeader", argRaw(0), argNode(0), optionArg(args, 1), argNode(1), pos), true
503
+ case "ApiType":
504
+ if len(args) < 2 {
505
+ return "{kind: 2, typeName: \"ApiType\"}", true
506
+ }
507
+ body := argExpr(1)
508
+ marker := typeAnnotationMarker("ApiName", "openapi:name", literalArg(args[0]))
509
+ return "{kind: 13, typeName: \"ApiType\", types: [" + body + ", " + marker + "]}", true
510
+ case "Record":
511
+ key := argExpr(0)
512
+ value := argExpr(1)
513
+ return "{kind: 18, typeName: \"Record\", utilityType: \"Record\", typeArguments: [" + key + ", " + value + "], index: " + value + ", types: []}", true
514
+ default:
515
+ return "", false
516
+ }
517
+ }
518
+
519
+ func preferredTypeArgExpr(info *fileInfo, reg *registry, args []string, node *shimast.Node, index int, pos int) string {
520
+ raw := "unknown"
521
+ if index < len(args) {
522
+ raw = args[index]
523
+ }
524
+ typeArgs := typeNodeArgs(node)
525
+ var argNode *shimast.Node
526
+ if index < len(typeArgs) {
527
+ argNode = typeArgs[index]
528
+ }
529
+ return typeExprForNodePreferred(info, reg, raw, argNode, pos, true)
530
+ }
531
+
532
+ func typeNodeArgs(node *shimast.Node) []*shimast.Node {
533
+ if node == nil {
534
+ return nil
535
+ }
536
+ switch node.Kind {
537
+ case shimast.KindTypeReference,
538
+ shimast.KindExpressionWithTypeArguments,
539
+ shimast.KindImportType,
540
+ shimast.KindTypeQuery:
541
+ return node.TypeArguments()
542
+ default:
543
+ return nil
544
+ }
545
+ }
546
+
547
+ func httpMarkerTypePreferred(info *fileInfo, reg *registry, typeName string, annotation string, valueRaw string, valueNode *shimast.Node, optionsRaw string, optionsNode *shimast.Node, pos int) string {
548
+ valueType := typeExprForNodePreferred(info, reg, valueRaw, valueNode, pos, true)
549
+ value := annotationOptionsWithTypeExpr(info, reg, optionsRaw, optionsNode, valueRaw, valueType, pos)
550
+ marker := typeAnnotationMarker(typeName, annotation, value)
551
+ return "{kind: 13, typeName: " + quote(typeName) + ", types: [" + valueType + ", " + marker + "]}"
552
+ }
553
+
554
+ func annotationOptionsWithTypeExpr(info *fileInfo, reg *registry, optionsRaw string, optionsNode *shimast.Node, valueRaw string, valueType string, pos int) string {
555
+ optionsRaw = strings.TrimSpace(optionsRaw)
556
+ props := []string{}
557
+ if optionsRaw != "" && optionsRaw != "{}" {
558
+ if isObjectLiteralTypeText(optionsRaw) {
559
+ ctx := &typeContext{seen: map[string]bool{}, pos: pos}
560
+ body := strings.TrimSpace(optionsRaw[1 : len(optionsRaw)-1])
561
+ props = append(props, objectLiteralProperties(info, reg, body, ctx)...)
562
+ } else {
563
+ ctx := &typeContext{seen: map[string]bool{}, pos: pos}
564
+ _ = optionsNode
565
+ return annotationValueExpr(info, reg, optionsRaw+" & { type: "+valueRaw+" }", ctx)
566
+ }
567
+ }
568
+ props = append(props, "{kind: 20, name: \"type\", type: "+valueType+", optional: false}")
569
+ return "{kind: 18, types: [" + strings.Join(props, ", ") + "]}"
570
+ }
571
+
572
+ func typiaTypeExprForNode(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
573
+ if reg == nil || reg.checker == nil || node == nil {
574
+ return "", false
575
+ }
576
+ typ := reg.checker.GetTypeFromTypeNode(node)
577
+ return typiaTypeExprFromType(info, reg, typ, pos, raw)
578
+ }
579
+
580
+ func shouldUseTypiaType(info *fileInfo, reg *registry, raw string) bool {
581
+ return shouldUseTypiaTypeCtx(info, reg, raw, map[string]bool{})
582
+ }
583
+
584
+ func shouldUseTypiaTypeCtx(info *fileInfo, reg *registry, raw string, seen map[string]bool) bool {
585
+ raw = strings.TrimSpace(trimParens(raw))
586
+ if raw == "" || isFunctionTypeSyntax(raw) {
587
+ return false
588
+ }
589
+ key := info.moduleKey + "\x00" + raw
590
+ if seen[key] {
591
+ return false
592
+ }
593
+ seen[key] = true
594
+ defer delete(seen, key)
595
+
596
+ if hasTypiaPreferredSyntax(raw) {
597
+ return true
598
+ }
599
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
600
+ return shouldUseTypiaTypeInParts(info, reg, parts, seen)
601
+ }
602
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
603
+ return shouldUseTypiaTypeInParts(info, reg, parts, seen)
604
+ }
605
+ if strings.HasSuffix(raw, "[]") {
606
+ return shouldUseTypiaTypeCtx(info, reg, strings.TrimSuffix(raw, "[]"), seen)
607
+ }
608
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
609
+ return shouldUseTypiaTypeInParts(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), seen)
610
+ }
611
+ if isObjectLiteralTypeText(raw) {
612
+ body := strings.TrimSpace(raw[1 : len(raw)-1])
613
+ for _, prop := range propertiesFromBody(body) {
614
+ if shouldUseTypiaTypeCtx(info, reg, prop.typeText, seen) {
615
+ return true
616
+ }
617
+ }
618
+ return false
619
+ }
620
+ if name, args, ok := generic(raw); ok {
621
+ if alias, owner, _, ok := resolveAliasRef(info, reg, name); ok {
622
+ if hasTypiaPreferredSyntax(alias.body) || shouldUseTypiaTypeCtx(owner, reg, alias.body, seen) {
623
+ return true
624
+ }
625
+ }
626
+ if ref, ok := info.imports[name]; ok && isFoundationImportRef(ref) {
627
+ return true
628
+ }
629
+ for _, arg := range args {
630
+ if shouldUseTypiaTypeCtx(info, reg, arg, seen) {
631
+ return true
632
+ }
633
+ }
634
+ return false
635
+ }
636
+ if isIdentifierName(raw) {
637
+ if alias, owner, _, ok := resolveAliasRef(info, reg, raw); ok {
638
+ return hasTypiaPreferredSyntax(alias.body) || shouldUseTypiaTypeCtx(owner, reg, alias.body, seen)
639
+ }
640
+ if ref, ok := info.imports[raw]; ok && isFoundationImportRef(ref) {
641
+ return true
642
+ }
643
+ }
644
+ return false
645
+ }
646
+
647
+ func shouldUseTypiaTypeInParts(info *fileInfo, reg *registry, parts []string, seen map[string]bool) bool {
648
+ for _, part := range parts {
649
+ if shouldUseTypiaTypeCtx(info, reg, part, seen) {
650
+ return true
651
+ }
652
+ }
653
+ return false
654
+ }
655
+
656
+ func hasTypiaPreferredSyntax(raw string) bool {
657
+ raw = strings.TrimSpace(raw)
658
+ compact := compactTypePattern(raw)
659
+ if strings.Contains(raw, "typia.tag") ||
660
+ strings.Contains(raw, "TypiaTagBase") ||
661
+ strings.Contains(raw, "TypiaFormat") ||
662
+ strings.Contains(raw, "TsfTypia") ||
663
+ strings.Contains(raw, "TsfTypeTag") ||
664
+ strings.Contains(raw, "TsfValidatorTag") ||
665
+ strings.Contains(raw, "TsfDatabase") {
666
+ return true
667
+ }
668
+ if strings.Contains(compact, "inkeyof") {
669
+ return true
670
+ }
671
+ return strings.Contains(raw, " extends ") && strings.Contains(raw, " ? ") && strings.Contains(raw, " : ")
672
+ }
673
+
674
+ func canPreferTypiaType(info *fileInfo, reg *registry, raw string) bool {
675
+ if typeContainsExternalImportReference(info, reg, raw, map[string]bool{}) {
676
+ return false
677
+ }
678
+ return !hasFrameworkMetadataSyntaxDeep(info, reg, raw, map[string]bool{})
679
+ }
680
+
681
+ func canPreferTypiaTypeOnPreferredSurface(info *fileInfo, reg *registry, raw string) bool {
682
+ return canPreferTypiaTypeOnPreferredSurfaceAt(info, reg, raw, 0)
683
+ }
684
+
685
+ func canPreferTypiaTypeOnPreferredSurfaceAt(info *fileInfo, reg *registry, raw string, pos int) bool {
686
+ return !hasPreferredTypiaBlockerSyntaxDeep(info, reg, raw, true, pos, map[string]bool{})
687
+ }
688
+
689
+ func shouldPreferTypiaAliasMetadata(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) bool {
690
+ raw = strings.TrimSpace(trimParens(raw))
691
+ if shouldResolveTypeAlgebraWithChecker(reg, raw, node) {
692
+ return canResolveTypeAlgebraWithChecker(info, reg, raw)
693
+ }
694
+ if sourceTypeContainsIndexedAccessSyntax(raw, map[string]bool{}) {
695
+ return canPreferTypiaTypeOnPreferredSurfaceAt(info, reg, raw, pos)
696
+ }
697
+ name, _, ok := generic(raw)
698
+ if !ok {
699
+ return false
700
+ }
701
+ ref, ok := info.imports[name]
702
+ return ok && isFoundationImportRef(ref) && !isRootInternalMetadataName(name) && canPreferTypiaTypeOnPreferredSurfaceAt(info, reg, raw, pos)
703
+ }
704
+
705
+ func canResolveTypeAlgebraWithChecker(info *fileInfo, reg *registry, raw string) bool {
706
+ // Imported package aliases are runtime package boundaries and must retain
707
+ // their emitted alias registry lookup. Local and standard-library type
708
+ // algebra is safe to resolve structurally; Typia preserves supported TSF
709
+ // tags and native runtime values in the resulting metadata.
710
+ return !typeContainsExternalImportReference(info, reg, raw, map[string]bool{})
711
+ }
712
+
713
+ // shouldResolveTypeAlgebraWithChecker recognizes type-only algebra that the
714
+ // internal encoder must not mistake for a JavaScript constructor. Project
715
+ // aliases expose their bodies through the registry and are already handled by
716
+ // shouldUseTypiaType. This extra checker lookup is for direct conditional or
717
+ // mapped syntax and standard-library helpers such as Exclude and Readonly,
718
+ // whose declarations are intentionally excluded from the project registry.
719
+ func shouldResolveTypeAlgebraWithChecker(reg *registry, raw string, node *shimast.Node) bool {
720
+ if node == nil {
721
+ return false
722
+ }
723
+ switch node.Kind {
724
+ case shimast.KindConditionalType, shimast.KindMappedType:
725
+ return true
726
+ case shimast.KindTypeReference:
727
+ default:
728
+ return false
729
+ }
730
+ name, _, ok := generic(strings.TrimSpace(trimParens(raw)))
731
+ if !ok || isInternallyEncodedTypeScriptAlias(name) || reg == nil || reg.checker == nil {
732
+ return false
733
+ }
734
+ typeName := node.AsTypeReferenceNode().TypeName
735
+ if typeName == nil {
736
+ return false
737
+ }
738
+ symbol := reg.checker.GetSymbolAtLocation(typeName)
739
+ if symbol == nil {
740
+ return false
741
+ }
742
+ if symbol.Flags&shimast.SymbolFlagsAlias != 0 {
743
+ symbol = shimchecker.Checker_getAliasedSymbol(reg.checker, symbol)
744
+ if symbol == nil {
745
+ return false
746
+ }
747
+ }
748
+ for _, declaration := range symbol.Declarations {
749
+ if declaration == nil || declaration.Kind != shimast.KindTypeAliasDeclaration {
750
+ continue
751
+ }
752
+ file := shimast.GetSourceFileOfNode(declaration)
753
+ if file == nil || !isTypeScriptLibDeclaration(file.FileName()) {
754
+ continue
755
+ }
756
+ body := declaration.AsTypeAliasDeclaration().Type
757
+ if body != nil && (body.Kind == shimast.KindConditionalType || body.Kind == shimast.KindMappedType) {
758
+ return true
759
+ }
760
+ }
761
+ return false
762
+ }
763
+
764
+ func isInternallyEncodedTypeScriptAlias(name string) bool {
765
+ switch name {
766
+ case "Extract", "NoInfer", "NonNullable", "Omit", "Partial", "Pick", "Record", "Required":
767
+ return true
768
+ default:
769
+ return false
770
+ }
771
+ }
772
+
773
+ // unresolvedTypeAlgebraExpr is a last-resort guard for a checker-recognized
774
+ // type alias that Typia could not serialize. Type aliases have no runtime value,
775
+ // so returning conservative metadata is safer than emitting classType: () =>
776
+ // Alias, which would both load the compact runtime and throw if evaluated.
777
+ func unresolvedTypeAlgebraExpr(info *fileInfo, reg *registry, raw string) string {
778
+ name, args, ok := generic(strings.TrimSpace(trimParens(raw)))
779
+ if !ok {
780
+ return "{kind: 2, typeName: " + quote(raw) + "}"
781
+ }
782
+ return "{kind: 2, typeName: " + quote(name) + ", typeArguments: [" + mapJoin(args, func(arg string) string {
783
+ return typeExprCtx(info, reg, arg, &typeContext{seen: map[string]bool{}})
784
+ }) + "]}"
785
+ }
786
+
787
+ func hasPreferredTypiaBlockerSyntaxDeep(info *fileInfo, reg *registry, raw string, root bool, pos int, seen map[string]bool) bool {
788
+ raw = strings.TrimSpace(trimParens(raw))
789
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
790
+ if raw == "" || raw == "unknown" {
791
+ return false
792
+ }
793
+ if isFunctionTypeSyntax(raw) {
794
+ return true
795
+ }
796
+ if isPreferredTypiaHardBlockerName(raw) || (root && isRootInternalMetadataName(raw)) {
797
+ return true
798
+ }
799
+
800
+ key := info.moduleKey + "\x00preferred\x00" + raw
801
+ if seen[key] {
802
+ return false
803
+ }
804
+ seen[key] = true
805
+ defer delete(seen, key)
806
+
807
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
808
+ nonNullish := nonNullishTypeParts(parts)
809
+ if len(nonNullish) > 1 && (hasLiteralUnionSyntax(nonNullish) || hasTaggedMetadataSyntaxInParts(info, reg, nonNullish, seen)) {
810
+ return true
811
+ }
812
+ return hasPreferredTypiaBlockerSyntaxInParts(info, reg, parts, false, pos, seen)
813
+ }
814
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
815
+ if root && hasRootInternalMetadataIntersectionPart(parts) {
816
+ return true
817
+ }
818
+ return hasPreferredTypiaBlockerSyntaxInParts(info, reg, parts, false, pos, seen)
819
+ }
820
+ if strings.HasSuffix(raw, "[]") {
821
+ return hasPreferredTypiaBlockerSyntaxDeep(info, reg, strings.TrimSuffix(raw, "[]"), false, pos, seen)
822
+ }
823
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
824
+ return hasPreferredTypiaBlockerSyntaxInParts(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), false, pos, seen)
825
+ }
826
+ if isObjectLiteralTypeText(raw) {
827
+ body := strings.TrimSpace(raw[1 : len(raw)-1])
828
+ for _, prop := range propertiesFromBody(body) {
829
+ if hasPreferredTypiaBlockerSyntaxDeep(info, reg, prop.typeText, false, pos, seen) {
830
+ return true
831
+ }
832
+ }
833
+ if indexType, ok := indexSignatureType(body); ok {
834
+ return hasPreferredTypiaBlockerSyntaxDeep(info, reg, indexType, false, pos, seen)
835
+ }
836
+ return false
837
+ }
838
+ if strings.Contains(raw, "[") || strings.Contains(raw, "]") {
839
+ return false
840
+ }
841
+ if name, args, ok := generic(raw); ok {
842
+ if (name == "Pattern" || name == "Validate") && (len(args) == 0 || !isLiteralStringType(args[0])) {
843
+ return true
844
+ }
845
+ if name == "TsfValidatorTag" && len(args) > 0 && literalStringValue(args[0]) == "object" {
846
+ return true
847
+ }
848
+ if isPreferredTypiaHardBlockerName(name) || (root && isRootInternalMetadataName(name)) {
849
+ return true
850
+ }
851
+ if ref, ok := info.imports[name]; ok && isFoundationImportRef(ref) {
852
+ return false
853
+ }
854
+ if isInternalUtilityObjectTypeName(name) {
855
+ ctx := &typeContext{seen: map[string]bool{}}
856
+ if props, owner, ok := utilityTypeProperties(info, reg, name, args, ctx); ok {
857
+ for _, prop := range props {
858
+ propOwner := owner
859
+ if prop.owner != nil {
860
+ propOwner = prop.owner
861
+ }
862
+ propPos := pos
863
+ if prop.typeNode != nil {
864
+ propPos = prop.typeNode.Pos()
865
+ }
866
+ if hasPreferredTypiaBlockerSyntaxDeep(propOwner, reg, prop.typeText, false, propPos, seen) {
867
+ return true
868
+ }
869
+ }
870
+ return false
871
+ }
872
+ }
873
+ if alias, owner, _, ok := resolveAliasRef(info, reg, name); ok {
874
+ body := alias.body
875
+ for i := range alias.params {
876
+ body = replaceTypeParameter(body, aliasParamName(alias, i), aliasArg(alias, args, i))
877
+ }
878
+ if hasPreferredTypiaBlockerSyntaxDeep(owner, reg, body, root, alias.pos, seen) {
879
+ return true
880
+ }
881
+ }
882
+ for i, arg := range args {
883
+ if (name == "Pick" || name == "Omit") && i > 0 {
884
+ continue
885
+ }
886
+ if hasPreferredTypiaBlockerSyntaxDeep(info, reg, arg, false, pos, seen) {
887
+ return true
888
+ }
889
+ }
890
+ return false
891
+ }
892
+ if isIdentifierName(raw) {
893
+ if alias, owner, _, ok := resolveAliasRef(info, reg, raw); ok {
894
+ return hasPreferredTypiaBlockerSyntaxDeep(owner, reg, alias.body, root, alias.pos, seen)
895
+ }
896
+ if decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, raw, pos); ok {
897
+ body := interfaceFullBody(owner, reg, decl, map[string]bool{})
898
+ return hasPreferredTypiaBlockerSyntaxDeep(owner, reg, "{"+body+"}", false, decl.pos, seen)
899
+ }
900
+ if class, owner, ok := resolveClassRefAt(info, reg, raw, pos); ok {
901
+ for _, prop := range class.properties {
902
+ propPos := pos
903
+ if prop.typeNode != nil {
904
+ propPos = prop.typeNode.Pos()
905
+ }
906
+ if hasPreferredTypiaBlockerSyntaxDeep(owner, reg, prop.typeText, false, propPos, seen) {
907
+ return true
908
+ }
909
+ }
910
+ }
911
+ }
912
+ return false
913
+ }
914
+
915
+ func isInternalUtilityObjectTypeName(name string) bool {
916
+ switch name {
917
+ case "Pick", "Omit", "Partial", "Required":
918
+ return true
919
+ default:
920
+ return false
921
+ }
922
+ }
923
+
924
+ func hasPreferredTypiaBlockerSyntaxInParts(info *fileInfo, reg *registry, parts []string, root bool, pos int, seen map[string]bool) bool {
925
+ for _, part := range parts {
926
+ if hasPreferredTypiaBlockerSyntaxDeep(info, reg, part, root, pos, seen) {
927
+ return true
928
+ }
929
+ }
930
+ return false
931
+ }
932
+
933
+ func nonNullishTypeParts(parts []string) []string {
934
+ out := []string{}
935
+ for _, part := range parts {
936
+ part = strings.TrimSpace(trimParens(part))
937
+ if part == "" || part == "null" || part == "undefined" {
938
+ continue
939
+ }
940
+ out = append(out, part)
941
+ }
942
+ return out
943
+ }
944
+
945
+ func hasRootInternalMetadataIntersectionPart(parts []string) bool {
946
+ for _, part := range parts {
947
+ name := strings.TrimSpace(trimParens(part))
948
+ if genericName, _, ok := generic(name); ok {
949
+ name = genericName
950
+ }
951
+ if isRootInternalMetadataName(name) {
952
+ return true
953
+ }
954
+ }
955
+ return false
956
+ }
957
+
958
+ func isPreferredTypiaHardBlockerName(name string) bool {
959
+ switch strings.TrimSpace(name) {
960
+ case "FileUpload":
961
+ return true
962
+ default:
963
+ return false
964
+ }
965
+ }
966
+
967
+ func isRootInternalMetadataName(name string) bool {
968
+ switch strings.TrimSpace(name) {
969
+ case "TypeAnnotation",
970
+ "ApiName",
971
+ "ApiType",
972
+ "HttpBody",
973
+ "HttpQueries",
974
+ "HttpQuery",
975
+ "HttpPath",
976
+ "HttpHeader",
977
+ "HttpRequest",
978
+ "HttpRequestStream",
979
+ "HttpResponse",
980
+ "ParsedJwt",
981
+ "JWT",
982
+ "RawResponseResult",
983
+ "Redirect",
984
+ "OkResponse",
985
+ "EmptyResponse",
986
+ "TsfDatabaseFieldTag",
987
+ "TsfDatabaseTag",
988
+ "DatabaseField",
989
+ "MySQL",
990
+ "Reference",
991
+ "Index",
992
+ "Unique",
993
+ "PrimaryKey",
994
+ "AutoIncrement":
995
+ return true
996
+ default:
997
+ return false
998
+ }
999
+ }
1000
+
1001
+ func hasFrameworkMetadataSyntaxDeep(info *fileInfo, reg *registry, raw string, seen map[string]bool) bool {
1002
+ raw = strings.TrimSpace(trimParens(raw))
1003
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
1004
+ if raw == "" || raw == "unknown" {
1005
+ return false
1006
+ }
1007
+ if isFunctionTypeSyntax(raw) {
1008
+ return true
1009
+ }
1010
+ if isFrameworkMetadataName(raw) {
1011
+ return true
1012
+ }
1013
+
1014
+ key := info.moduleKey + "\x00" + raw
1015
+ if seen[key] {
1016
+ return false
1017
+ }
1018
+ seen[key] = true
1019
+ defer delete(seen, key)
1020
+
1021
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
1022
+ if hasLiteralUnionSyntax(parts) {
1023
+ return true
1024
+ }
1025
+ if hasTaggedMetadataSyntaxInParts(info, reg, parts, seen) {
1026
+ return true
1027
+ }
1028
+ return hasFrameworkMetadataSyntaxInParts(info, reg, parts, seen)
1029
+ }
1030
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
1031
+ return hasFrameworkMetadataSyntaxInParts(info, reg, parts, seen)
1032
+ }
1033
+ if name, args, ok := generic(raw); ok {
1034
+ if (name == "Pattern" || name == "Validate") && (len(args) == 0 || !isLiteralStringType(args[0])) {
1035
+ return true
1036
+ }
1037
+ if isFrameworkMetadataName(name) {
1038
+ return true
1039
+ }
1040
+ }
1041
+ if hasTypiaPreferredSyntax(raw) {
1042
+ return false
1043
+ }
1044
+ if strings.HasSuffix(raw, "[]") {
1045
+ return hasFrameworkMetadataSyntaxDeep(info, reg, strings.TrimSuffix(raw, "[]"), seen)
1046
+ }
1047
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
1048
+ return hasFrameworkMetadataSyntaxInParts(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), seen)
1049
+ }
1050
+ if strings.Contains(raw, "[") || strings.Contains(raw, "]") {
1051
+ return true
1052
+ }
1053
+ if isObjectLiteralTypeText(raw) {
1054
+ body := strings.TrimSpace(raw[1 : len(raw)-1])
1055
+ for _, prop := range propertiesFromBody(body) {
1056
+ if hasFrameworkMetadataSyntaxDeep(info, reg, prop.typeText, seen) {
1057
+ return true
1058
+ }
1059
+ }
1060
+ return false
1061
+ }
1062
+ if name, args, ok := generic(raw); ok {
1063
+ if (name == "Pattern" || name == "Validate") && (len(args) == 0 || !isLiteralStringType(args[0])) {
1064
+ return true
1065
+ }
1066
+ if isFrameworkMetadataName(name) {
1067
+ return true
1068
+ }
1069
+ if alias, owner, _, ok := resolveAliasRef(info, reg, name); ok {
1070
+ body := alias.body
1071
+ for i := range alias.params {
1072
+ body = replaceTypeParameter(body, aliasParamName(alias, i), aliasArg(alias, args, i))
1073
+ }
1074
+ if hasFrameworkMetadataSyntaxDeep(owner, reg, body, seen) {
1075
+ return true
1076
+ }
1077
+ }
1078
+ for i, arg := range args {
1079
+ if (name == "Pick" || name == "Omit") && i > 0 {
1080
+ continue
1081
+ }
1082
+ if hasFrameworkMetadataSyntaxDeep(info, reg, arg, seen) {
1083
+ return true
1084
+ }
1085
+ }
1086
+ return false
1087
+ }
1088
+ if isIdentifierName(raw) {
1089
+ if isFoundationTypeIdentifier(info, raw) {
1090
+ return true
1091
+ }
1092
+ if alias, owner, _, ok := resolveAliasRef(info, reg, raw); ok {
1093
+ return hasFrameworkMetadataSyntaxDeep(owner, reg, alias.body, seen)
1094
+ }
1095
+ if decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, raw, 0); ok {
1096
+ body := interfaceFullBody(owner, reg, decl, map[string]bool{})
1097
+ return hasFrameworkMetadataSyntaxDeep(owner, reg, "{"+body+"}", seen)
1098
+ }
1099
+ if class, owner, ok := resolveClassRefAt(info, reg, raw, 0); ok {
1100
+ for _, prop := range class.properties {
1101
+ if hasFrameworkMetadataSyntaxDeep(owner, reg, prop.typeText, seen) {
1102
+ return true
1103
+ }
1104
+ }
1105
+ }
1106
+ }
1107
+ return false
1108
+ }
1109
+
1110
+ func hasTaggedMetadataSyntaxInParts(info *fileInfo, reg *registry, parts []string, seen map[string]bool) bool {
1111
+ for _, part := range parts {
1112
+ part = strings.TrimSpace(trimParens(part))
1113
+ if part == "null" || part == "undefined" {
1114
+ continue
1115
+ }
1116
+ if hasTaggedMetadataSyntaxDeep(info, reg, part, seen) {
1117
+ return true
1118
+ }
1119
+ }
1120
+ return false
1121
+ }
1122
+
1123
+ func hasTaggedMetadataSyntaxDeep(info *fileInfo, reg *registry, raw string, seen map[string]bool) bool {
1124
+ raw = strings.TrimSpace(trimParens(raw))
1125
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
1126
+ if raw == "" || raw == "unknown" {
1127
+ return false
1128
+ }
1129
+ if hasTypiaPreferredSyntax(raw) || isFrameworkMetadataName(raw) {
1130
+ return true
1131
+ }
1132
+ key := info.moduleKey + "\x00tagged\x00" + raw
1133
+ if seen[key] {
1134
+ return false
1135
+ }
1136
+ seen[key] = true
1137
+ defer delete(seen, key)
1138
+
1139
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
1140
+ return hasTaggedMetadataSyntaxInParts(info, reg, parts, seen)
1141
+ }
1142
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
1143
+ return hasTaggedMetadataSyntaxInParts(info, reg, parts, seen)
1144
+ }
1145
+ if strings.HasSuffix(raw, "[]") {
1146
+ return hasTaggedMetadataSyntaxDeep(info, reg, strings.TrimSuffix(raw, "[]"), seen)
1147
+ }
1148
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
1149
+ return hasTaggedMetadataSyntaxInParts(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), seen)
1150
+ }
1151
+ if isObjectLiteralTypeText(raw) {
1152
+ body := strings.TrimSpace(raw[1 : len(raw)-1])
1153
+ for _, prop := range propertiesFromBody(body) {
1154
+ if hasTaggedMetadataSyntaxDeep(info, reg, prop.typeText, seen) {
1155
+ return true
1156
+ }
1157
+ }
1158
+ return false
1159
+ }
1160
+ if name, args, ok := generic(raw); ok {
1161
+ if alias, owner, _, ok := resolveAliasRef(info, reg, name); ok {
1162
+ body := alias.body
1163
+ for i := range alias.params {
1164
+ body = replaceTypeParameter(body, aliasParamName(alias, i), aliasArg(alias, args, i))
1165
+ }
1166
+ if hasTaggedMetadataSyntaxDeep(owner, reg, body, seen) {
1167
+ return true
1168
+ }
1169
+ }
1170
+ for _, arg := range args {
1171
+ if hasTaggedMetadataSyntaxDeep(info, reg, arg, seen) {
1172
+ return true
1173
+ }
1174
+ }
1175
+ return false
1176
+ }
1177
+ if isIdentifierName(raw) {
1178
+ if alias, owner, _, ok := resolveAliasRef(info, reg, raw); ok {
1179
+ return hasTaggedMetadataSyntaxDeep(owner, reg, alias.body, seen)
1180
+ }
1181
+ if decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, raw, 0); ok {
1182
+ body := interfaceFullBody(owner, reg, decl, map[string]bool{})
1183
+ return hasTaggedMetadataSyntaxDeep(owner, reg, "{"+body+"}", seen)
1184
+ }
1185
+ if class, owner, ok := resolveClassRefAt(info, reg, raw, 0); ok {
1186
+ for _, prop := range class.properties {
1187
+ if hasTaggedMetadataSyntaxDeep(owner, reg, prop.typeText, seen) {
1188
+ return true
1189
+ }
1190
+ }
1191
+ }
1192
+ }
1193
+ return false
1194
+ }
1195
+
1196
+ func hasFrameworkMetadataSyntaxInParts(info *fileInfo, reg *registry, parts []string, seen map[string]bool) bool {
1197
+ for _, part := range parts {
1198
+ if hasFrameworkMetadataSyntaxDeep(info, reg, part, seen) {
1199
+ return true
1200
+ }
1201
+ }
1202
+ return false
1203
+ }
1204
+
1205
+ func hasLiteralUnionSyntax(parts []string) bool {
1206
+ for _, part := range parts {
1207
+ part = strings.TrimSpace(trimParens(part))
1208
+ if strings.HasPrefix(part, "\"") ||
1209
+ strings.HasPrefix(part, "'") ||
1210
+ part == "true" ||
1211
+ part == "false" {
1212
+ return true
1213
+ }
1214
+ if _, err := strconv.ParseFloat(part, 64); err == nil {
1215
+ return true
1216
+ }
1217
+ }
1218
+ return false
1219
+ }
1220
+
1221
+ func isFrameworkMetadataName(name string) bool {
1222
+ switch strings.TrimSpace(name) {
1223
+ case "TypeAnnotation",
1224
+ "ApiName",
1225
+ "ApiType",
1226
+ "HttpBody",
1227
+ "HttpQueries",
1228
+ "HttpQuery",
1229
+ "HttpPath",
1230
+ "HttpHeader",
1231
+ "HttpRequest",
1232
+ "HttpRequestStream",
1233
+ "HttpResponse",
1234
+ "ParsedJwt",
1235
+ "JWT",
1236
+ "FileUpload",
1237
+ "RawResponseResult",
1238
+ "Redirect",
1239
+ "OkResponse",
1240
+ "EmptyResponse",
1241
+ "Indexed",
1242
+ "TsfDatabaseFieldTag",
1243
+ "TsfDatabaseTag",
1244
+ "DatabaseField",
1245
+ "MySQL",
1246
+ "Reference",
1247
+ "Index",
1248
+ "Unique",
1249
+ "PrimaryKey",
1250
+ "AutoIncrement",
1251
+ "Date",
1252
+ "ValidDate":
1253
+ return true
1254
+ default:
1255
+ return false
1256
+ }
1257
+ }
1258
+
1259
+ func typiaTypeExprFromType(info *fileInfo, reg *registry, typ *shimchecker.Type, pos int, raw string) (string, bool) {
1260
+ if typ == nil || typ.IsTypeParameter() {
1261
+ return "", false
1262
+ }
1263
+ if reg.typiaCache == nil {
1264
+ reg.typiaCache = map[typiaCacheKey]string{}
1265
+ }
1266
+ if reg.typiaFailures == nil {
1267
+ reg.typiaFailures = map[*shimchecker.Type]bool{}
1268
+ }
1269
+ cacheKey := typiaCacheKey{typ: typ, moduleKey: info.moduleKey, raw: strings.TrimSpace(raw), pos: pos}
1270
+ if expr, ok := reg.typiaCache[cacheKey]; ok {
1271
+ return expr, true
1272
+ }
1273
+ if reg.typiaFailures[typ] {
1274
+ return "", false
1275
+ }
1276
+ components := schemametadata.NewMetadataCollection()
1277
+ result := typiafactories.MetadataFactory.Analyze(typiafactories.MetadataFactory_IProps{
1278
+ Checker: reg.checker,
1279
+ Options: typiafactories.MetadataFactory_IOptions{
1280
+ Absorb: true,
1281
+ Constant: true,
1282
+ Escape: true,
1283
+ },
1284
+ Components: components,
1285
+ Type: typ,
1286
+ })
1287
+ if !result.Success || result.Data == nil {
1288
+ reg.typiaFailures[typ] = true
1289
+ return "", false
1290
+ }
1291
+ expr := typiaMetadataExpr(info, reg, result.Data, true, newTypiaRenderStateForSource(pos, raw))
1292
+ reg.typiaCache[cacheKey] = expr
1293
+ return expr, true
1294
+ }
1295
+
1296
+ type typiaRenderState struct {
1297
+ metadata map[*schemametadata.MetadataSchema]bool
1298
+ aliases map[*schemametadata.MetadataAliasType]bool
1299
+ arrays map[*schemametadata.MetadataArrayType]bool
1300
+ tuples map[*schemametadata.MetadataTupleType]bool
1301
+ objects map[*schemametadata.MetadataObjectType]bool
1302
+ pos int
1303
+ sourceRaw string
1304
+ }
1305
+
1306
+ func newTypiaRenderState(pos ...int) *typiaRenderState {
1307
+ state := &typiaRenderState{
1308
+ metadata: map[*schemametadata.MetadataSchema]bool{},
1309
+ aliases: map[*schemametadata.MetadataAliasType]bool{},
1310
+ arrays: map[*schemametadata.MetadataArrayType]bool{},
1311
+ tuples: map[*schemametadata.MetadataTupleType]bool{},
1312
+ objects: map[*schemametadata.MetadataObjectType]bool{},
1313
+ }
1314
+ if len(pos) > 0 {
1315
+ state.pos = pos[0]
1316
+ }
1317
+ return state
1318
+ }
1319
+
1320
+ func newTypiaRenderStateForSource(pos int, sourceRaw string) *typiaRenderState {
1321
+ state := newTypiaRenderState(pos)
1322
+ state.sourceRaw = sourceRaw
1323
+ return state
1324
+ }
1325
+
1326
+ func typiaMetadataExpr(info *fileInfo, reg *registry, meta *schemametadata.MetadataSchema, includeOptional bool, state *typiaRenderState) string {
1327
+ if meta == nil {
1328
+ return "{kind: 2}"
1329
+ }
1330
+ if state == nil {
1331
+ state = newTypiaRenderState()
1332
+ }
1333
+ if state.metadata[meta] {
1334
+ return "{kind: 2, typeName: " + quote(meta.GetDisplayName()) + "}"
1335
+ }
1336
+ state.metadata[meta] = true
1337
+ defer delete(state.metadata, meta)
1338
+
1339
+ types := []string{}
1340
+ if meta.Any {
1341
+ types = append(types, "{kind: 1}")
1342
+ }
1343
+ if meta.Escaped != nil && meta.Escaped.Returns != nil {
1344
+ types = append(types, typiaMetadataExpr(info, reg, meta.Escaped.Returns, includeOptional, state))
1345
+ }
1346
+ if meta.Rest != nil {
1347
+ types = append(types, "{kind: 14, type: "+typiaMetadataExpr(info, reg, meta.Rest, true, state)+"}")
1348
+ }
1349
+ for _, atomic := range meta.Atomics {
1350
+ if expr, ok := typiaAtomicExpr(atomic); ok {
1351
+ types = append(types, expr)
1352
+ }
1353
+ }
1354
+ for _, constant := range meta.Constants {
1355
+ for _, value := range constant.Values {
1356
+ if value != nil {
1357
+ types = append(types, typiaTaggedExpr("{kind: 10, literal: "+typiaLiteralExpr(value.Value)+"}", value.Tags))
1358
+ }
1359
+ }
1360
+ }
1361
+ for _, template := range meta.Templates {
1362
+ if template != nil {
1363
+ types = append(types, typiaTaggedExpr("{kind: 23, typeName: "+quote(template.GetName())+"}", template.Tags))
1364
+ }
1365
+ }
1366
+ for _, array := range meta.Arrays {
1367
+ types = append(types, typiaArrayExpr(info, reg, array, state))
1368
+ }
1369
+ for _, tuple := range meta.Tuples {
1370
+ types = append(types, typiaTupleExpr(info, reg, tuple, state))
1371
+ }
1372
+ for _, object := range meta.Objects {
1373
+ types = append(types, typiaObjectExpr(info, reg, object, state))
1374
+ }
1375
+ for _, alias := range meta.Aliases {
1376
+ types = append(types, typiaAliasExpr(info, reg, alias, state))
1377
+ }
1378
+ for _, native := range meta.Natives {
1379
+ types = append(types, typiaNativeExpr(info, reg, native))
1380
+ }
1381
+ for range meta.Functions {
1382
+ types = append(types, "{kind: 21}")
1383
+ }
1384
+ for _, set := range meta.Sets {
1385
+ if set != nil && set.Value != nil {
1386
+ types = append(types, typiaTaggedExpr("{kind: 2, typeName: \"Set\", typeArguments: ["+typiaMetadataExpr(info, reg, set.Value, true, state)+"]}", set.Tags))
1387
+ }
1388
+ }
1389
+ for _, m := range meta.Maps {
1390
+ if m != nil {
1391
+ key := "{kind: 2}"
1392
+ value := "{kind: 2}"
1393
+ if m.Key != nil {
1394
+ key = typiaMetadataExpr(info, reg, m.Key, true, state)
1395
+ }
1396
+ if m.Value != nil {
1397
+ value = typiaMetadataExpr(info, reg, m.Value, true, state)
1398
+ }
1399
+ types = append(types, typiaTaggedExpr("{kind: 2, typeName: \"Map\", typeArguments: ["+key+", "+value+"]}", m.Tags))
1400
+ }
1401
+ }
1402
+ if meta.Nullable {
1403
+ types = append(types, "{kind: 5}")
1404
+ }
1405
+ if includeOptional && !meta.IsRequired() {
1406
+ types = append(types, "{kind: 4}")
1407
+ }
1408
+ if len(types) == 0 {
1409
+ if meta.Empty() && meta.Required && !meta.Nullable && !meta.Optional {
1410
+ return "{kind: 0}"
1411
+ }
1412
+ return "{kind: 2, typeName: " + quote(meta.GetDisplayName()) + "}"
1413
+ }
1414
+ return typiaUnionExpr(types)
1415
+ }
1416
+
1417
+ func typiaAtomicExpr(atomic *schemametadata.MetadataAtomic) (string, bool) {
1418
+ if atomic == nil {
1419
+ return "", false
1420
+ }
1421
+ switch atomic.Type {
1422
+ case "string":
1423
+ return typiaTaggedExpr("{kind: 6}", atomic.Tags), true
1424
+ case "number":
1425
+ return typiaTaggedExpr("{kind: 7}", atomic.Tags), true
1426
+ case "boolean":
1427
+ return typiaTaggedExpr("{kind: 8}", atomic.Tags), true
1428
+ case "bigint":
1429
+ return typiaTaggedExpr("{kind: 9}", atomic.Tags), true
1430
+ default:
1431
+ return typiaTaggedExpr("{kind: 2, typeName: "+quote(atomic.GetName())+"}", atomic.Tags), true
1432
+ }
1433
+ }
1434
+
1435
+ func typiaArrayExpr(info *fileInfo, reg *registry, array *schemametadata.MetadataArray, state *typiaRenderState) string {
1436
+ if array == nil || array.Type == nil {
1437
+ return "{kind: 14, type: {kind: 2}}"
1438
+ }
1439
+ if state.arrays[array.Type] {
1440
+ return "{kind: 14, type: {kind: 2}}"
1441
+ }
1442
+ state.arrays[array.Type] = true
1443
+ defer delete(state.arrays, array.Type)
1444
+
1445
+ value := "{kind: 2}"
1446
+ if array.Type.Value != nil {
1447
+ value = typiaMetadataExpr(info, reg, array.Type.Value, true, state)
1448
+ }
1449
+ return typiaTaggedExpr("{kind: 14, type: "+value+"}", array.Tags)
1450
+ }
1451
+
1452
+ func typiaTupleExpr(info *fileInfo, reg *registry, tuple *schemametadata.MetadataTuple, state *typiaRenderState) string {
1453
+ if tuple == nil || tuple.Type == nil {
1454
+ return "{kind: 15, types: []}"
1455
+ }
1456
+ if state.tuples[tuple.Type] {
1457
+ return "{kind: 15, typeName: " + quote(tuple.Type.GetDisplayName()) + ", types: []}"
1458
+ }
1459
+ state.tuples[tuple.Type] = true
1460
+ defer delete(state.tuples, tuple.Type)
1461
+
1462
+ items := []string{}
1463
+ for _, element := range tuple.Type.Elements {
1464
+ items = append(items, "{type: "+typiaMetadataExpr(info, reg, element, true, state)+"}")
1465
+ }
1466
+ return typiaTaggedExpr("{kind: 15, typeName: "+quote(tuple.Type.GetDisplayName())+", types: ["+strings.Join(items, ", ")+"]}", tuple.Tags)
1467
+ }
1468
+
1469
+ func typiaObjectExpr(info *fileInfo, reg *registry, object *schemametadata.MetadataObject, state *typiaRenderState) string {
1470
+ if object == nil || object.Type == nil {
1471
+ return "{kind: 18, types: []}"
1472
+ }
1473
+ obj := object.Type
1474
+ name, named := typiaObjectTypeName(info, reg, obj, state.pos)
1475
+ if named {
1476
+ if expr, ok := typiaNamedObjectInternalOverrideExpr(info, reg, name, state.pos); ok {
1477
+ return typiaTaggedExpr(expr, object.Tags)
1478
+ }
1479
+ }
1480
+ if obj.IsClass && isIdentifierName(obj.Name) {
1481
+ runtimeName := obj.Name
1482
+ if obj.ValueRef != "" {
1483
+ runtimeName = obj.ValueRef
1484
+ }
1485
+ return typiaTaggedExpr("{kind: 16, typeName: "+quote(name)+", classType: () => "+runtimeValueExpr(info, reg, runtimeName)+"}", object.Tags)
1486
+ }
1487
+ if state.objects[obj] {
1488
+ if named {
1489
+ return "{kind: 18, typeName: " + quote(name) + ", types: []}"
1490
+ }
1491
+ return "{kind: 18, types: []}"
1492
+ }
1493
+ state.objects[obj] = true
1494
+ defer delete(state.objects, obj)
1495
+
1496
+ properties := []string{}
1497
+ indexExpr := ""
1498
+ for _, prop := range obj.Properties {
1499
+ if prop == nil || prop.Key == nil || prop.Value == nil {
1500
+ continue
1501
+ }
1502
+ if expr, ok := typiaIndexPropertyExpr(info, reg, prop, state); ok {
1503
+ if indexExpr == "" {
1504
+ indexExpr = expr
1505
+ }
1506
+ continue
1507
+ }
1508
+ propName := typiaPropertyName(prop)
1509
+ if propName == "" {
1510
+ continue
1511
+ }
1512
+ optional := !prop.Value.IsRequired()
1513
+ valueExpr := typiaMetadataExpr(info, reg, prop.Value, true, state)
1514
+ overrideSources := []string{name}
1515
+ if display := strings.TrimSpace(obj.GetDisplayName()); display != "" && display != name {
1516
+ overrideSources = append(overrideSources, display)
1517
+ }
1518
+ overrideSources = append(overrideSources, state.sourceRaw)
1519
+ if override, ok := typiaSourcePropertyOverrideExpr(info, reg, "", propName, state.pos, overrideSources...); ok {
1520
+ valueExpr = override
1521
+ }
1522
+ properties = append(properties, "{kind: 20, name: "+quote(propName)+", type: "+valueExpr+", optional: "+boolLit(optional)+"}")
1523
+ }
1524
+ items := []string{"kind: 18"}
1525
+ if named {
1526
+ items = append(items, "typeName: "+quote(name))
1527
+ }
1528
+ if indexExpr != "" {
1529
+ items = append(items, "index: "+indexExpr)
1530
+ }
1531
+ items = append(items, "types: ["+strings.Join(properties, ", ")+"]")
1532
+ return typiaTaggedExpr("{"+strings.Join(items, ", ")+"}", object.Tags)
1533
+ }
1534
+
1535
+ func typiaNamedObjectInternalOverrideExpr(info *fileInfo, reg *registry, name string, pos int) (string, bool) {
1536
+ name = strings.TrimSpace(name)
1537
+ if !isIdentifierName(name) {
1538
+ return "", false
1539
+ }
1540
+ internalExpr := typeExprCtx(info, reg, name, &typeContext{seen: map[string]bool{}, pos: pos})
1541
+ if decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, name, pos); ok {
1542
+ if sourcePropertiesNeedInternalObjectMetadata(owner, reg, interfaceFullProperties(owner, reg, decl, map[string]bool{}), pos) {
1543
+ return internalExpr, true
1544
+ }
1545
+ }
1546
+ if alias, owner, _, ok := resolveAliasRef(info, reg, name); ok && len(alias.params) == 0 {
1547
+ if sourceObjectTextNeedsInternalObjectMetadata(owner, reg, alias.body, pos) {
1548
+ return internalExpr, true
1549
+ }
1550
+ }
1551
+ if isResolvedInternalNamedObjectExpr(internalExpr, name) && internalObjectExprCarriesSourceMetadata(internalExpr) {
1552
+ return internalExpr, true
1553
+ }
1554
+ return "", false
1555
+ }
1556
+
1557
+ func isResolvedInternalNamedObjectExpr(expr string, name string) bool {
1558
+ expr = strings.TrimSpace(expr)
1559
+ return strings.Contains(expr, "kind: 18") &&
1560
+ strings.Contains(expr, "typeName: "+quote(name)) &&
1561
+ !isUnresolvedInternalTypeExpr(expr, name)
1562
+ }
1563
+
1564
+ func internalObjectExprCarriesSourceMetadata(expr string) bool {
1565
+ return strings.Contains(expr, "literal:") ||
1566
+ strings.Contains(expr, "classType: () => Date") ||
1567
+ strings.Contains(expr, "annotations:")
1568
+ }
1569
+
1570
+ func sourceObjectTextNeedsInternalObjectMetadata(info *fileInfo, reg *registry, raw string, pos int) bool {
1571
+ raw = strings.TrimSpace(trimParens(raw))
1572
+ if isObjectLiteralTypeText(raw) {
1573
+ return sourcePropertiesNeedInternalObjectMetadata(info, reg, propertiesFromBody(strings.TrimSpace(raw[1:len(raw)-1])), pos)
1574
+ }
1575
+ return sourceTypeContainsIndexedAccessSyntax(raw, map[string]bool{})
1576
+ }
1577
+
1578
+ func sourcePropertiesNeedInternalObjectMetadata(info *fileInfo, reg *registry, props []utilityProperty, pos int) bool {
1579
+ for _, prop := range props {
1580
+ if sourceTypeContainsIndexedAccessSyntax(prop.typeText, map[string]bool{}) {
1581
+ return true
1582
+ }
1583
+ if sourceTypeNeedsInternalPropertyMetadata(info, reg, prop.typeText, &typeContext{seen: map[string]bool{}, pos: pos}, map[string]bool{}) {
1584
+ return true
1585
+ }
1586
+ }
1587
+ return false
1588
+ }
1589
+
1590
+ func typiaObjectTypeName(info *fileInfo, reg *registry, obj *schemametadata.MetadataObjectType, pos int) (string, bool) {
1591
+ name := strings.TrimSpace(obj.GetDisplayName())
1592
+ if name == "" || isAnonymousTypiaObjectName(name) {
1593
+ return "", false
1594
+ }
1595
+ if obj.IsClass && isIdentifierName(obj.Name) {
1596
+ return name, true
1597
+ }
1598
+ if genericName, _, ok := generic(name); ok && isIdentifierName(genericName) {
1599
+ return name, true
1600
+ }
1601
+ if isIdentifierName(name) || typiaObjectNameIsDeclared(info, reg, name, pos) || typiaObjectNameIsUtilityDisplay(name) {
1602
+ return name, true
1603
+ }
1604
+ if obj.DisplayName != "" {
1605
+ return "", false
1606
+ }
1607
+ rawName := strings.TrimSpace(obj.Name)
1608
+ if rawName != "" && rawName != name && typiaObjectNameIsDeclared(info, reg, rawName, pos) {
1609
+ return name, true
1610
+ }
1611
+ return "", false
1612
+ }
1613
+
1614
+ func isAnonymousTypiaObjectName(name string) bool {
1615
+ name = strings.TrimSpace(name)
1616
+ return name == "" || strings.HasPrefix(name, "{") || strings.HasPrefix(name, "__")
1617
+ }
1618
+
1619
+ func typiaObjectNameIsDeclared(info *fileInfo, reg *registry, name string, pos int) bool {
1620
+ if !isIdentifierName(name) {
1621
+ return false
1622
+ }
1623
+ if _, _, _, ok := resolveAliasRef(info, reg, name); ok {
1624
+ return true
1625
+ }
1626
+ if _, _, _, ok := resolveInterfaceDeclRefAt(info, reg, name, pos); ok {
1627
+ return true
1628
+ }
1629
+ if _, _, ok := resolveClassRefAt(info, reg, name, pos); ok {
1630
+ return true
1631
+ }
1632
+ if ref, ok := info.imports[name]; ok {
1633
+ return isFoundationImportRef(ref)
1634
+ }
1635
+ return false
1636
+ }
1637
+
1638
+ func typiaObjectNameIsUtilityDisplay(name string) bool {
1639
+ if genericName, _, ok := generic(name); ok {
1640
+ name = genericName
1641
+ }
1642
+ switch strings.TrimSpace(name) {
1643
+ case "Pick", "Omit", "Partial", "Required", "Readonly", "OptionalNulls", "Record":
1644
+ return true
1645
+ default:
1646
+ return false
1647
+ }
1648
+ }
1649
+
1650
+ func typiaSourcePropertyOverrideExpr(info *fileInfo, reg *registry, sourceName string, propName string, pos int, alternateSources ...string) (string, bool) {
1651
+ sourceName = strings.TrimSpace(sourceName)
1652
+ propName = strings.TrimSpace(propName)
1653
+ if propName == "" {
1654
+ return "", false
1655
+ }
1656
+ sources := []string{sourceName}
1657
+ sources = append(sources, alternateSources...)
1658
+ for _, source := range sources {
1659
+ source = strings.TrimSpace(source)
1660
+ if source == "" {
1661
+ continue
1662
+ }
1663
+ ctx := &typeContext{seen: map[string]bool{}, pos: pos}
1664
+ propType, owner, ok := propertyTypeText(info, reg, source, propName, ctx)
1665
+ if !ok {
1666
+ continue
1667
+ }
1668
+ propType = strings.TrimSpace(propType)
1669
+ valueExpr := typeExprCtx(owner, reg, propType, &typeContext{seen: map[string]bool{}, pos: pos})
1670
+ if sourceTypeContainsIndexedAccessSyntax(propType, map[string]bool{}) && !isUnresolvedInternalTypeExpr(valueExpr, propType) {
1671
+ return valueExpr, true
1672
+ }
1673
+ if !sourceTypeNeedsInternalPropertyMetadata(owner, reg, propType, &typeContext{seen: map[string]bool{}, pos: pos}, map[string]bool{}) &&
1674
+ !typeContainsAliasReference(owner, reg, propType, map[string]bool{}) {
1675
+ continue
1676
+ }
1677
+ return valueExpr, true
1678
+ }
1679
+ return "", false
1680
+ }
1681
+
1682
+ func isUnresolvedInternalTypeExpr(expr string, raw string) bool {
1683
+ return strings.TrimSpace(expr) == "{kind: 2, typeName: "+quote(strings.TrimSpace(raw))+"}"
1684
+ }
1685
+
1686
+ func sourceTypeContainsIndexedAccessSyntax(raw string, seen map[string]bool) bool {
1687
+ raw = strings.TrimSpace(trimParens(raw))
1688
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
1689
+ if raw == "" {
1690
+ return false
1691
+ }
1692
+ key := raw
1693
+ if seen[key] {
1694
+ return false
1695
+ }
1696
+ seen[key] = true
1697
+
1698
+ if _, _, ok := trailingIndexedAccess(raw); ok {
1699
+ return true
1700
+ }
1701
+ for _, sep := range []string{"|", "&"} {
1702
+ if parts := nonEmptyParts(splitTop(raw, sep)); len(parts) > 1 {
1703
+ for _, part := range parts {
1704
+ if sourceTypeContainsIndexedAccessSyntax(part, seen) {
1705
+ return true
1706
+ }
1707
+ }
1708
+ return false
1709
+ }
1710
+ }
1711
+ if strings.HasSuffix(raw, "[]") {
1712
+ return sourceTypeContainsIndexedAccessSyntax(strings.TrimSuffix(raw, "[]"), seen)
1713
+ }
1714
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
1715
+ for _, part := range splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ",") {
1716
+ if sourceTypeContainsIndexedAccessSyntax(part, seen) {
1717
+ return true
1718
+ }
1719
+ }
1720
+ return false
1721
+ }
1722
+ if isObjectLiteralTypeText(raw) {
1723
+ for _, prop := range propertiesFromBody(strings.TrimSpace(raw[1 : len(raw)-1])) {
1724
+ if sourceTypeContainsIndexedAccessSyntax(prop.typeText, seen) {
1725
+ return true
1726
+ }
1727
+ }
1728
+ return false
1729
+ }
1730
+ if _, args, ok := generic(raw); ok {
1731
+ for _, arg := range args {
1732
+ if sourceTypeContainsIndexedAccessSyntax(arg, seen) {
1733
+ return true
1734
+ }
1735
+ }
1736
+ }
1737
+ return false
1738
+ }
1739
+
1740
+ func sourceTypeNeedsInternalPropertyMetadata(info *fileInfo, reg *registry, raw string, ctx *typeContext, seen map[string]bool) bool {
1741
+ return sourceTypeContainsDateType(info, reg, raw, ctx, seen) ||
1742
+ sourceTypeContainsOrderedLiteralUnion(info, reg, raw, ctx, map[string]bool{}) ||
1743
+ typeContainsExternalImportReference(info, reg, raw, map[string]bool{}) ||
1744
+ sourceTypeContainsInternalMetadata(info, reg, raw, ctx, map[string]bool{})
1745
+ }
1746
+
1747
+ func sourceTypeContainsOrderedLiteralUnion(info *fileInfo, reg *registry, raw string, ctx *typeContext, seen map[string]bool) bool {
1748
+ raw = strings.TrimSpace(trimParens(raw))
1749
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
1750
+ if raw == "" {
1751
+ return false
1752
+ }
1753
+ if isIdentifierName(raw) && isFoundationTypeIdentifier(info, raw) {
1754
+ return true
1755
+ }
1756
+ if ctx == nil {
1757
+ ctx = &typeContext{seen: map[string]bool{}}
1758
+ }
1759
+ key := info.moduleKey + "\x00literal-union-source\x00" + raw
1760
+ if seen[key] {
1761
+ return false
1762
+ }
1763
+ seen[key] = true
1764
+
1765
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
1766
+ nonNullish := nonNullishTypeParts(parts)
1767
+ if len(nonNullish) > 1 && hasLiteralUnionSyntax(nonNullish) {
1768
+ return true
1769
+ }
1770
+ return sourcePartsContainOrderedLiteralUnion(info, reg, parts, ctx, seen)
1771
+ }
1772
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
1773
+ return sourcePartsContainOrderedLiteralUnion(info, reg, parts, ctx, seen)
1774
+ }
1775
+ if strings.HasSuffix(raw, "[]") {
1776
+ return sourceTypeContainsOrderedLiteralUnion(info, reg, strings.TrimSuffix(raw, "[]"), ctx, seen)
1777
+ }
1778
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
1779
+ return sourcePartsContainOrderedLiteralUnion(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), ctx, seen)
1780
+ }
1781
+ if isObjectLiteralTypeText(raw) {
1782
+ for _, prop := range propertiesFromBody(strings.TrimSpace(raw[1 : len(raw)-1])) {
1783
+ if sourceTypeContainsOrderedLiteralUnion(info, reg, prop.typeText, ctx, seen) {
1784
+ return true
1785
+ }
1786
+ }
1787
+ return false
1788
+ }
1789
+ if name, args, ok := generic(raw); ok {
1790
+ for i, arg := range args {
1791
+ if (name == "Pick" || name == "Omit") && i > 0 {
1792
+ continue
1793
+ }
1794
+ if sourceTypeContainsOrderedLiteralUnion(info, reg, arg, ctx, seen) {
1795
+ return true
1796
+ }
1797
+ }
1798
+ }
1799
+ if resolved, owner, ok := resolveTypeText(info, reg, raw, ctx); ok && strings.TrimSpace(resolved) != raw {
1800
+ return sourceTypeContainsOrderedLiteralUnion(owner, reg, resolved, ctx, seen)
1801
+ }
1802
+ return false
1803
+ }
1804
+
1805
+ func sourcePartsContainOrderedLiteralUnion(info *fileInfo, reg *registry, parts []string, ctx *typeContext, seen map[string]bool) bool {
1806
+ for _, part := range parts {
1807
+ if sourceTypeContainsOrderedLiteralUnion(info, reg, part, ctx, seen) {
1808
+ return true
1809
+ }
1810
+ }
1811
+ return false
1812
+ }
1813
+
1814
+ func sourceTypeContainsInternalMetadata(info *fileInfo, reg *registry, raw string, ctx *typeContext, seen map[string]bool) bool {
1815
+ raw = strings.TrimSpace(trimParens(raw))
1816
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
1817
+ if raw == "" {
1818
+ return false
1819
+ }
1820
+ if ctx == nil {
1821
+ ctx = &typeContext{seen: map[string]bool{}}
1822
+ }
1823
+ key := info.moduleKey + "\x00internal-metadata-source\x00" + raw
1824
+ if seen[key] {
1825
+ return false
1826
+ }
1827
+ seen[key] = true
1828
+
1829
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
1830
+ return sourcePartsContainInternalMetadata(info, reg, parts, ctx, seen)
1831
+ }
1832
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
1833
+ return sourcePartsContainInternalMetadata(info, reg, parts, ctx, seen)
1834
+ }
1835
+ if strings.HasSuffix(raw, "[]") {
1836
+ return sourceTypeContainsInternalMetadata(info, reg, strings.TrimSuffix(raw, "[]"), ctx, seen)
1837
+ }
1838
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
1839
+ return sourcePartsContainInternalMetadata(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), ctx, seen)
1840
+ }
1841
+ if isObjectLiteralTypeText(raw) {
1842
+ for _, prop := range propertiesFromBody(strings.TrimSpace(raw[1 : len(raw)-1])) {
1843
+ if sourceTypeContainsInternalMetadata(info, reg, prop.typeText, ctx, seen) {
1844
+ return true
1845
+ }
1846
+ }
1847
+ return false
1848
+ }
1849
+ if name, args, ok := generic(raw); ok {
1850
+ if isInternalPropertyMetadataName(name) || isInternalPropertyMetadataTypiaTag(name, args) {
1851
+ return true
1852
+ }
1853
+ for i, arg := range args {
1854
+ if (name == "Pick" || name == "Omit") && i > 0 {
1855
+ continue
1856
+ }
1857
+ if sourceTypeContainsInternalMetadata(info, reg, arg, ctx, seen) {
1858
+ return true
1859
+ }
1860
+ }
1861
+ }
1862
+ if resolved, owner, ok := resolveTypeText(info, reg, raw, ctx); ok && strings.TrimSpace(resolved) != raw {
1863
+ return sourceTypeContainsInternalMetadata(owner, reg, resolved, ctx, seen)
1864
+ }
1865
+ return false
1866
+ }
1867
+
1868
+ func sourcePartsContainInternalMetadata(info *fileInfo, reg *registry, parts []string, ctx *typeContext, seen map[string]bool) bool {
1869
+ for _, part := range parts {
1870
+ if sourceTypeContainsInternalMetadata(info, reg, part, ctx, seen) {
1871
+ return true
1872
+ }
1873
+ }
1874
+ return false
1875
+ }
1876
+
1877
+ func isInternalPropertyMetadataName(name string) bool {
1878
+ switch strings.TrimSpace(name) {
1879
+ case "TypeAnnotation",
1880
+ "ApiName",
1881
+ "ApiType",
1882
+ "TsfDatabaseFieldTag",
1883
+ "TsfDatabaseTag",
1884
+ "DatabaseField",
1885
+ "MySQL":
1886
+ return true
1887
+ default:
1888
+ return false
1889
+ }
1890
+ }
1891
+
1892
+ func isInternalPropertyMetadataTypiaTag(name string, args []string) bool {
1893
+ name = strings.TrimSpace(name)
1894
+ if name == "Validate" {
1895
+ return true
1896
+ }
1897
+ if name == "TsfValidatorTag" && len(args) > 0 && literalStringValue(args[0]) == "object" {
1898
+ return true
1899
+ }
1900
+ return false
1901
+ }
1902
+
1903
+ func sourceTypeContainsDateType(info *fileInfo, reg *registry, raw string, ctx *typeContext, seen map[string]bool) bool {
1904
+ raw = strings.TrimSpace(trimParens(raw))
1905
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
1906
+ if raw == "" {
1907
+ return false
1908
+ }
1909
+ if raw == "Date" || (raw == "ValidDate" && isFoundationTypeIdentifier(info, raw)) {
1910
+ return true
1911
+ }
1912
+ if ctx == nil {
1913
+ ctx = &typeContext{seen: map[string]bool{}}
1914
+ }
1915
+ key := info.moduleKey + "\x00date-source\x00" + raw
1916
+ if seen[key] {
1917
+ return false
1918
+ }
1919
+ seen[key] = true
1920
+
1921
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
1922
+ return sourcePartsContainDateType(info, reg, parts, ctx, seen)
1923
+ }
1924
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
1925
+ return sourcePartsContainDateType(info, reg, parts, ctx, seen)
1926
+ }
1927
+ if strings.HasSuffix(raw, "[]") {
1928
+ return sourceTypeContainsDateType(info, reg, strings.TrimSuffix(raw, "[]"), ctx, seen)
1929
+ }
1930
+ if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
1931
+ return sourcePartsContainDateType(info, reg, splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","), ctx, seen)
1932
+ }
1933
+ if isObjectLiteralTypeText(raw) {
1934
+ for _, prop := range propertiesFromBody(strings.TrimSpace(raw[1 : len(raw)-1])) {
1935
+ if sourceTypeContainsDateType(info, reg, prop.typeText, ctx, seen) {
1936
+ return true
1937
+ }
1938
+ }
1939
+ return false
1940
+ }
1941
+ if name, args, ok := generic(raw); ok {
1942
+ if name == "Date" {
1943
+ return true
1944
+ }
1945
+ for _, arg := range args {
1946
+ if sourceTypeContainsDateType(info, reg, arg, ctx, seen) {
1947
+ return true
1948
+ }
1949
+ }
1950
+ }
1951
+ if resolved, owner, ok := resolveTypeText(info, reg, raw, ctx); ok && strings.TrimSpace(resolved) != raw {
1952
+ return sourceTypeContainsDateType(owner, reg, resolved, ctx, seen)
1953
+ }
1954
+ return false
1955
+ }
1956
+
1957
+ func sourceTypeIsDateRootType(info *fileInfo, reg *registry, raw string, ctx *typeContext, seen map[string]bool) bool {
1958
+ raw = strings.TrimSpace(trimParens(raw))
1959
+ raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
1960
+ if raw == "" {
1961
+ return false
1962
+ }
1963
+ if raw == "Date" || (raw == "ValidDate" && isFoundationTypeIdentifier(info, raw)) {
1964
+ return true
1965
+ }
1966
+ if ctx == nil {
1967
+ ctx = &typeContext{seen: map[string]bool{}}
1968
+ }
1969
+ key := info.moduleKey + "\x00date-root\x00" + raw
1970
+ if seen[key] {
1971
+ return false
1972
+ }
1973
+ seen[key] = true
1974
+
1975
+ if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
1976
+ nonNullish := nonNullishTypeParts(parts)
1977
+ if len(nonNullish) == 0 {
1978
+ return false
1979
+ }
1980
+ for _, part := range nonNullish {
1981
+ if !sourceTypeIsDateRootType(info, reg, part, ctx, seen) {
1982
+ return false
1983
+ }
1984
+ }
1985
+ return true
1986
+ }
1987
+ if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
1988
+ hasDate := false
1989
+ for _, part := range parts {
1990
+ if sourceTypeIsDateRootType(info, reg, part, ctx, seen) {
1991
+ hasDate = true
1992
+ continue
1993
+ }
1994
+ if isMetadataOnlyIntersectionPart(part) {
1995
+ continue
1996
+ }
1997
+ return false
1998
+ }
1999
+ return hasDate
2000
+ }
2001
+ if name, args, ok := generic(raw); ok {
2002
+ if name == "Date" || (name == "ValidDate" && isFoundationTypeIdentifier(info, name)) {
2003
+ return true
2004
+ }
2005
+ if name == "NonNullable" {
2006
+ return sourceTypeIsDateRootType(info, reg, firstArg(args), ctx, seen)
2007
+ }
2008
+ }
2009
+ if resolved, owner, ok := resolveTypeText(info, reg, raw, ctx); ok && strings.TrimSpace(resolved) != raw {
2010
+ return sourceTypeIsDateRootType(owner, reg, resolved, ctx, seen)
2011
+ }
2012
+ return false
2013
+ }
2014
+
2015
+ func isFoundationTypeIdentifier(info *fileInfo, name string) bool {
2016
+ ref, ok := info.imports[name]
2017
+ return ok && isFoundationImportRef(ref)
2018
+ }
2019
+
2020
+ func sourcePartsContainDateType(info *fileInfo, reg *registry, parts []string, ctx *typeContext, seen map[string]bool) bool {
2021
+ for _, part := range parts {
2022
+ if sourceTypeContainsDateType(info, reg, part, ctx, seen) {
2023
+ return true
2024
+ }
2025
+ }
2026
+ return false
2027
+ }
2028
+
2029
+ func typiaIndexPropertyExpr(info *fileInfo, reg *registry, prop *schemametadata.MetadataProperty, state *typiaRenderState) (string, bool) {
2030
+ if prop == nil || prop.Key == nil || prop.Value == nil || prop.Key.GetSoleLiteral() != nil {
2031
+ return "", false
2032
+ }
2033
+ if prop.Key.Any ||
2034
+ prop.Key.Escaped != nil ||
2035
+ prop.Key.Rest != nil ||
2036
+ len(prop.Key.Templates) != 0 ||
2037
+ len(prop.Key.Constants) != 0 ||
2038
+ len(prop.Key.Arrays) != 0 ||
2039
+ len(prop.Key.Tuples) != 0 ||
2040
+ len(prop.Key.Objects) != 0 ||
2041
+ len(prop.Key.Aliases) != 0 ||
2042
+ len(prop.Key.Natives) != 0 ||
2043
+ len(prop.Key.Sets) != 0 ||
2044
+ len(prop.Key.Maps) != 0 ||
2045
+ len(prop.Key.Functions) != 0 ||
2046
+ len(prop.Key.Atomics) != 1 {
2047
+ return "", false
2048
+ }
2049
+ switch prop.Key.Atomics[0].Type {
2050
+ case "string", "number":
2051
+ return typiaMetadataExpr(info, reg, prop.Value, true, state), true
2052
+ default:
2053
+ return "", false
2054
+ }
2055
+ }
2056
+
2057
+ func typiaAliasExpr(info *fileInfo, reg *registry, alias *schemametadata.MetadataAlias, state *typiaRenderState) string {
2058
+ if alias == nil || alias.Type == nil {
2059
+ return "{kind: 2}"
2060
+ }
2061
+ if state.aliases[alias.Type] {
2062
+ return "{kind: 2, typeName: " + quote(alias.GetDisplayName()) + "}"
2063
+ }
2064
+ state.aliases[alias.Type] = true
2065
+ defer delete(state.aliases, alias.Type)
2066
+
2067
+ if alias.Type.Value == nil {
2068
+ return "{kind: 2, typeName: " + quote(alias.GetDisplayName()) + "}"
2069
+ }
2070
+ return typiaTaggedExpr(withTypeName(typiaMetadataExpr(info, reg, alias.Type.Value, true, state), alias.GetDisplayName()), alias.Tags)
2071
+ }
2072
+
2073
+ func typiaNativeExpr(info *fileInfo, reg *registry, native *schemametadata.MetadataNative) string {
2074
+ if native == nil {
2075
+ return "{kind: 2}"
2076
+ }
2077
+ name := native.Name
2078
+ if name == "" {
2079
+ name = native.GetName()
2080
+ }
2081
+ if isIdentifierName(name) {
2082
+ return typiaTaggedExpr("{kind: 16, typeName: "+quote(native.GetName())+", classType: () => "+runtimeValueExpr(info, reg, name)+"}", native.Tags)
2083
+ }
2084
+ return typiaTaggedExpr("{kind: 2, typeName: "+quote(native.GetName())+"}", native.Tags)
2085
+ }
2086
+
2087
+ func typiaTaggedExpr(base string, tags [][]schemametadata.IMetadataTypeTag) string {
2088
+ markers := typiaTagMarkerExprs(tags)
2089
+ if len(markers) == 0 {
2090
+ return base
2091
+ }
2092
+ types := append([]string{base}, markers...)
2093
+ return "{kind: 13, types: [" + strings.Join(types, ", ") + "]}"
2094
+ }
2095
+
2096
+ func typiaTagMarkerExprs(tags [][]schemametadata.IMetadataTypeTag) []string {
2097
+ out := []string{}
2098
+ seen := map[string]bool{}
2099
+ for _, row := range tags {
2100
+ for _, tag := range row {
2101
+ expr := typiaTagMarkerExpr(tag)
2102
+ if expr == "" || seen[expr] {
2103
+ continue
2104
+ }
2105
+ seen[expr] = true
2106
+ out = append(out, expr)
2107
+ }
2108
+ }
2109
+ return out
2110
+ }
2111
+
2112
+ func typiaTagMarkerExpr(tag schemametadata.IMetadataTypeTag) string {
2113
+ switch tag.Kind {
2114
+ case "minLength":
2115
+ return validationMarker("MinLength", "minLength", typiaNumericTagValueTypeExpr(tag.Value))
2116
+ case "maxLength":
2117
+ return validationMarker("MaxLength", "maxLength", typiaNumericTagValueTypeExpr(tag.Value))
2118
+ case "minimum":
2119
+ return validationMarker("Minimum", "minimum", typiaNumericTagValueTypeExpr(tag.Value))
2120
+ case "greaterThan":
2121
+ return validationMarker("GreaterThan", "greaterThan", typiaNumericTagValueTypeExpr(tag.Value))
2122
+ case "maximum":
2123
+ return validationMarker("Maximum", "maximum", typiaNumericTagValueTypeExpr(tag.Value))
2124
+ case "lessThan":
2125
+ return validationMarker("LessThan", "lessThan", typiaNumericTagValueTypeExpr(tag.Value))
2126
+ case "pattern":
2127
+ return validationMarker("Pattern", "pattern", typiaTagValueTypeExpr(tag.Value))
2128
+ case "format":
2129
+ if pattern := typiaFormatPatternArg(fmt.Sprint(tag.Value)); pattern != "" {
2130
+ return validationMarker("Format", "pattern", pattern)
2131
+ }
2132
+ return ""
2133
+ case "database:field":
2134
+ return "{kind: 2, typeName: \"DatabaseField\", database: {\"*\": " + typiaTagPayloadPlainValueExpr(tag) + "}}"
2135
+ case "database:mysql":
2136
+ return "{kind: 2, typeName: \"MySQL\", database: {mysql: " + typiaTagPayloadPlainValueExpr(tag) + "}}"
2137
+ case "database:primaryKey":
2138
+ return "{kind: 2, typeName: \"PrimaryKey\"}"
2139
+ case "database:autoIncrement":
2140
+ return "{kind: 2, typeName: \"AutoIncrement\"}"
2141
+ case "database:reference":
2142
+ return "{kind: 2, typeName: \"Reference\"}"
2143
+ case "database:index":
2144
+ return "{kind: 2, typeName: \"Index\"}"
2145
+ case "database:unique":
2146
+ return "{kind: 2, typeName: \"Unique\"}"
2147
+ default:
2148
+ if strings.HasPrefix(tag.Kind, "tsf:") || strings.HasPrefix(tag.Kind, "openapi:") {
2149
+ if tag.Kind == "tsf:length" {
2150
+ return typeAnnotationMarker("TypeAnnotation", tag.Kind, typiaNumericTagValueTypeExpr(tag.Value))
2151
+ }
2152
+ if tag.Kind == "tsf:validator" {
2153
+ return validationMarker("Validator", "validator", typiaTagValueTypeExpr(tag.Value))
2154
+ }
2155
+ return typeAnnotationMarker("TypeAnnotation", tag.Kind, typiaTagValueTypeExpr(tag.Value))
2156
+ }
2157
+ return ""
2158
+ }
2159
+ }
2160
+
2161
+ func typiaFormatPatternArg(format string) string {
2162
+ switch format {
2163
+ case "date":
2164
+ return "{kind: 10, literal: \"^\\\\d{4}-\\\\d{2}-\\\\d{2}$\"}"
2165
+ case "email":
2166
+ return "{kind: 10, literal: \"^[a-zA-Z0-9_+.-]+@[a-zA-Z0-9-.]+\\\\.[a-zA-Z]+$\"}"
2167
+ case "uuid":
2168
+ return "{kind: 10, literal: \"^(?:urn:uuid:)?[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$\"}"
2169
+ default:
2170
+ return ""
2171
+ }
2172
+ }
2173
+
2174
+ func typiaTagValueTypeExpr(value any) string {
2175
+ switch v := value.(type) {
2176
+ case nil:
2177
+ return "{kind: 4}"
2178
+ case map[string]any:
2179
+ keys := make([]string, 0, len(v))
2180
+ for key := range v {
2181
+ keys = append(keys, key)
2182
+ }
2183
+ sort.Strings(keys)
2184
+ props := make([]string, 0, len(keys))
2185
+ for _, key := range keys {
2186
+ props = append(props, "{kind: 20, name: "+quote(key)+", type: "+typiaTagValueTypeExpr(v[key])+", optional: false}")
2187
+ }
2188
+ return "{kind: 18, types: [" + strings.Join(props, ", ") + "]}"
2189
+ case []any:
2190
+ items := make([]string, 0, len(v))
2191
+ for _, item := range v {
2192
+ items = append(items, "{type: "+typiaTagValueTypeExpr(item)+"}")
2193
+ }
2194
+ return "{kind: 15, types: [" + strings.Join(items, ", ") + "]}"
2195
+ default:
2196
+ return "{kind: 10, literal: " + typiaLiteralExpr(value) + "}"
2197
+ }
2198
+ }
2199
+
2200
+ func typiaNumericTagValueTypeExpr(value any) string {
2201
+ if value != nil {
2202
+ str := fmt.Sprint(value)
2203
+ if _, err := strconv.ParseFloat(str, 64); err == nil {
2204
+ return "{kind: 10, literal: " + str + "}"
2205
+ }
2206
+ }
2207
+ return typiaTagValueTypeExpr(value)
2208
+ }
2209
+
2210
+ func typiaTagPayloadPlainValueExpr(tag schemametadata.IMetadataTypeTag) string {
2211
+ if tag.Schema != nil {
2212
+ return typiaPlainValueExpr(tag.Schema)
2213
+ }
2214
+ return typiaPlainValueExpr(tag.Value)
2215
+ }
2216
+
2217
+ func typiaPlainValueExpr(value any) string {
2218
+ switch v := value.(type) {
2219
+ case nil:
2220
+ return "undefined"
2221
+ case map[string]any:
2222
+ keys := make([]string, 0, len(v))
2223
+ for key := range v {
2224
+ keys = append(keys, key)
2225
+ }
2226
+ sort.Strings(keys)
2227
+ props := make([]string, 0, len(keys))
2228
+ for _, key := range keys {
2229
+ props = append(props, quote(key)+": "+typiaPlainValueExpr(v[key]))
2230
+ }
2231
+ return "{" + strings.Join(props, ", ") + "}"
2232
+ case []any:
2233
+ items := make([]string, 0, len(v))
2234
+ for _, item := range v {
2235
+ items = append(items, typiaPlainValueExpr(item))
2236
+ }
2237
+ return "[" + strings.Join(items, ", ") + "]"
2238
+ default:
2239
+ return typiaLiteralExpr(value)
2240
+ }
2241
+ }
2242
+
2243
+ func typiaPropertyName(prop *schemametadata.MetadataProperty) string {
2244
+ if literal := prop.Key.GetSoleLiteral(); literal != nil {
2245
+ return *literal
2246
+ }
2247
+ name := strings.TrimSpace(prop.Key.GetName())
2248
+ if strings.HasPrefix(name, "\"") || strings.HasPrefix(name, "'") {
2249
+ return literalStringValue(name)
2250
+ }
2251
+ return name
2252
+ }
2253
+
2254
+ func typiaUnionExpr(types []string) string {
2255
+ out := make([]string, 0, len(types))
2256
+ seen := map[string]bool{}
2257
+ for _, typ := range types {
2258
+ typ = strings.TrimSpace(typ)
2259
+ if typ == "" || seen[typ] {
2260
+ continue
2261
+ }
2262
+ seen[typ] = true
2263
+ out = append(out, typ)
2264
+ }
2265
+ if len(out) == 0 {
2266
+ return "{kind: 2}"
2267
+ }
2268
+ if len(out) == 1 {
2269
+ return out[0]
2270
+ }
2271
+ return "{kind: 12, types: [" + strings.Join(out, ", ") + "]}"
2272
+ }
2273
+
2274
+ func typiaLiteralExpr(value any) string {
2275
+ switch v := value.(type) {
2276
+ case nil:
2277
+ return "null"
2278
+ case string:
2279
+ return quote(v)
2280
+ case bool:
2281
+ return boolLit(v)
2282
+ case int:
2283
+ return strconv.Itoa(v)
2284
+ case int8:
2285
+ return strconv.FormatInt(int64(v), 10)
2286
+ case int16:
2287
+ return strconv.FormatInt(int64(v), 10)
2288
+ case int32:
2289
+ return strconv.FormatInt(int64(v), 10)
2290
+ case int64:
2291
+ return strconv.FormatInt(v, 10)
2292
+ case uint:
2293
+ return strconv.FormatUint(uint64(v), 10)
2294
+ case uint8:
2295
+ return strconv.FormatUint(uint64(v), 10)
2296
+ case uint16:
2297
+ return strconv.FormatUint(uint64(v), 10)
2298
+ case uint32:
2299
+ return strconv.FormatUint(uint64(v), 10)
2300
+ case uint64:
2301
+ return strconv.FormatUint(v, 10)
2302
+ case float32:
2303
+ return typiaFloatLiteral(float64(v), 32)
2304
+ case float64:
2305
+ return typiaFloatLiteral(v, 64)
2306
+ default:
2307
+ return quote(fmt.Sprint(v))
2308
+ }
2309
+ }
2310
+
2311
+ func typiaFloatLiteral(value float64, bitSize int) string {
2312
+ if math.IsNaN(value) || math.IsInf(value, 0) {
2313
+ return quote(strconv.FormatFloat(value, 'g', -1, bitSize))
2314
+ }
2315
+ return strconv.FormatFloat(value, 'f', -1, bitSize)
2316
+ }