@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.
- package/README.md +13 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +966 -0
- package/dist/reflection/annotations.d.ts +15 -0
- package/dist/reflection/annotations.d.ts.map +1 -0
- package/dist/reflection/compact-metadata.d.ts +18 -0
- package/dist/reflection/compact-metadata.d.ts.map +1 -0
- package/dist/reflection/conversion.d.ts +15 -0
- package/dist/reflection/conversion.d.ts.map +1 -0
- package/dist/reflection/deserializer.d.ts +15 -0
- package/dist/reflection/deserializer.d.ts.map +1 -0
- package/dist/reflection/errors.d.ts +8 -0
- package/dist/reflection/errors.d.ts.map +1 -0
- package/dist/reflection/index.d.ts +10 -0
- package/dist/reflection/index.d.ts.map +1 -0
- package/dist/reflection/metadata-store.d.ts +20 -0
- package/dist/reflection/metadata-store.d.ts.map +1 -0
- package/dist/reflection/model.d.ts +273 -0
- package/dist/reflection/model.d.ts.map +1 -0
- package/dist/reflection/primitive-conversion.d.ts +2 -0
- package/dist/reflection/primitive-conversion.d.ts.map +1 -0
- package/dist/reflection/reflection-class.d.ts +60 -0
- package/dist/reflection/reflection-class.d.ts.map +1 -0
- package/dist/reflection/type-utils.d.ts +34 -0
- package/dist/reflection/type-utils.d.ts.map +1 -0
- package/dist/type-compiler/download-prebuilt.cjs +114 -0
- package/dist/type-compiler/go/ast_expression.go +187 -0
- package/dist/type-compiler/go/ast_metadata.go +388 -0
- package/dist/type-compiler/go/collect.go +963 -0
- package/dist/type-compiler/go/compact_metadata.go +553 -0
- package/dist/type-compiler/go/emission_plan.go +340 -0
- package/dist/type-compiler/go/emit_ast.go +557 -0
- package/dist/type-compiler/go/emit_ast_test.go +558 -0
- package/dist/type-compiler/go/go.mod +10 -0
- package/dist/type-compiler/go/plugin.go +359 -0
- package/dist/type-compiler/go/plugin_test.go +1206 -0
- package/dist/type-compiler/go/precompute.go +86 -0
- package/dist/type-compiler/go/receive_type.go +912 -0
- package/dist/type-compiler/go/resolve.go +265 -0
- package/dist/type-compiler/go/source_scan.go +51 -0
- package/dist/type-compiler/go/text_parse.go +734 -0
- package/dist/type-compiler/go/type_expr.go +1291 -0
- package/dist/type-compiler/go/typia_expr.go +2316 -0
- package/dist/type-compiler/index.cjs +43 -0
- package/dist/type-compiler/pnp.cjs +474 -0
- package/dist/type-compiler/prebuilt.cjs +324 -0
- package/dist/type-metadata-runtime.cjs +1 -0
- package/dist/type-metadata-runtime.d.ts +2 -0
- package/dist/type-metadata-runtime.d.ts.map +1 -0
- package/dist/type-metadata-runtime.js +107 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/primitives.d.ts +33 -0
- package/dist/types/primitives.d.ts.map +1 -0
- package/dist/types/runtime.d.ts +2 -0
- package/dist/types/runtime.d.ts.map +1 -0
- package/dist/types/type-annotations.d.ts +28 -0
- package/dist/types/type-annotations.d.ts.map +1 -0
- 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
|
+
}
|