@zyno-io/ts-server-foundation 26.714.5 → 26.714.423

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 (56) hide show
  1. package/dist/src/app/base.js +1 -1
  2. package/dist/src/app/index.js +1 -1
  3. package/dist/src/database/database.js +1 -1
  4. package/dist/src/database/index.js +1 -1
  5. package/dist/src/database/metadata.js +1 -1
  6. package/dist/src/database/query.d.ts.map +1 -1
  7. package/dist/src/database/query.js +6 -8
  8. package/dist/src/database/query.js.map +1 -1
  9. package/dist/src/devconsole/server.js +3 -3
  10. package/dist/src/devconsole/server.js.map +1 -1
  11. package/dist/src/di/container.js +1 -1
  12. package/dist/src/di/index.js +1 -1
  13. package/dist/src/di/module.js +1 -1
  14. package/dist/src/http/base.js +1 -1
  15. package/dist/src/http/index.js +1 -1
  16. package/dist/src/http/request.js +2 -2
  17. package/dist/src/http/response.js +3 -3
  18. package/dist/src/http/router.js +2 -3
  19. package/dist/src/http/workflow.js +1 -1
  20. package/dist/src/index.js +1 -1
  21. package/dist/src/openapi/index.js +1 -1
  22. package/dist/src/openapi/schema.js +1 -1
  23. package/dist/src/openapi/types.js +1 -1
  24. package/dist/src/reflection/conversion.d.ts.map +1 -1
  25. package/dist/src/reflection/conversion.js +3 -5
  26. package/dist/src/reflection/conversion.js.map +1 -1
  27. package/dist/src/reflection/deserializer.js +1 -1
  28. package/dist/src/reflection/index.js +1 -1
  29. package/dist/src/reflection/model.js +1 -1
  30. package/dist/src/reflection/primitive-conversion.d.ts +2 -0
  31. package/dist/src/reflection/primitive-conversion.d.ts.map +1 -0
  32. package/dist/src/reflection/primitive-conversion.js +19 -0
  33. package/dist/src/reflection/primitive-conversion.js.map +1 -0
  34. package/dist/src/reflection/reflection-class.js +3 -3
  35. package/dist/src/reflection/type-utils.d.ts.map +1 -1
  36. package/dist/src/reflection/type-utils.js +13 -0
  37. package/dist/src/reflection/type-utils.js.map +1 -1
  38. package/dist/src/services/index.js +1 -1
  39. package/dist/src/services/mesh-client/index.js +1 -1
  40. package/dist/src/services/mesh-client/mesh-client-redis-registry.js +1 -1
  41. package/dist/src/services/mesh-client/mesh-client-registry.js +1 -1
  42. package/dist/src/services/mesh-client/types.js +1 -1
  43. package/dist/src/testing/index.js +4 -4
  44. package/dist/src/testing/index.js.map +1 -1
  45. package/dist/src/testing/sql.js +1 -1
  46. package/dist/src/type-compiler/go/ast_metadata.go +1 -1
  47. package/dist/src/type-compiler/go/collect.go +17 -2
  48. package/dist/src/type-compiler/go/emission_plan.go +1 -1
  49. package/dist/src/type-compiler/go/plugin_test.go +148 -1
  50. package/dist/src/type-compiler/go/receive_type.go +67 -1
  51. package/dist/src/type-compiler/go/text_parse.go +65 -2
  52. package/dist/src/type-compiler/go/type_expr.go +5 -9
  53. package/dist/src/type-compiler/go/typia_expr.go +104 -15
  54. package/docs/content/database.md +11 -9
  55. package/docs/content/sql.md +1 -1
  56. package/package.json +1 -1
@@ -10,12 +10,8 @@ func typeExpr(info *fileInfo, reg *registry, raw string) string {
10
10
  return typeExprCtx(info, reg, raw, &typeContext{seen: map[string]bool{}})
11
11
  }
12
12
 
13
- func internalTypeExprAt(info *fileInfo, reg *registry, raw string, pos int) string {
14
- return typeExprCtx(info, reg, raw, &typeContext{seen: map[string]bool{}, pos: pos})
15
- }
16
-
17
13
  func typeExprCtx(info *fileInfo, reg *registry, raw string, ctx *typeContext) string {
18
- raw = strings.TrimSpace(raw)
14
+ raw = strings.TrimSpace(stripTypeComments(raw))
19
15
  raw = trimParens(raw)
20
16
  raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
21
17
  if raw == "" || raw == "unknown" {
@@ -415,7 +411,7 @@ func renderUtilityProperty(info *fileInfo, reg *registry, prop utilityProperty,
415
411
  if prop.owner != nil {
416
412
  owner = prop.owner
417
413
  }
418
- t := typeExprCtx(owner, reg, prop.typeText, ctx)
414
+ t := internalTypeExprForNodeCtx(owner, reg, prop.typeText, prop.typeNode, ctx)
419
415
  if prop.optional {
420
416
  t = "{kind: 12, types: [" + t + ", {kind: 4}]}"
421
417
  }
@@ -436,7 +432,7 @@ func renderPreferredUtilityProperty(info *fileInfo, reg *registry, prop utilityP
436
432
  }
437
433
  var t string
438
434
  if sourceTypeNeedsInternalPropertyMetadata(owner, reg, prop.typeText, &typeContext{seen: map[string]bool{}, pos: pos}, map[string]bool{}) {
439
- t = typeExprCtx(owner, reg, prop.typeText, &typeContext{seen: map[string]bool{}, pos: pos})
435
+ t = internalTypeExprForNode(owner, reg, prop.typeText, prop.typeNode, pos)
440
436
  } else {
441
437
  t = typeExprForNodePreferred(owner, reg, prop.typeText, prop.typeNode, pos, true)
442
438
  }
@@ -634,7 +630,7 @@ func utilitySourceProperties(info *fileInfo, reg *registry, source string, ctx *
634
630
  if class, owner, ok := resolveClassRefAt(info, reg, source, ctx.pos); ok {
635
631
  props := make([]utilityProperty, 0, len(class.properties))
636
632
  for _, prop := range class.properties {
637
- props = append(props, utilityProperty{name: prop.name, typeText: prop.typeText, optional: prop.optional, owner: owner})
633
+ props = append(props, utilityProperty{name: prop.name, typeText: prop.typeText, typeNode: prop.typeNode, optional: prop.optional, owner: owner})
638
634
  }
639
635
  return props, owner, true
640
636
  }
@@ -1097,7 +1093,7 @@ func aliasTypeExprCtx(owner *fileInfo, reg *registry, alias aliasInfo, name stri
1097
1093
  if strings.TrimSpace(alias.metadataText) != "" {
1098
1094
  return withTypeName(alias.metadataText, name)
1099
1095
  }
1100
- return withTypeName(typeExprCtx(owner, reg, alias.body, ctx), name)
1096
+ return withTypeName(internalTypeExprForNodeCtx(owner, reg, alias.body, alias.typeNode, ctx), name)
1101
1097
  }
1102
1098
 
1103
1099
  func ensureAliasMetadata(owner *fileInfo, reg *registry, name string, alias aliasInfo) aliasInfo {
@@ -18,6 +18,7 @@ func typeExprForNode(info *fileInfo, reg *registry, raw string, node *shimast.No
18
18
  }
19
19
 
20
20
  func typeExprForNodePreferred(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int, preferTypia bool) string {
21
+ raw = strings.TrimSpace(stripTypeComments(raw))
21
22
  if preferTypia {
22
23
  if expr, ok := preferredWrapperTypeExprForNode(info, reg, raw, node, pos); ok {
23
24
  return expr
@@ -25,16 +26,16 @@ func typeExprForNodePreferred(info *fileInfo, reg *registry, raw string, node *s
25
26
  if expr, ok := preferredCachedAliasTypeExpr(info, reg, raw, pos); ok {
26
27
  return expr
27
28
  }
28
- if expr, ok := preferredNullishAliasTypeExpr(info, reg, raw, pos); ok {
29
+ if expr, ok := preferredNullishAliasTypeExpr(info, reg, raw, node, pos); ok {
29
30
  return expr
30
31
  }
31
- if expr, ok := preferredDateRootTypeExpr(info, reg, raw, pos); ok {
32
+ if expr, ok := preferredDateRootTypeExpr(info, reg, raw, node, pos); ok {
32
33
  return expr
33
34
  }
34
35
  if expr, ok := preferredExternalImportedTypeExpr(info, raw); ok {
35
36
  return expr
36
37
  }
37
- if expr, ok := preferredExternalImportedCompositeTypeExpr(info, reg, raw, pos); ok {
38
+ if expr, ok := preferredExternalImportedCompositeTypeExpr(info, reg, raw, node, pos); ok {
38
39
  return expr
39
40
  }
40
41
  if expr, ok := preferredNamedInterfaceTypeExpr(info, reg, raw, pos); ok {
@@ -47,14 +48,78 @@ func typeExprForNodePreferred(info *fileInfo, reg *registry, raw string, node *s
47
48
  }
48
49
  }
49
50
  if shouldUseTextTypeExpr(raw) {
50
- return internalTypeExprAt(info, reg, raw, pos)
51
+ return internalTypeExprForNode(info, reg, raw, node, pos)
51
52
  }
52
53
  if shouldUseTypiaType(info, reg, raw) && canPreferTypiaType(info, reg, raw) {
53
54
  if expr, ok := typiaTypeExprForNode(info, reg, raw, node, pos); ok {
54
55
  return typiaSourceNamedExpr(info, reg, expr, raw)
55
56
  }
56
57
  }
57
- return internalTypeExprAt(info, reg, raw, pos)
58
+ return internalTypeExprForNode(info, reg, raw, node, pos)
59
+ }
60
+
61
+ func internalTypeExprForNode(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) string {
62
+ return internalTypeExprForNodeCtx(info, reg, raw, node, &typeContext{seen: map[string]bool{}, pos: pos})
63
+ }
64
+
65
+ func internalTypeExprForNodeCtx(info *fileInfo, reg *registry, raw string, node *shimast.Node, ctx *typeContext) string {
66
+ if ctx == nil {
67
+ ctx = &typeContext{seen: map[string]bool{}}
68
+ }
69
+ if node == nil {
70
+ return typeExprCtx(info, reg, raw, ctx)
71
+ }
72
+ if node.Kind == shimast.KindParenthesizedType {
73
+ inner := node.AsParenthesizedTypeNode().Type
74
+ if innerRaw, ok := sourceTypeNodeText(info, inner); ok {
75
+ return internalTypeExprForNodeCtx(info, reg, innerRaw, inner, ctx)
76
+ }
77
+ return typeExprCtx(info, reg, raw, ctx)
78
+ }
79
+
80
+ var kind int
81
+ var nodes []*shimast.Node
82
+ switch node.Kind {
83
+ case shimast.KindUnionType:
84
+ kind = 12
85
+ if types := node.AsUnionTypeNode().Types; types != nil {
86
+ nodes = types.Nodes
87
+ }
88
+ case shimast.KindIntersectionType:
89
+ kind = 13
90
+ if types := node.AsIntersectionTypeNode().Types; types != nil {
91
+ nodes = types.Nodes
92
+ }
93
+ default:
94
+ return typeExprCtx(info, reg, raw, ctx)
95
+ }
96
+ if len(nodes) < 2 {
97
+ return typeExprCtx(info, reg, raw, ctx)
98
+ }
99
+
100
+ types := make([]string, 0, len(nodes))
101
+ for _, child := range nodes {
102
+ childRaw, ok := sourceTypeNodeText(info, child)
103
+ if !ok {
104
+ return typeExprCtx(info, reg, raw, ctx)
105
+ }
106
+ types = append(types, internalTypeExprForNodeCtx(info, reg, childRaw, child, ctx))
107
+ }
108
+ return "{kind: " + strconv.Itoa(kind) + ", types: [" + strings.Join(types, ", ") + "]}"
109
+ }
110
+
111
+ func sourceTypeNodeText(info *fileInfo, node *shimast.Node) (string, bool) {
112
+ if node == nil {
113
+ return "", false
114
+ }
115
+ file := shimast.GetSourceFileOfNode(node)
116
+ if file == nil && info != nil {
117
+ file = info.file
118
+ }
119
+ if file == nil {
120
+ return "", false
121
+ }
122
+ return nodeText(file, node), true
58
123
  }
59
124
 
60
125
  func preferredCachedAliasTypeExpr(info *fileInfo, reg *registry, raw string, pos int) (string, bool) {
@@ -77,22 +142,46 @@ func preferredCachedAliasTypeExpr(info *fileInfo, reg *registry, raw string, pos
77
142
  return aliasTypeExprCtx(owner, reg, alias, raw, &typeContext{seen: map[string]bool{}, pos: pos}), true
78
143
  }
79
144
 
80
- func preferredNullishAliasTypeExpr(info *fileInfo, reg *registry, raw string, pos int) (string, bool) {
145
+ func preferredNullishAliasTypeExpr(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
81
146
  types := []string{}
82
- aliasCount, ok := collectNullishAliasTypeExprs(info, reg, raw, pos, &types)
147
+ aliasCount, ok := collectNullishAliasTypeExprs(info, reg, raw, node, pos, &types)
83
148
  if !ok || aliasCount != 1 || len(types) <= 1 {
84
149
  return "", false
85
150
  }
86
151
  return "{kind: 12, types: [" + strings.Join(types, ", ") + "]}", true
87
152
  }
88
153
 
89
- func collectNullishAliasTypeExprs(info *fileInfo, reg *registry, raw string, pos int, types *[]string) (int, bool) {
154
+ func collectNullishAliasTypeExprs(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int, types *[]string) (int, bool) {
90
155
  raw = strings.TrimSpace(trimParens(raw))
156
+ if node != nil && node.Kind == shimast.KindParenthesizedType {
157
+ inner := node.AsParenthesizedTypeNode().Type
158
+ if innerRaw, ok := sourceTypeNodeText(info, inner); ok {
159
+ return collectNullishAliasTypeExprs(info, reg, innerRaw, inner, pos, types)
160
+ }
161
+ }
162
+ if node != nil && node.Kind == shimast.KindUnionType {
163
+ union := node.AsUnionTypeNode()
164
+ if union.Types != nil && len(union.Types.Nodes) > 1 {
165
+ aliasCount := 0
166
+ for _, child := range union.Types.Nodes {
167
+ childRaw, ok := sourceTypeNodeText(info, child)
168
+ if !ok {
169
+ return 0, false
170
+ }
171
+ count, ok := collectNullishAliasTypeExprs(info, reg, childRaw, child, pos, types)
172
+ if !ok {
173
+ return 0, false
174
+ }
175
+ aliasCount += count
176
+ }
177
+ return aliasCount, true
178
+ }
179
+ }
91
180
  parts := nonEmptyParts(splitTop(raw, "|"))
92
181
  if len(parts) > 1 {
93
182
  aliasCount := 0
94
183
  for _, part := range parts {
95
- count, ok := collectNullishAliasTypeExprs(info, reg, part, pos, types)
184
+ count, ok := collectNullishAliasTypeExprs(info, reg, part, nil, pos, types)
96
185
  if !ok {
97
186
  return 0, false
98
187
  }
@@ -117,11 +206,11 @@ func collectNullishAliasTypeExprs(info *fileInfo, reg *registry, raw string, pos
117
206
  }
118
207
  }
119
208
 
120
- func preferredDateRootTypeExpr(info *fileInfo, reg *registry, raw string, pos int) (string, bool) {
209
+ func preferredDateRootTypeExpr(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
121
210
  if !sourceTypeIsDateRootType(info, reg, raw, &typeContext{seen: map[string]bool{}, pos: pos}, map[string]bool{}) {
122
211
  return "", false
123
212
  }
124
- return internalTypeExprAt(info, reg, raw, pos), true
213
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
125
214
  }
126
215
 
127
216
  func preferredExternalImportedTypeExpr(info *fileInfo, raw string) (string, bool) {
@@ -136,25 +225,25 @@ func preferredExternalImportedTypeExpr(info *fileInfo, raw string) (string, bool
136
225
  return externalImportedTypeExpr(ref, raw), true
137
226
  }
138
227
 
139
- func preferredExternalImportedCompositeTypeExpr(info *fileInfo, reg *registry, raw string, pos int) (string, bool) {
228
+ func preferredExternalImportedCompositeTypeExpr(info *fileInfo, reg *registry, raw string, node *shimast.Node, pos int) (string, bool) {
140
229
  raw = strings.TrimSpace(trimParens(raw))
141
230
  if raw == "" || isIdentifierName(raw) {
142
231
  return "", false
143
232
  }
144
233
  if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
145
234
  if typeContainsExternalImportReferenceInParts(info, reg, parts, map[string]bool{}) {
146
- return internalTypeExprAt(info, reg, raw, pos), true
235
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
147
236
  }
148
237
  }
149
238
  if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
150
239
  if typeContainsExternalImportReferenceInParts(info, reg, parts, map[string]bool{}) {
151
- return internalTypeExprAt(info, reg, raw, pos), true
240
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
152
241
  }
153
242
  }
154
243
  if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
155
244
  parts := nonEmptyParts(splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ","))
156
245
  if typeContainsExternalImportReferenceInParts(info, reg, parts, map[string]bool{}) {
157
- return internalTypeExprAt(info, reg, raw, pos), true
246
+ return internalTypeExprForNode(info, reg, raw, node, pos), true
158
247
  }
159
248
  }
160
249
  return "", false
@@ -63,14 +63,14 @@ The migration generator reads entity metadata to infer table names, column names
63
63
 
64
64
  Database I/O does not run the reflected HTTP-input deserializer or validator over whole entities. TSF instead performs a small set of column-aware storage conversions and otherwise relies on the database driver and database engine.
65
65
 
66
- | Path | Outbound conversion | Inbound conversion | Reflected validation |
67
- | ---------------------------------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------- | -------------------- |
68
- | Entity `save()` / `saveEntity()` | Column-aware | N/A | No |
69
- | Query-builder filters and patches | Column-aware | N/A | No |
70
- | Query-builder entity hydration | N/A | Column-aware | No |
71
- | `createEntity()` and related constructors | None; assigns application values and fills framework defaults | N/A | No |
72
- | `rawFind<T>()` / `rawFindOne<T>()` | Generic SQL binding normalization only | Driver values returned unchanged | No |
73
- | `rawFindUnsafe<T>()` / `rawFindOneUnsafe<T>()` | Generic SQL binding normalization only | Reflected `deserialize<T>()` when compiler metadata is available | No |
66
+ | Path | Outbound conversion | Inbound conversion | Reflected validation |
67
+ | ---------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------ | -------------------- |
68
+ | Entity `save()` / `saveEntity()` | Column-aware | N/A | No |
69
+ | Query-builder filters and patches | Column-aware | N/A | No |
70
+ | Query-builder entity hydration | N/A | Column-aware | No |
71
+ | `createEntity()` and related constructors | None; assigns application values and fills framework defaults | N/A | No |
72
+ | `rawFind<T>()` / `rawFindOne<T>()` | Generic SQL binding normalization only | Driver values returned unchanged | No |
73
+ | `rawFindUnsafe<T>()` / `rawFindOneUnsafe<T>()` | Generic SQL binding normalization only | Type-directed `deserialize<T>()` with an explicit or inferable `T` | No |
74
74
 
75
75
  Column-aware writes perform these conversions:
76
76
 
@@ -340,7 +340,9 @@ await db.rawExecute(
340
340
 
341
341
  `rawQuery<T>()` is the base row-returning method, and `rawFind<T>()` is its alias. `rawFindOne()` returns the first row or `undefined`. `rawExecute()` returns `{ affectedRows, rowCount?, insertId?, warningStatus? }`.
342
342
 
343
- The generic type on `rawFind<T>()` is a TypeScript-only assertion: returned rows keep the values produced by the database driver. The unsafe string methods have an additional compiler-injected reflected type slot, so `rawFindUnsafe<T>()` and `rawFindOneUnsafe<T>()` pass rows through `deserialize<T>()` when that metadata is available. That operation can coerce nested values or construct reflected classes, but it does not validate the rows. Prefer the query builder when entity column-aware hydration is required.
343
+ The generic type on `rawFind<T>()` is a TypeScript-only assertion: returned rows keep the values produced by the database driver. The unsafe string methods have an additional compiler-injected reflected type slot, so an explicit or otherwise inferable `T` on `rawFindUnsafe<T>()` and `rawFindOneUnsafe<T>()` passes rows through `deserialize<T>()`. A call without a resolvable row type keeps the driver's values unchanged.
344
+
345
+ Reflected raw-row deserialization is type-directed rather than column-aware. It recursively converts numeric boolean values such as MySQL `TINYINT(1)` (`0`, `1`, or other numeric values) to booleans, converts numeric strings to numbers when the target is `number`, and can construct reflected classes. Consequently, type precision-sensitive `DECIMAL` results as `string`, not `number`, and treat deserialized entity instances as unmanaged objects without ORM snapshots. The operation does not validate rows; prefer the query builder when entity column-aware hydration and persistence tracking are required.
344
346
 
345
347
  The unsafe variants accept a SQL string and bindings:
346
348
 
@@ -107,7 +107,7 @@ await session.rawExecuteUnsafe('UPDATE users SET active = ? WHERE id = ?', [fals
107
107
 
108
108
  Prefer the `sql` tag for new code because identifiers and values stay explicit in the same expression.
109
109
 
110
- When TSF's metadata compiler can provide `T`, `rawFindUnsafe<T>()` and `rawFindOneUnsafe<T>()` reflected-deserialize returned rows. They still do not validate them. This behavior is specific to the unsafe methods' receive-type signature; use query-builder entity reads for column-aware hydration.
110
+ When TSF's metadata compiler can resolve an explicit or inferable `T`, `rawFindUnsafe<T>()` and `rawFindOneUnsafe<T>()` reflected-deserialize returned rows. Numeric values targeting booleans are converted to `true` or `false`, including MySQL `TINYINT(1)` results. Numeric strings targeting `number` are also converted, so precision-sensitive `DECIMAL` results should be typed as `string`. Calls without a resolvable row type keep driver-native values. Typed raw reads do not validate rows or attach ORM persistence state; use query-builder entity reads for column-aware hydration.
111
111
 
112
112
  ## Rendering For Logs Or Tests
113
113
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zyno-io/ts-server-foundation",
3
- "version": "26.714.5",
3
+ "version": "26.714.423",
4
4
  "description": "TypeScript server foundation with reflected type metadata",
5
5
  "license": "MIT",
6
6
  "bin": {