@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,1291 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"regexp"
|
|
5
|
+
"strconv"
|
|
6
|
+
"strings"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func typeExpr(info *fileInfo, reg *registry, raw string) string {
|
|
10
|
+
return typeExprCtx(info, reg, raw, &typeContext{seen: map[string]bool{}})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
func typeExprCtx(info *fileInfo, reg *registry, raw string, ctx *typeContext) string {
|
|
14
|
+
raw = strings.TrimSpace(stripTypeComments(raw))
|
|
15
|
+
raw = trimParens(raw)
|
|
16
|
+
raw = strings.TrimSpace(strings.TrimPrefix(raw, "readonly "))
|
|
17
|
+
if raw == "" || raw == "unknown" {
|
|
18
|
+
return "{kind: 2}"
|
|
19
|
+
}
|
|
20
|
+
if ctx == nil {
|
|
21
|
+
ctx = &typeContext{seen: map[string]bool{}}
|
|
22
|
+
}
|
|
23
|
+
if ctx.typeParams[raw] {
|
|
24
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
25
|
+
}
|
|
26
|
+
ctx.depth++
|
|
27
|
+
defer func() { ctx.depth-- }()
|
|
28
|
+
if ctx.depth > 80 {
|
|
29
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
30
|
+
}
|
|
31
|
+
key := info.moduleKey + "\x00" + raw
|
|
32
|
+
if ctx.seen[key] {
|
|
33
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
34
|
+
}
|
|
35
|
+
ctx.seen[key] = true
|
|
36
|
+
defer delete(ctx.seen, key)
|
|
37
|
+
if raw == "string" {
|
|
38
|
+
return "{kind: 6}"
|
|
39
|
+
}
|
|
40
|
+
if raw == "never" {
|
|
41
|
+
return "{kind: 0}"
|
|
42
|
+
}
|
|
43
|
+
if raw == "number" {
|
|
44
|
+
return "{kind: 7}"
|
|
45
|
+
}
|
|
46
|
+
if raw == "boolean" {
|
|
47
|
+
return "{kind: 8}"
|
|
48
|
+
}
|
|
49
|
+
if raw == "bigint" {
|
|
50
|
+
return "{kind: 9}"
|
|
51
|
+
}
|
|
52
|
+
if raw == "void" {
|
|
53
|
+
return "{kind: 3}"
|
|
54
|
+
}
|
|
55
|
+
if raw == "undefined" {
|
|
56
|
+
return "{kind: 4}"
|
|
57
|
+
}
|
|
58
|
+
if raw == "null" {
|
|
59
|
+
return "{kind: 5}"
|
|
60
|
+
}
|
|
61
|
+
if raw == "any" {
|
|
62
|
+
return "{kind: 1}"
|
|
63
|
+
}
|
|
64
|
+
if raw == "object" {
|
|
65
|
+
return "{kind: 17}"
|
|
66
|
+
}
|
|
67
|
+
if raw == "symbol" {
|
|
68
|
+
return "{kind: 2, typeName: \"symbol\"}"
|
|
69
|
+
}
|
|
70
|
+
if raw == "ReflectionKind" {
|
|
71
|
+
return "{kind: 11, typeName: \"ReflectionKind\", values: []}"
|
|
72
|
+
}
|
|
73
|
+
if strings.HasPrefix(raw, "keyof ") {
|
|
74
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
75
|
+
}
|
|
76
|
+
if isFunctionTypeSyntax(raw) {
|
|
77
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
78
|
+
}
|
|
79
|
+
if parts := nonEmptyParts(splitTop(raw, "|")); len(parts) > 1 {
|
|
80
|
+
return "{kind: 12, types: [" + mapJoin(parts, func(part string) string { return typeExprCtx(info, reg, part, ctx) }) + "]}"
|
|
81
|
+
}
|
|
82
|
+
if parts := nonEmptyParts(splitTop(raw, "&")); len(parts) > 1 {
|
|
83
|
+
return "{kind: 13, types: [" + mapJoin(parts, func(part string) string { return typeExprCtx(info, reg, part, ctx) }) + "]}"
|
|
84
|
+
}
|
|
85
|
+
if strings.HasPrefix(raw, "\"") || strings.HasPrefix(raw, "'") {
|
|
86
|
+
return "{kind: 10, literal: " + normalizeStringLiteral(raw) + "}"
|
|
87
|
+
}
|
|
88
|
+
if raw == "true" || raw == "false" {
|
|
89
|
+
return "{kind: 10, literal: " + raw + "}"
|
|
90
|
+
}
|
|
91
|
+
if _, err := strconv.ParseFloat(raw, 64); err == nil {
|
|
92
|
+
return "{kind: 10, literal: " + raw + "}"
|
|
93
|
+
}
|
|
94
|
+
if strings.HasSuffix(raw, "[]") {
|
|
95
|
+
return "{kind: 14, type: " + typeExprCtx(info, reg, strings.TrimSuffix(raw, "[]"), ctx) + "}"
|
|
96
|
+
}
|
|
97
|
+
if strings.HasPrefix(raw, "[") && strings.HasSuffix(raw, "]") {
|
|
98
|
+
items := splitTop(strings.TrimSpace(raw[1:len(raw)-1]), ",")
|
|
99
|
+
return "{kind: 15, types: [" + mapJoin(items, func(item string) string {
|
|
100
|
+
return "{type: " + typeExprCtx(info, reg, item, ctx) + "}"
|
|
101
|
+
}) + "]}"
|
|
102
|
+
}
|
|
103
|
+
if expr, ok := indexedAccessTypeExpr(info, reg, raw, ctx); ok {
|
|
104
|
+
return expr
|
|
105
|
+
}
|
|
106
|
+
if isObjectLiteralTypeText(raw) {
|
|
107
|
+
return objectTypeLiteralExpr(info, reg, raw, ctx)
|
|
108
|
+
}
|
|
109
|
+
if expr, ok := importTypeReferenceExpr(info, reg, raw, ctx); ok {
|
|
110
|
+
return expr
|
|
111
|
+
}
|
|
112
|
+
if name, args, ok := generic(raw); ok {
|
|
113
|
+
return genericTypeExpr(info, reg, name, args, ctx)
|
|
114
|
+
}
|
|
115
|
+
if isUnsupportedTypeSyntax(raw) {
|
|
116
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
117
|
+
}
|
|
118
|
+
if ref, ok := info.imports[raw]; ok && isExternalImportRef(ref) && !isFoundationImportRef(ref) {
|
|
119
|
+
return externalImportedTypeExpr(ref, raw)
|
|
120
|
+
}
|
|
121
|
+
if class, ok := chooseClass(info, raw, ctx.pos); ok {
|
|
122
|
+
if iface, hasInterface := chooseInterface(info, raw, ctx.pos); !hasInterface || class.pos >= iface.pos {
|
|
123
|
+
return "{kind: 16, typeName: " + quote(raw) + ", classType: () => " + runtimeValueExpr(info, reg, raw) + "}"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if enum, _, ok := resolveEnum(info, reg, raw); ok {
|
|
127
|
+
return enumTypeExpr(enum, raw)
|
|
128
|
+
}
|
|
129
|
+
if decl, owner, ref, ok := resolveInterfaceDeclRefAt(info, reg, raw, ctx.pos); ok {
|
|
130
|
+
_ = ref
|
|
131
|
+
return interfaceObjectLiteralExpr(owner, reg, raw, decl, ctx)
|
|
132
|
+
}
|
|
133
|
+
if alias, owner, ref, ok := resolveAliasRef(info, reg, raw); ok {
|
|
134
|
+
if len(alias.params) > 0 {
|
|
135
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
136
|
+
}
|
|
137
|
+
if ref != nil {
|
|
138
|
+
alias = ensureAliasMetadata(owner, reg, ref.exportName, alias)
|
|
139
|
+
}
|
|
140
|
+
return aliasTypeExprCtx(owner, reg, alias, raw, ctx)
|
|
141
|
+
}
|
|
142
|
+
if ref, ok := info.imports[raw]; ok && isExternalImportRef(ref) {
|
|
143
|
+
return externalImportedTypeExpr(ref, raw)
|
|
144
|
+
}
|
|
145
|
+
switch raw {
|
|
146
|
+
case "PrimaryKey", "AutoIncrement", "Reference", "Index", "Unique":
|
|
147
|
+
return "{kind: 2, typeName: " + quote(raw) + "}"
|
|
148
|
+
}
|
|
149
|
+
return "{kind: 16, typeName: " + quote(raw) + ", classType: () => " + runtimeValueExpr(info, reg, raw) + "}"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func genericTypeExpr(info *fileInfo, reg *registry, name string, args []string, ctx *typeContext) string {
|
|
153
|
+
switch name {
|
|
154
|
+
case "Array", "ReadonlyArray":
|
|
155
|
+
return "{kind: 14, type: " + typeExprCtx(info, reg, firstArg(args), ctx) + "}"
|
|
156
|
+
case "Promise":
|
|
157
|
+
return "{kind: 22, type: " + typeExprCtx(info, reg, firstArg(args), ctx) + "}"
|
|
158
|
+
case "NoInfer":
|
|
159
|
+
return typeExprCtx(info, reg, firstArg(args), ctx)
|
|
160
|
+
case "NonNullable":
|
|
161
|
+
source := firstArg(args)
|
|
162
|
+
if resolved, owner, ok := resolveTypeText(info, reg, source, ctx); ok {
|
|
163
|
+
return typeExprCtx(owner, reg, nonNullableTypeText(resolved), ctx)
|
|
164
|
+
}
|
|
165
|
+
return typeExprCtx(info, reg, nonNullableTypeText(source), ctx)
|
|
166
|
+
case "ApiResponse":
|
|
167
|
+
bodyType := typeExprCtx(info, reg, firstArg(args), ctx)
|
|
168
|
+
statusType := literalArg("200")
|
|
169
|
+
if len(args) > 1 {
|
|
170
|
+
statusType = literalArg(args[1])
|
|
171
|
+
}
|
|
172
|
+
return "{kind: 22, typeName: \"ApiResponse\", type: " + bodyType + ", typeArguments: [" + bodyType + ", " + statusType + "]}"
|
|
173
|
+
case "HttpBody":
|
|
174
|
+
return httpMarkerType(info, reg, "HttpBody", "httpBody", firstArg(args), "{}", ctx)
|
|
175
|
+
case "HttpQueries":
|
|
176
|
+
return httpMarkerType(info, reg, "HttpQueries", "httpQueries", firstArg(args), "{}", ctx)
|
|
177
|
+
case "HttpQuery":
|
|
178
|
+
return httpMarkerType(info, reg, "HttpQuery", "httpQuery", firstArg(args), optionArg(args, 1), ctx)
|
|
179
|
+
case "HttpPath":
|
|
180
|
+
return httpMarkerType(info, reg, "HttpPath", "httpPath", firstArg(args), optionArg(args, 1), ctx)
|
|
181
|
+
case "HttpHeader":
|
|
182
|
+
return httpMarkerType(info, reg, "HttpHeader", "httpHeader", firstArg(args), optionArg(args, 1), ctx)
|
|
183
|
+
case "ApiName":
|
|
184
|
+
return typeAnnotationMarker("ApiName", "openapi:name", literalArg(firstArg(args)))
|
|
185
|
+
case "ApiType":
|
|
186
|
+
if len(args) < 2 {
|
|
187
|
+
return "{kind: 2, typeName: \"ApiType\"}"
|
|
188
|
+
}
|
|
189
|
+
bodyType := typeExprCtx(info, reg, args[1], ctx)
|
|
190
|
+
marker := typeAnnotationMarker("ApiName", "openapi:name", literalArg(firstArg(args)))
|
|
191
|
+
return "{kind: 13, typeName: \"ApiType\", types: [" + bodyType + ", " + marker + "]}"
|
|
192
|
+
case "Indexed":
|
|
193
|
+
if len(args) == 0 {
|
|
194
|
+
return "{kind: 2, typeName: \"Indexed\"}"
|
|
195
|
+
}
|
|
196
|
+
return indexedTypeExpr(info, reg, firstArg(args), ctx)
|
|
197
|
+
case "MinLength":
|
|
198
|
+
return validationMarker("MinLength", "minLength", literalArg(firstArg(args)))
|
|
199
|
+
case "MaxLength":
|
|
200
|
+
return validationMarker("MaxLength", "maxLength", literalArg(firstArg(args)))
|
|
201
|
+
case "Length":
|
|
202
|
+
value := literalArg(firstArg(args))
|
|
203
|
+
return "{kind: 13, typeName: \"Length\", types: [{kind: 6}, " +
|
|
204
|
+
validationMarker("MinLength", "minLength", value) + ", " +
|
|
205
|
+
validationMarker("MaxLength", "maxLength", value) + ", " +
|
|
206
|
+
typeAnnotationMarker("Length", "tsf:length", value) + "]}"
|
|
207
|
+
case "Minimum":
|
|
208
|
+
return validationMarker("Minimum", "minimum", literalArg(firstArg(args)))
|
|
209
|
+
case "GreaterThan":
|
|
210
|
+
return validationMarker("GreaterThan", "greaterThan", literalArg(firstArg(args)))
|
|
211
|
+
case "Maximum":
|
|
212
|
+
return validationMarker("Maximum", "maximum", literalArg(firstArg(args)))
|
|
213
|
+
case "LessThan":
|
|
214
|
+
return validationMarker("LessThan", "lessThan", literalArg(firstArg(args)))
|
|
215
|
+
case "Pattern":
|
|
216
|
+
if isLiteralStringType(firstArg(args)) {
|
|
217
|
+
return validationMarker("Pattern", "pattern", literalArg(firstArg(args)))
|
|
218
|
+
}
|
|
219
|
+
return validationMarker("Pattern", "pattern", runtimeArg(info, reg, firstArg(args)))
|
|
220
|
+
case "TypiaFormat":
|
|
221
|
+
if pattern := typiaFormatPatternArg(literalStringValue(firstArg(args))); pattern != "" {
|
|
222
|
+
return validationMarker("Format", "pattern", pattern)
|
|
223
|
+
}
|
|
224
|
+
return "{kind: 2, typeName: \"TypiaFormat\"}"
|
|
225
|
+
case "Validate":
|
|
226
|
+
if isLiteralStringType(firstArg(args)) {
|
|
227
|
+
return validationMarker("Validator", "validator", literalArg(firstArg(args)))
|
|
228
|
+
}
|
|
229
|
+
return validationMarker("Validate", "validate", runtimeArg(info, reg, firstArg(args)))
|
|
230
|
+
case "TsfValidatorTag":
|
|
231
|
+
return validationMarker("Validator", "validator", internalTagValueExpr(info, reg, firstArg(args[1:]), ctx))
|
|
232
|
+
case "TsfTypeTag":
|
|
233
|
+
return typeAnnotationMarker("TypeAnnotation", "tsf:type", internalTagValueExpr(info, reg, firstArg(args[1:]), ctx))
|
|
234
|
+
case "TsfTypiaTag":
|
|
235
|
+
if expr, ok := internalTypiaTagMarkerExpr(info, reg, name, args, 1, 2, -1, ctx); ok {
|
|
236
|
+
return expr
|
|
237
|
+
}
|
|
238
|
+
return "{kind: 2, typeName: \"TsfTypiaTag\"}"
|
|
239
|
+
case "TsfTypiaSchemaTag":
|
|
240
|
+
if expr, ok := internalTypiaTagMarkerExpr(info, reg, name, args, 1, 2, 3, ctx); ok {
|
|
241
|
+
return expr
|
|
242
|
+
}
|
|
243
|
+
return "{kind: 2, typeName: \"TsfTypiaSchemaTag\"}"
|
|
244
|
+
case "TsfDatabaseFieldTag":
|
|
245
|
+
return "{kind: 2, typeName: \"DatabaseField\", database: {\"*\": " + plainValue(firstArg(args)) + "}}"
|
|
246
|
+
case "TsfDatabaseTag":
|
|
247
|
+
if expr, ok := internalDatabaseTagMarkerExpr(literalStringValue(firstArg(args)), plainValue(optionArg(args, 1))); ok {
|
|
248
|
+
return expr
|
|
249
|
+
}
|
|
250
|
+
return "{kind: 2, typeName: \"TsfDatabaseTag\"}"
|
|
251
|
+
case "DatabaseField":
|
|
252
|
+
return "{kind: 2, typeName: \"DatabaseField\", database: {\"*\": " + plainValue(firstArg(args)) + "}}"
|
|
253
|
+
case "MySQL":
|
|
254
|
+
return "{kind: 2, typeName: \"MySQL\", database: {mysql: " + plainValue(firstArg(args)) + "}}"
|
|
255
|
+
case "Reference", "Index", "Unique", "PrimaryKey", "AutoIncrement":
|
|
256
|
+
return "{kind: 2, typeName: " + quote(name) + "}"
|
|
257
|
+
case "TypeAnnotation":
|
|
258
|
+
if len(args) == 0 {
|
|
259
|
+
return "{kind: 2}"
|
|
260
|
+
}
|
|
261
|
+
annotation := literalStringValue(args[0])
|
|
262
|
+
value := "{kind: 4}"
|
|
263
|
+
if len(args) > 1 {
|
|
264
|
+
value = annotationValueExpr(info, reg, args[1], ctx)
|
|
265
|
+
}
|
|
266
|
+
return typeAnnotationMarker("TypeAnnotation", annotation, value)
|
|
267
|
+
case "Record":
|
|
268
|
+
key := "{kind: 2}"
|
|
269
|
+
if len(args) > 0 {
|
|
270
|
+
key = typeExprCtx(info, reg, firstArg(args), ctx)
|
|
271
|
+
}
|
|
272
|
+
value := "{kind: 2}"
|
|
273
|
+
if len(args) > 1 {
|
|
274
|
+
value = typeExprCtx(info, reg, args[1], ctx)
|
|
275
|
+
}
|
|
276
|
+
return "{kind: 18, typeName: \"Record\", utilityType: \"Record\", typeArguments: [" + key + ", " + value + "], index: " + value + ", types: []}"
|
|
277
|
+
case "EntityFields", "EntityOptionals", "NewEntityFields":
|
|
278
|
+
if props, owner, ok := utilitySourceProperties(info, reg, firstArg(args), ctx); ok {
|
|
279
|
+
sourceExpr := typeExprCtx(info, reg, firstArg(args), ctx)
|
|
280
|
+
return "{kind: 18, typeName: " + quote(name) + ", typeArguments: [" + sourceExpr + "], types: [" + renderUtilityProperties(owner, reg, props, ctx) + "]}"
|
|
281
|
+
}
|
|
282
|
+
return "{kind: 18, typeName: " + quote(name) + ", types: []}"
|
|
283
|
+
case "Pick", "Omit", "Partial", "Required":
|
|
284
|
+
if expr, ok := utilityTypeExpr(info, reg, name, args, ctx); ok {
|
|
285
|
+
return expr
|
|
286
|
+
}
|
|
287
|
+
if expr, ok := runtimeUtilityTypeExpr(info, reg, name, args, ctx); ok {
|
|
288
|
+
return expr
|
|
289
|
+
}
|
|
290
|
+
return "{kind: 18, typeName: " + quote(name) + ", types: []}"
|
|
291
|
+
case "Extract":
|
|
292
|
+
sourceExpr := typeExprCtx(info, reg, firstArg(args), ctx)
|
|
293
|
+
targetExpr := typeExprCtx(info, reg, firstArg(args[1:]), ctx)
|
|
294
|
+
return "{kind: 12, typeName: \"Extract\", utilityType: \"Extract\", typeArguments: [" + sourceExpr + ", " + targetExpr + "], types: []}"
|
|
295
|
+
default:
|
|
296
|
+
if alias, owner, ref, ok := resolveAliasRef(info, reg, name); ok {
|
|
297
|
+
_ = ref
|
|
298
|
+
out := alias.body
|
|
299
|
+
for i := range alias.params {
|
|
300
|
+
out = replaceTypeParameter(out, aliasParamName(alias, i), aliasArg(alias, args, i))
|
|
301
|
+
}
|
|
302
|
+
if hasUnresolvedTypeParameters(out, alias.params) || isUnsupportedTypeSyntax(out) {
|
|
303
|
+
return "{kind: 2, typeName: " + quote(name) + ", typeArguments: [" + mapJoin(args, func(arg string) string { return typeExprCtx(info, reg, arg, ctx) }) + "]}"
|
|
304
|
+
}
|
|
305
|
+
return withTypeName(typeExprCtx(owner, reg, out, ctx), name)
|
|
306
|
+
}
|
|
307
|
+
if decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, name, ctx.pos); ok {
|
|
308
|
+
return interfaceObjectLiteralExpr(owner, reg, name, instantiateInterfaceDecl(decl, args), ctx)
|
|
309
|
+
}
|
|
310
|
+
if ref, ok := info.imports[name]; ok && isExternalImportRef(ref) {
|
|
311
|
+
return withTypeArguments(externalImportedTypeExpr(ref, name), info, reg, args, ctx)
|
|
312
|
+
}
|
|
313
|
+
return "{kind: 16, typeName: " + quote(name) + ", classType: () => " + runtimeValueExpr(info, reg, name) + typeArgumentsProperty(info, reg, args, ctx) + "}"
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
func typeArgumentsProperty(info *fileInfo, reg *registry, args []string, ctx *typeContext) string {
|
|
318
|
+
if len(args) == 0 {
|
|
319
|
+
return ""
|
|
320
|
+
}
|
|
321
|
+
return ", typeArguments: [" + mapJoin(args, func(arg string) string { return typeExprCtx(info, reg, arg, ctx) }) + "]"
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
func withTypeArguments(expr string, info *fileInfo, reg *registry, args []string, ctx *typeContext) string {
|
|
325
|
+
if len(args) == 0 {
|
|
326
|
+
return expr
|
|
327
|
+
}
|
|
328
|
+
return "Object.assign(" + expr + ", {typeArguments: [" + mapJoin(args, func(arg string) string { return typeExprCtx(info, reg, arg, ctx) }) + "]})"
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
func httpMarkerType(info *fileInfo, reg *registry, typeName string, annotation string, valueType string, options string, ctx *typeContext) string {
|
|
332
|
+
value := annotationValueExpr(info, reg, options+" & { type: "+valueType+" }", ctx)
|
|
333
|
+
marker := typeAnnotationMarker(typeName, annotation, value)
|
|
334
|
+
return "{kind: 13, typeName: " + quote(typeName) + ", types: [" + typeExprCtx(info, reg, valueType, ctx) + ", " + marker + "]}"
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
func objectLiteralExpr(info *fileInfo, reg *registry, typeName string, body string, ctx *typeContext) string {
|
|
338
|
+
props := propertiesFromBody(body)
|
|
339
|
+
return "{kind: 18, typeName: " + quote(typeName) + objectIndexExpr(info, reg, body, ctx) + ", types: [" + renderUtilityProperties(info, reg, props, ctx) + "]}"
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
func stringSliceExpr(values []string) string {
|
|
343
|
+
parts := make([]string, len(values))
|
|
344
|
+
for index, value := range values {
|
|
345
|
+
parts[index] = quote(value)
|
|
346
|
+
}
|
|
347
|
+
return "[" + strings.Join(parts, ", ") + "]"
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
func interfaceObjectLiteralExpr(info *fileInfo, reg *registry, typeName string, decl interfaceInfo, ctx *typeContext) string {
|
|
351
|
+
if ctx == nil {
|
|
352
|
+
ctx = &typeContext{seen: map[string]bool{}}
|
|
353
|
+
}
|
|
354
|
+
if ctx.interfaces == nil {
|
|
355
|
+
ctx.interfaces = map[string]bool{}
|
|
356
|
+
}
|
|
357
|
+
previousTypeParams := ctx.typeParams
|
|
358
|
+
ctx.typeParams = mergedTypeParameters(previousTypeParams, decl.params)
|
|
359
|
+
defer func() { ctx.typeParams = previousTypeParams }()
|
|
360
|
+
key := info.moduleKey + "\x00" + strconv.Itoa(decl.pos)
|
|
361
|
+
if ctx.interfaces[key] {
|
|
362
|
+
return "{kind: 2, typeName: " + quote(typeName) + "}"
|
|
363
|
+
}
|
|
364
|
+
ctx.interfaces[key] = true
|
|
365
|
+
defer delete(ctx.interfaces, key)
|
|
366
|
+
|
|
367
|
+
props := interfaceFullProperties(info, reg, decl, map[string]bool{})
|
|
368
|
+
body := interfaceFullBody(info, reg, decl, map[string]bool{})
|
|
369
|
+
items := []string{
|
|
370
|
+
"kind: 18",
|
|
371
|
+
"typeName: " + quote(typeName),
|
|
372
|
+
"types: [" + renderUtilityProperties(info, reg, props, ctx) + "]",
|
|
373
|
+
}
|
|
374
|
+
if len(decl.params) != 0 {
|
|
375
|
+
items = append(items, "typeParameters: "+stringSliceExpr(decl.params))
|
|
376
|
+
}
|
|
377
|
+
if index := objectIndexExpr(info, reg, body, ctx); index != "" {
|
|
378
|
+
items = append(items, strings.TrimPrefix(index, ", "))
|
|
379
|
+
}
|
|
380
|
+
if implements := interfaceImplementsExpr(info, reg, decl, ctx); implements != "" {
|
|
381
|
+
items = append(items, "implements: ["+implements+"]")
|
|
382
|
+
}
|
|
383
|
+
return "{" + strings.Join(items, ", ") + "}"
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
func interfaceObjectLiteralExprPreferred(info *fileInfo, reg *registry, typeName string, decl interfaceInfo, ctx *typeContext) string {
|
|
387
|
+
if ctx == nil {
|
|
388
|
+
ctx = &typeContext{seen: map[string]bool{}}
|
|
389
|
+
}
|
|
390
|
+
previousTypeParams := ctx.typeParams
|
|
391
|
+
ctx.typeParams = mergedTypeParameters(previousTypeParams, decl.params)
|
|
392
|
+
defer func() { ctx.typeParams = previousTypeParams }()
|
|
393
|
+
|
|
394
|
+
props := interfaceFullProperties(info, reg, decl, map[string]bool{})
|
|
395
|
+
body := interfaceFullBody(info, reg, decl, map[string]bool{})
|
|
396
|
+
items := []string{
|
|
397
|
+
"kind: 18",
|
|
398
|
+
"typeName: " + quote(typeName),
|
|
399
|
+
"types: [" + renderPreferredUtilityProperties(info, reg, props, ctx) + "]",
|
|
400
|
+
}
|
|
401
|
+
if len(decl.params) != 0 {
|
|
402
|
+
items = append(items, "typeParameters: "+stringSliceExpr(decl.params))
|
|
403
|
+
}
|
|
404
|
+
if index := objectIndexExpr(info, reg, body, ctx); index != "" {
|
|
405
|
+
items = append(items, strings.TrimPrefix(index, ", "))
|
|
406
|
+
}
|
|
407
|
+
if implements := interfaceImplementsExpr(info, reg, decl, ctx); implements != "" {
|
|
408
|
+
items = append(items, "implements: ["+implements+"]")
|
|
409
|
+
}
|
|
410
|
+
return "{" + strings.Join(items, ", ") + "}"
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
func mergedTypeParameters(existing map[string]bool, names []string) map[string]bool {
|
|
414
|
+
if len(names) == 0 {
|
|
415
|
+
return existing
|
|
416
|
+
}
|
|
417
|
+
merged := make(map[string]bool, len(existing)+len(names))
|
|
418
|
+
for name, enabled := range existing {
|
|
419
|
+
merged[name] = enabled
|
|
420
|
+
}
|
|
421
|
+
for _, name := range names {
|
|
422
|
+
merged[name] = true
|
|
423
|
+
}
|
|
424
|
+
return merged
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
func objectTypeLiteralExpr(info *fileInfo, reg *registry, raw string, ctx *typeContext) string {
|
|
428
|
+
body := strings.TrimSpace(raw[1 : len(raw)-1])
|
|
429
|
+
props := propertiesFromBody(body)
|
|
430
|
+
return "{kind: 18" + objectIndexExpr(info, reg, body, ctx) + ", types: [" + renderUtilityProperties(info, reg, props, ctx) + "]}"
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
func objectIndexExpr(info *fileInfo, reg *registry, body string, ctx *typeContext) string {
|
|
434
|
+
if indexType, ok := indexSignatureType(body); ok {
|
|
435
|
+
return ", index: " + typeExprCtx(info, reg, indexType, ctx)
|
|
436
|
+
}
|
|
437
|
+
return ""
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
func objectLiteralProperties(info *fileInfo, reg *registry, body string, ctx *typeContext) []string {
|
|
441
|
+
props := []string{}
|
|
442
|
+
for _, prop := range propertiesFromBody(body) {
|
|
443
|
+
props = append(props, renderUtilityProperty(info, reg, prop, ctx))
|
|
444
|
+
}
|
|
445
|
+
return props
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
func propertiesFromBody(body string) []utilityProperty {
|
|
449
|
+
props := []utilityProperty{}
|
|
450
|
+
for _, field := range splitInterfaceFields(body) {
|
|
451
|
+
name, typeText, optional, ok := parseField(field)
|
|
452
|
+
if !ok {
|
|
453
|
+
continue
|
|
454
|
+
}
|
|
455
|
+
props = append(props, utilityProperty{name: name, typeText: typeText, optional: optional})
|
|
456
|
+
}
|
|
457
|
+
return props
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
func renderUtilityProperties(info *fileInfo, reg *registry, props []utilityProperty, ctx *typeContext) string {
|
|
461
|
+
return strings.Join(mapUtilityProperties(props, func(prop utilityProperty) string {
|
|
462
|
+
return renderUtilityProperty(info, reg, prop, ctx)
|
|
463
|
+
}), ", ")
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
func renderPreferredUtilityProperties(info *fileInfo, reg *registry, props []utilityProperty, ctx *typeContext) string {
|
|
467
|
+
return strings.Join(mapUtilityProperties(props, func(prop utilityProperty) string {
|
|
468
|
+
return renderPreferredUtilityProperty(info, reg, prop, ctx)
|
|
469
|
+
}), ", ")
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
func renderUtilityProperty(info *fileInfo, reg *registry, prop utilityProperty, ctx *typeContext) string {
|
|
473
|
+
owner := info
|
|
474
|
+
if prop.owner != nil {
|
|
475
|
+
owner = prop.owner
|
|
476
|
+
}
|
|
477
|
+
t := internalTypeExprForNodeCtx(owner, reg, prop.typeText, prop.typeNode, ctx)
|
|
478
|
+
if prop.optional {
|
|
479
|
+
t = "{kind: 12, types: [" + t + ", {kind: 4}]}"
|
|
480
|
+
}
|
|
481
|
+
return "{kind: 20, name: " + quote(prop.name) + ", type: " + t + ", optional: " + boolLit(prop.optional) + "}"
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
func renderPreferredUtilityProperty(info *fileInfo, reg *registry, prop utilityProperty, ctx *typeContext) string {
|
|
485
|
+
owner := info
|
|
486
|
+
if prop.owner != nil {
|
|
487
|
+
owner = prop.owner
|
|
488
|
+
}
|
|
489
|
+
pos := 0
|
|
490
|
+
if ctx != nil {
|
|
491
|
+
pos = ctx.pos
|
|
492
|
+
}
|
|
493
|
+
if prop.typeNode != nil {
|
|
494
|
+
pos = prop.typeNode.Pos()
|
|
495
|
+
}
|
|
496
|
+
var t string
|
|
497
|
+
if sourceTypeNeedsInternalPropertyMetadata(owner, reg, prop.typeText, &typeContext{seen: map[string]bool{}, pos: pos}, map[string]bool{}) {
|
|
498
|
+
t = internalTypeExprForNode(owner, reg, prop.typeText, prop.typeNode, pos)
|
|
499
|
+
} else {
|
|
500
|
+
t = typeExprForNodePreferred(owner, reg, prop.typeText, prop.typeNode, pos, true)
|
|
501
|
+
}
|
|
502
|
+
if prop.optional {
|
|
503
|
+
t = "{kind: 12, types: [" + t + ", {kind: 4}]}"
|
|
504
|
+
}
|
|
505
|
+
return "{kind: 20, name: " + quote(prop.name) + ", type: " + t + ", optional: " + boolLit(prop.optional) + "}"
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
func mapUtilityProperties(values []utilityProperty, mapper func(utilityProperty) string) []string {
|
|
509
|
+
out := make([]string, 0, len(values))
|
|
510
|
+
for _, value := range values {
|
|
511
|
+
out = append(out, mapper(value))
|
|
512
|
+
}
|
|
513
|
+
return out
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
func utilityTypeExpr(info *fileInfo, reg *registry, name string, args []string, ctx *typeContext) (string, bool) {
|
|
517
|
+
props, owner, ok := utilityTypeProperties(info, reg, name, args, ctx)
|
|
518
|
+
if !ok {
|
|
519
|
+
return "", false
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
sourceExpr := typeExprCtx(info, reg, firstArg(args), ctx)
|
|
523
|
+
keysExpr := "[]"
|
|
524
|
+
if name == "Pick" || name == "Omit" {
|
|
525
|
+
keysExpr = utilityKeysExpr(firstArg(args[1:]))
|
|
526
|
+
}
|
|
527
|
+
return "{kind: 18, typeName: " + quote(name) + ", utilityType: " + quote(name) + ", typeArguments: [" + sourceExpr +
|
|
528
|
+
"], utilityKeys: " + keysExpr + ", types: [" + renderUtilityProperties(owner, reg, props, ctx) + "]}", true
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
func runtimeUtilityTypeExpr(info *fileInfo, reg *registry, name string, args []string, ctx *typeContext) (string, bool) {
|
|
532
|
+
if len(args) == 0 {
|
|
533
|
+
return "", false
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
sourceExpr := typeExprCtx(info, reg, firstArg(args), ctx)
|
|
537
|
+
keysExpr := "[]"
|
|
538
|
+
if name == "Pick" || name == "Omit" {
|
|
539
|
+
keysExpr = utilityKeysExpr(firstArg(args[1:]))
|
|
540
|
+
}
|
|
541
|
+
return "{kind: 18, typeName: " + quote(name) + ", utilityType: " + quote(name) + ", typeArguments: [" + sourceExpr + "], utilityKeys: " + keysExpr + ", types: []}", true
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
func isIdentityMappedAlias(info *fileInfo, reg *registry, name string) bool {
|
|
545
|
+
alias, _, _, ok := resolveAliasRef(info, reg, name)
|
|
546
|
+
if !ok {
|
|
547
|
+
return false
|
|
548
|
+
}
|
|
549
|
+
_, ok = identityMappedAliasParam(alias)
|
|
550
|
+
return ok
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
func identityMappedAliasParam(alias aliasInfo) (string, bool) {
|
|
554
|
+
body := compactTypePattern(alias.body)
|
|
555
|
+
re := regexp.MustCompile(`^\{\[([A-Za-z_$][\w$]*)inkeyof([A-Za-z_$][\w$]*)\]:([A-Za-z_$][\w$]*)\[([A-Za-z_$][\w$]*)\];?\}$`)
|
|
556
|
+
match := re.FindStringSubmatch(body)
|
|
557
|
+
if match == nil || match[1] != match[4] || match[2] != match[3] {
|
|
558
|
+
return "", false
|
|
559
|
+
}
|
|
560
|
+
if !aliasHasParam(alias, match[2]) {
|
|
561
|
+
return "", false
|
|
562
|
+
}
|
|
563
|
+
return match[2], true
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
func aliasHasParam(alias aliasInfo, name string) bool {
|
|
567
|
+
for _, param := range alias.params {
|
|
568
|
+
if param == name {
|
|
569
|
+
return true
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return false
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
func sameTypeText(left string, right string) bool {
|
|
576
|
+
return compactTypePattern(left) == compactTypePattern(right)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
func compactTypePattern(raw string) string {
|
|
580
|
+
var out strings.Builder
|
|
581
|
+
for _, char := range raw {
|
|
582
|
+
if char == ' ' || char == '\t' || char == '\n' || char == '\r' {
|
|
583
|
+
continue
|
|
584
|
+
}
|
|
585
|
+
out.WriteRune(char)
|
|
586
|
+
}
|
|
587
|
+
return out.String()
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
func indexedTypeExpr(info *fileInfo, reg *registry, raw string, ctx *typeContext) string {
|
|
591
|
+
raw = strings.TrimSpace(trimParens(raw))
|
|
592
|
+
if resolved, owner, ok := resolveTypeText(info, reg, raw, ctx); ok && strings.TrimSpace(resolved) != raw {
|
|
593
|
+
return indexedTypeExpr(owner, reg, resolved, ctx)
|
|
594
|
+
}
|
|
595
|
+
parts := nonEmptyParts(splitTop(raw, "|"))
|
|
596
|
+
if len(parts) > 1 {
|
|
597
|
+
nullish := []string{}
|
|
598
|
+
nonNullish := []string{}
|
|
599
|
+
for _, part := range parts {
|
|
600
|
+
part = strings.TrimSpace(trimParens(part))
|
|
601
|
+
if part == "null" || part == "undefined" {
|
|
602
|
+
nullish = append(nullish, part)
|
|
603
|
+
} else {
|
|
604
|
+
nonNullish = append(nonNullish, part)
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if len(nullish) > 0 {
|
|
608
|
+
types := []string{}
|
|
609
|
+
if len(nonNullish) > 0 {
|
|
610
|
+
types = append(types, indexedNonNullTypeExpr(info, reg, strings.Join(nonNullish, " | "), ctx))
|
|
611
|
+
}
|
|
612
|
+
for _, part := range nullish {
|
|
613
|
+
types = append(types, typeExprCtx(info, reg, part, ctx))
|
|
614
|
+
}
|
|
615
|
+
return "{kind: 12, types: [" + strings.Join(types, ", ") + "]}"
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return indexedNonNullTypeExpr(info, reg, raw, ctx)
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
func indexedNonNullTypeExpr(info *fileInfo, reg *registry, raw string, ctx *typeContext) string {
|
|
622
|
+
bodyType := typeExprCtx(info, reg, raw, ctx)
|
|
623
|
+
return "{kind: 13, typeName: \"Indexed\", types: [" + bodyType + ", {kind: 2, typeName: \"Index\"}]}"
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
func utilityTypeProperties(info *fileInfo, reg *registry, name string, args []string, ctx *typeContext) ([]utilityProperty, *fileInfo, bool) {
|
|
627
|
+
source := firstArg(args)
|
|
628
|
+
props, owner, ok := utilitySourceProperties(info, reg, source, ctx)
|
|
629
|
+
if !ok {
|
|
630
|
+
return nil, nil, false
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
switch name {
|
|
634
|
+
case "Pick":
|
|
635
|
+
keys := utilityKeys(firstArg(args[1:]))
|
|
636
|
+
props = filterUtilityProperties(props, func(prop utilityProperty) bool { return keys[prop.name] })
|
|
637
|
+
case "Omit":
|
|
638
|
+
keys := utilityKeys(firstArg(args[1:]))
|
|
639
|
+
props = filterUtilityProperties(props, func(prop utilityProperty) bool { return !keys[prop.name] })
|
|
640
|
+
case "Partial":
|
|
641
|
+
for i := range props {
|
|
642
|
+
props[i].optional = true
|
|
643
|
+
}
|
|
644
|
+
case "Required":
|
|
645
|
+
for i := range props {
|
|
646
|
+
props[i].optional = false
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return props, owner, true
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
func utilitySourceProperties(info *fileInfo, reg *registry, source string, ctx *typeContext) ([]utilityProperty, *fileInfo, bool) {
|
|
654
|
+
source = strings.TrimSpace(source)
|
|
655
|
+
if parts := splitTop(source, "&"); len(parts) > 1 {
|
|
656
|
+
props := []utilityProperty{}
|
|
657
|
+
owner := info
|
|
658
|
+
failed := false
|
|
659
|
+
for _, part := range parts {
|
|
660
|
+
partProps, partOwner, ok := utilitySourceProperties(info, reg, part, ctx)
|
|
661
|
+
if !ok {
|
|
662
|
+
if isMetadataOnlyIntersectionPart(part) {
|
|
663
|
+
continue
|
|
664
|
+
}
|
|
665
|
+
failed = true
|
|
666
|
+
continue
|
|
667
|
+
}
|
|
668
|
+
props = append(props, partProps...)
|
|
669
|
+
owner = partOwner
|
|
670
|
+
}
|
|
671
|
+
if failed {
|
|
672
|
+
return nil, nil, false
|
|
673
|
+
}
|
|
674
|
+
if len(props) > 0 {
|
|
675
|
+
return props, owner, true
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
if resolved, owner, ok := resolveTypeText(info, reg, source, ctx); ok && strings.TrimSpace(resolved) != source {
|
|
679
|
+
return utilitySourceProperties(owner, reg, resolved, ctx)
|
|
680
|
+
}
|
|
681
|
+
if name, args, ok := generic(source); ok {
|
|
682
|
+
switch name {
|
|
683
|
+
case "Pick", "Omit", "Partial", "Required":
|
|
684
|
+
return utilityTypeProperties(info, reg, name, args, ctx)
|
|
685
|
+
case "ApiType":
|
|
686
|
+
if len(args) > 1 {
|
|
687
|
+
return utilitySourceProperties(info, reg, args[1], ctx)
|
|
688
|
+
}
|
|
689
|
+
case "Indexed":
|
|
690
|
+
return utilitySourceProperties(info, reg, firstArg(args), ctx)
|
|
691
|
+
case "EntityFields", "EntityOptionals", "NewEntityFields":
|
|
692
|
+
return utilitySourceProperties(info, reg, firstArg(args), ctx)
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
if isObjectLiteralTypeText(source) {
|
|
696
|
+
return withUtilityPropertyOwner(propertiesFromBody(strings.TrimSpace(source[1:len(source)-1])), info), info, true
|
|
697
|
+
}
|
|
698
|
+
if class, owner, ok := resolveClassRefAt(info, reg, source, ctx.pos); ok {
|
|
699
|
+
props := make([]utilityProperty, 0, len(class.properties))
|
|
700
|
+
for _, prop := range class.properties {
|
|
701
|
+
props = append(props, utilityProperty{name: prop.name, typeText: prop.typeText, typeNode: prop.typeNode, optional: prop.optional, owner: owner})
|
|
702
|
+
}
|
|
703
|
+
return props, owner, true
|
|
704
|
+
}
|
|
705
|
+
if decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, source, ctx.pos); ok {
|
|
706
|
+
return interfaceFullProperties(owner, reg, decl, map[string]bool{}), owner, true
|
|
707
|
+
}
|
|
708
|
+
if alias, owner, _, ok := resolveAliasRef(info, reg, source); ok {
|
|
709
|
+
if isObjectLiteralTypeText(alias.body) {
|
|
710
|
+
body := strings.TrimSpace(alias.body)
|
|
711
|
+
return withUtilityPropertyOwner(propertiesFromBody(strings.TrimSpace(body[1:len(body)-1])), owner), owner, true
|
|
712
|
+
}
|
|
713
|
+
if props, propOwner, ok := utilitySourceProperties(owner, reg, alias.body, ctx); ok {
|
|
714
|
+
return props, propOwner, true
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
return nil, nil, false
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
func isMetadataOnlyIntersectionPart(raw string) bool {
|
|
721
|
+
raw = strings.TrimSpace(trimParens(raw))
|
|
722
|
+
name, _, ok := generic(raw)
|
|
723
|
+
if !ok {
|
|
724
|
+
name = raw
|
|
725
|
+
}
|
|
726
|
+
switch name {
|
|
727
|
+
case "ApiName", "TypeAnnotation", "MinLength", "MaxLength", "Minimum", "GreaterThan", "Maximum", "LessThan", "Pattern", "Validate",
|
|
728
|
+
"DatabaseField", "MySQL", "Reference", "Index", "Unique", "PrimaryKey", "AutoIncrement",
|
|
729
|
+
"HttpBody", "HttpQueries", "HttpQuery", "HttpPath", "HttpHeader":
|
|
730
|
+
return true
|
|
731
|
+
default:
|
|
732
|
+
return false
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
func indexedAccessTypeExpr(info *fileInfo, reg *registry, raw string, ctx *typeContext) (string, bool) {
|
|
737
|
+
source, index, ok := trailingIndexedAccess(raw)
|
|
738
|
+
if !ok {
|
|
739
|
+
return "", false
|
|
740
|
+
}
|
|
741
|
+
if propertyName, ok := indexedAccessPropertyName(index); ok {
|
|
742
|
+
if propertyType, owner, ok := propertyTypeText(info, reg, source, propertyName, ctx); ok {
|
|
743
|
+
return typeExprCtx(owner, reg, propertyType, ctx), true
|
|
744
|
+
}
|
|
745
|
+
return "{kind: 2, typeName: " + quote(raw) + "}", true
|
|
746
|
+
}
|
|
747
|
+
if strings.TrimSpace(index) == "number" {
|
|
748
|
+
if elementType, owner, ok := arrayElementTypeText(info, reg, source, ctx); ok {
|
|
749
|
+
return typeExprCtx(owner, reg, elementType, ctx), true
|
|
750
|
+
}
|
|
751
|
+
return "{kind: 2, typeName: " + quote(raw) + "}", true
|
|
752
|
+
}
|
|
753
|
+
return "{kind: 2, typeName: " + quote(raw) + "}", true
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
func resolveTypeText(info *fileInfo, reg *registry, raw string, ctx *typeContext) (string, *fileInfo, bool) {
|
|
757
|
+
raw = strings.TrimSpace(trimParens(raw))
|
|
758
|
+
if raw == "" {
|
|
759
|
+
return "", nil, false
|
|
760
|
+
}
|
|
761
|
+
if source, index, ok := trailingIndexedAccess(raw); ok {
|
|
762
|
+
if propertyName, ok := indexedAccessPropertyName(index); ok {
|
|
763
|
+
return propertyTypeText(info, reg, source, propertyName, ctx)
|
|
764
|
+
}
|
|
765
|
+
if strings.TrimSpace(index) == "number" {
|
|
766
|
+
return arrayElementTypeText(info, reg, source, ctx)
|
|
767
|
+
}
|
|
768
|
+
return "", nil, false
|
|
769
|
+
}
|
|
770
|
+
if name, args, ok := generic(raw); ok {
|
|
771
|
+
if name == "NonNullable" {
|
|
772
|
+
source := firstArg(args)
|
|
773
|
+
if resolved, owner, ok := resolveTypeText(info, reg, source, ctx); ok {
|
|
774
|
+
return nonNullableTypeText(resolved), owner, true
|
|
775
|
+
}
|
|
776
|
+
return nonNullableTypeText(source), info, true
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if alias, owner, _, ok := resolveAliasRef(info, reg, raw); ok && len(alias.params) == 0 {
|
|
780
|
+
return alias.body, owner, true
|
|
781
|
+
}
|
|
782
|
+
return "", nil, false
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
func propertyTypeText(info *fileInfo, reg *registry, source string, propertyName string, ctx *typeContext) (string, *fileInfo, bool) {
|
|
786
|
+
source = strings.TrimSpace(trimParens(source))
|
|
787
|
+
if resolved, owner, ok := resolveTypeText(info, reg, source, ctx); ok && strings.TrimSpace(resolved) != source {
|
|
788
|
+
return propertyTypeText(owner, reg, resolved, propertyName, ctx)
|
|
789
|
+
}
|
|
790
|
+
if strings.HasSuffix(source, "[]") {
|
|
791
|
+
return propertyTypeText(info, reg, strings.TrimSpace(strings.TrimSuffix(source, "[]")), propertyName, ctx)
|
|
792
|
+
}
|
|
793
|
+
if parts := splitTop(source, "&"); len(parts) > 1 {
|
|
794
|
+
propertyType := ""
|
|
795
|
+
propertyOwner := info
|
|
796
|
+
found := false
|
|
797
|
+
for _, part := range parts {
|
|
798
|
+
partType, partOwner, ok := propertyTypeText(info, reg, part, propertyName, ctx)
|
|
799
|
+
if !ok {
|
|
800
|
+
continue
|
|
801
|
+
}
|
|
802
|
+
propertyType = partType
|
|
803
|
+
propertyOwner = partOwner
|
|
804
|
+
found = true
|
|
805
|
+
}
|
|
806
|
+
if found {
|
|
807
|
+
return propertyType, propertyOwner, true
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
if isObjectLiteralTypeText(source) {
|
|
811
|
+
if prop, ok := findUtilityProperty(propertiesFromBody(strings.TrimSpace(source[1:len(source)-1])), propertyName); ok {
|
|
812
|
+
return prop.typeText, info, true
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if name, args, ok := generic(source); ok {
|
|
816
|
+
switch name {
|
|
817
|
+
case "Promise", "Array", "ReadonlyArray":
|
|
818
|
+
return propertyTypeText(info, reg, firstArg(args), propertyName, ctx)
|
|
819
|
+
case "Pick", "Omit", "Partial", "Required":
|
|
820
|
+
if props, owner, ok := utilityTypeProperties(info, reg, name, args, ctx); ok {
|
|
821
|
+
if prop, ok := findUtilityProperty(props, propertyName); ok {
|
|
822
|
+
if prop.owner != nil {
|
|
823
|
+
owner = prop.owner
|
|
824
|
+
}
|
|
825
|
+
return prop.typeText, owner, true
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
case "EntityFields", "EntityOptionals", "NewEntityFields":
|
|
829
|
+
if props, owner, ok := utilitySourceProperties(info, reg, firstArg(args), ctx); ok {
|
|
830
|
+
if prop, ok := findUtilityProperty(props, propertyName); ok {
|
|
831
|
+
if prop.owner != nil {
|
|
832
|
+
owner = prop.owner
|
|
833
|
+
}
|
|
834
|
+
return prop.typeText, owner, true
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
if class, owner, ok := resolveClassRefAt(info, reg, source, ctx.pos); ok {
|
|
840
|
+
for _, prop := range class.properties {
|
|
841
|
+
if prop.name == propertyName {
|
|
842
|
+
return prop.typeText, owner, true
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
if decl, owner, _, ok := resolveInterfaceDeclRefAt(info, reg, source, ctx.pos); ok {
|
|
847
|
+
if prop, ok := findUtilityProperty(interfaceFullProperties(owner, reg, decl, map[string]bool{}), propertyName); ok {
|
|
848
|
+
if prop.owner != nil {
|
|
849
|
+
owner = prop.owner
|
|
850
|
+
}
|
|
851
|
+
return prop.typeText, owner, true
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
if alias, owner, _, ok := resolveAliasRef(info, reg, source); ok && len(alias.params) == 0 {
|
|
855
|
+
return propertyTypeText(owner, reg, alias.body, propertyName, ctx)
|
|
856
|
+
}
|
|
857
|
+
return "", nil, false
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
func withUtilityPropertyOwner(props []utilityProperty, owner *fileInfo) []utilityProperty {
|
|
861
|
+
for i := range props {
|
|
862
|
+
if props[i].owner == nil {
|
|
863
|
+
props[i].owner = owner
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
return props
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
func arrayElementTypeText(info *fileInfo, reg *registry, source string, ctx *typeContext) (string, *fileInfo, bool) {
|
|
870
|
+
source = strings.TrimSpace(trimParens(source))
|
|
871
|
+
if resolved, owner, ok := resolveTypeText(info, reg, source, ctx); ok && strings.TrimSpace(resolved) != source {
|
|
872
|
+
source = strings.TrimSpace(resolved)
|
|
873
|
+
info = owner
|
|
874
|
+
}
|
|
875
|
+
if strings.HasSuffix(source, "[]") {
|
|
876
|
+
return strings.TrimSpace(strings.TrimSuffix(source, "[]")), info, true
|
|
877
|
+
}
|
|
878
|
+
if name, args, ok := generic(source); ok {
|
|
879
|
+
if name == "Array" || name == "ReadonlyArray" {
|
|
880
|
+
return firstArg(args), info, true
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if strings.HasPrefix(source, "[") && strings.HasSuffix(source, "]") {
|
|
884
|
+
items := nonEmptyParts(splitTop(strings.TrimSpace(source[1:len(source)-1]), ","))
|
|
885
|
+
if len(items) == 1 {
|
|
886
|
+
return items[0], info, true
|
|
887
|
+
}
|
|
888
|
+
if len(items) > 1 {
|
|
889
|
+
return strings.Join(items, " | "), info, true
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return "", nil, false
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
func trailingIndexedAccess(raw string) (string, string, bool) {
|
|
896
|
+
raw = strings.TrimSpace(raw)
|
|
897
|
+
if !strings.HasSuffix(raw, "]") {
|
|
898
|
+
return "", "", false
|
|
899
|
+
}
|
|
900
|
+
start := -1
|
|
901
|
+
depthAngle, depthBrace, depthParen, depthBracket := 0, 0, 0, 0
|
|
902
|
+
quote := byte(0)
|
|
903
|
+
for i := 0; i < len(raw); i++ {
|
|
904
|
+
c := raw[i]
|
|
905
|
+
if quote != 0 {
|
|
906
|
+
if c == quote && (i == 0 || raw[i-1] != '\\') {
|
|
907
|
+
quote = 0
|
|
908
|
+
}
|
|
909
|
+
continue
|
|
910
|
+
}
|
|
911
|
+
switch c {
|
|
912
|
+
case '\'', '"', '`':
|
|
913
|
+
quote = c
|
|
914
|
+
case '<':
|
|
915
|
+
depthAngle++
|
|
916
|
+
case '>':
|
|
917
|
+
if depthAngle > 0 {
|
|
918
|
+
depthAngle--
|
|
919
|
+
}
|
|
920
|
+
case '{':
|
|
921
|
+
depthBrace++
|
|
922
|
+
case '}':
|
|
923
|
+
if depthBrace > 0 {
|
|
924
|
+
depthBrace--
|
|
925
|
+
}
|
|
926
|
+
case '(':
|
|
927
|
+
depthParen++
|
|
928
|
+
case ')':
|
|
929
|
+
if depthParen > 0 {
|
|
930
|
+
depthParen--
|
|
931
|
+
}
|
|
932
|
+
case '[':
|
|
933
|
+
if depthAngle == 0 && depthBrace == 0 && depthParen == 0 && depthBracket == 0 {
|
|
934
|
+
start = i
|
|
935
|
+
}
|
|
936
|
+
depthBracket++
|
|
937
|
+
case ']':
|
|
938
|
+
if depthBracket > 0 {
|
|
939
|
+
depthBracket--
|
|
940
|
+
}
|
|
941
|
+
if i == len(raw)-1 && depthAngle == 0 && depthBrace == 0 && depthParen == 0 && depthBracket == 0 && start > 0 {
|
|
942
|
+
return strings.TrimSpace(raw[:start]), strings.TrimSpace(raw[start+1 : i]), true
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return "", "", false
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
func indexedAccessPropertyName(index string) (string, bool) {
|
|
950
|
+
index = strings.TrimSpace(index)
|
|
951
|
+
if index == "" || index == "number" {
|
|
952
|
+
return "", false
|
|
953
|
+
}
|
|
954
|
+
if strings.HasPrefix(index, "'") || strings.HasPrefix(index, "\"") {
|
|
955
|
+
return literalStringValue(index), true
|
|
956
|
+
}
|
|
957
|
+
if isIdentifierName(index) {
|
|
958
|
+
return index, true
|
|
959
|
+
}
|
|
960
|
+
return "", false
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
func findUtilityProperty(props []utilityProperty, name string) (utilityProperty, bool) {
|
|
964
|
+
for _, prop := range props {
|
|
965
|
+
if prop.name == name {
|
|
966
|
+
return prop, true
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return utilityProperty{}, false
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
func nonNullableTypeText(raw string) string {
|
|
973
|
+
parts := nonEmptyParts(splitTop(raw, "|"))
|
|
974
|
+
if len(parts) <= 1 {
|
|
975
|
+
return strings.TrimSpace(raw)
|
|
976
|
+
}
|
|
977
|
+
nonNull := []string{}
|
|
978
|
+
for _, part := range parts {
|
|
979
|
+
if part == "null" || part == "undefined" {
|
|
980
|
+
continue
|
|
981
|
+
}
|
|
982
|
+
nonNull = append(nonNull, part)
|
|
983
|
+
}
|
|
984
|
+
if len(nonNull) == 0 {
|
|
985
|
+
return "never"
|
|
986
|
+
}
|
|
987
|
+
return strings.Join(nonNull, " | ")
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
func utilityKeys(raw string) map[string]bool {
|
|
991
|
+
keys := map[string]bool{}
|
|
992
|
+
for _, part := range splitTop(raw, "|") {
|
|
993
|
+
part = strings.TrimSpace(part)
|
|
994
|
+
if part == "" {
|
|
995
|
+
continue
|
|
996
|
+
}
|
|
997
|
+
keys[literalStringValue(part)] = true
|
|
998
|
+
}
|
|
999
|
+
return keys
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
func utilityKeysExpr(raw string) string {
|
|
1003
|
+
values := []string{}
|
|
1004
|
+
for _, part := range splitTop(raw, "|") {
|
|
1005
|
+
part = strings.TrimSpace(part)
|
|
1006
|
+
if part == "" {
|
|
1007
|
+
continue
|
|
1008
|
+
}
|
|
1009
|
+
values = append(values, quote(literalStringValue(part)))
|
|
1010
|
+
}
|
|
1011
|
+
return "[" + strings.Join(values, ", ") + "]"
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
func enumValuesFromBody(body string) []string {
|
|
1015
|
+
body = stripTypeComments(body)
|
|
1016
|
+
values := []string{}
|
|
1017
|
+
nextNumber := 0
|
|
1018
|
+
for _, field := range splitTop(body, ",") {
|
|
1019
|
+
field = strings.TrimSpace(field)
|
|
1020
|
+
if field == "" {
|
|
1021
|
+
continue
|
|
1022
|
+
}
|
|
1023
|
+
name, initializer, hasInitializer := strings.Cut(field, "=")
|
|
1024
|
+
name = strings.TrimSpace(name)
|
|
1025
|
+
if name == "" {
|
|
1026
|
+
continue
|
|
1027
|
+
}
|
|
1028
|
+
if !hasInitializer {
|
|
1029
|
+
values = append(values, strconv.Itoa(nextNumber))
|
|
1030
|
+
nextNumber++
|
|
1031
|
+
continue
|
|
1032
|
+
}
|
|
1033
|
+
initializer = strings.TrimSpace(initializer)
|
|
1034
|
+
if strings.HasPrefix(initializer, "\"") || strings.HasPrefix(initializer, "'") || strings.HasPrefix(initializer, "`") {
|
|
1035
|
+
values = append(values, normalizeStringLiteral(initializer))
|
|
1036
|
+
continue
|
|
1037
|
+
}
|
|
1038
|
+
if _, err := strconv.ParseFloat(initializer, 64); err == nil {
|
|
1039
|
+
values = append(values, initializer)
|
|
1040
|
+
if parsed, err := strconv.Atoi(initializer); err == nil {
|
|
1041
|
+
nextNumber = parsed + 1
|
|
1042
|
+
}
|
|
1043
|
+
continue
|
|
1044
|
+
}
|
|
1045
|
+
values = append(values, quote(strings.Trim(name, "\"'`")))
|
|
1046
|
+
}
|
|
1047
|
+
return values
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
func enumTypeExpr(enum enumInfo, name string) string {
|
|
1051
|
+
return "{kind: 11, typeName: " + quote(name) + ", values: [" + strings.Join(enum.values, ", ") + "]}"
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
func filterUtilityProperties(props []utilityProperty, keep func(utilityProperty) bool) []utilityProperty {
|
|
1055
|
+
out := []utilityProperty{}
|
|
1056
|
+
for _, prop := range props {
|
|
1057
|
+
if keep(prop) {
|
|
1058
|
+
out = append(out, prop)
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
return out
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
func annotationValueExpr(info *fileInfo, reg *registry, raw string, ctx *typeContext) string {
|
|
1065
|
+
parts := splitTop(strings.TrimSpace(raw), "&")
|
|
1066
|
+
if len(parts) <= 1 {
|
|
1067
|
+
return typeExprCtx(info, reg, raw, ctx)
|
|
1068
|
+
}
|
|
1069
|
+
props := []string{}
|
|
1070
|
+
for _, part := range parts {
|
|
1071
|
+
part = strings.TrimSpace(part)
|
|
1072
|
+
if part == "{}" {
|
|
1073
|
+
continue
|
|
1074
|
+
}
|
|
1075
|
+
if !isObjectLiteralTypeText(part) {
|
|
1076
|
+
return typeExprCtx(info, reg, raw, ctx)
|
|
1077
|
+
}
|
|
1078
|
+
body := strings.TrimSpace(part[1 : len(part)-1])
|
|
1079
|
+
props = append(props, objectLiteralProperties(info, reg, body, ctx)...)
|
|
1080
|
+
}
|
|
1081
|
+
return "{kind: 18, types: [" + strings.Join(props, ", ") + "]}"
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
func internalTypiaTagMarkerExpr(info *fileInfo, reg *registry, typeName string, args []string, kindIndex int, valueIndex int, schemaIndex int, ctx *typeContext) (string, bool) {
|
|
1085
|
+
if len(args) <= kindIndex {
|
|
1086
|
+
return "", false
|
|
1087
|
+
}
|
|
1088
|
+
kind := literalStringValue(args[kindIndex])
|
|
1089
|
+
value := "{kind: 4}"
|
|
1090
|
+
if len(args) > valueIndex {
|
|
1091
|
+
value = internalTagValueExpr(info, reg, args[valueIndex], ctx)
|
|
1092
|
+
}
|
|
1093
|
+
if strings.HasPrefix(kind, "database:") {
|
|
1094
|
+
payload := "undefined"
|
|
1095
|
+
if schemaIndex >= 0 && len(args) > schemaIndex {
|
|
1096
|
+
payload = plainValue(args[schemaIndex])
|
|
1097
|
+
} else if len(args) > valueIndex {
|
|
1098
|
+
payload = plainValue(args[valueIndex])
|
|
1099
|
+
}
|
|
1100
|
+
if expr, ok := internalDatabaseTagMarkerExpr(kind, payload); ok {
|
|
1101
|
+
return expr, true
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
if kind == "tsf:validator" {
|
|
1105
|
+
return validationMarker("Validator", "validator", value), true
|
|
1106
|
+
}
|
|
1107
|
+
if strings.HasPrefix(kind, "tsf:") || strings.HasPrefix(kind, "openapi:") {
|
|
1108
|
+
return typeAnnotationMarker("TypeAnnotation", kind, value), true
|
|
1109
|
+
}
|
|
1110
|
+
return "{kind: 2, typeName: " + quote(typeName) + "}", true
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
func internalDatabaseTagMarkerExpr(kind string, payload string) (string, bool) {
|
|
1114
|
+
switch kind {
|
|
1115
|
+
case "database:field":
|
|
1116
|
+
return "{kind: 2, typeName: \"DatabaseField\", database: {\"*\": " + payload + "}}", true
|
|
1117
|
+
case "database:mysql":
|
|
1118
|
+
return "{kind: 2, typeName: \"MySQL\", database: {mysql: " + payload + "}}", true
|
|
1119
|
+
case "database:primaryKey":
|
|
1120
|
+
return "{kind: 2, typeName: \"PrimaryKey\"}", true
|
|
1121
|
+
case "database:autoIncrement":
|
|
1122
|
+
return "{kind: 2, typeName: \"AutoIncrement\"}", true
|
|
1123
|
+
case "database:reference":
|
|
1124
|
+
return "{kind: 2, typeName: \"Reference\"}", true
|
|
1125
|
+
case "database:index":
|
|
1126
|
+
return "{kind: 2, typeName: \"Index\"}", true
|
|
1127
|
+
case "database:unique":
|
|
1128
|
+
return "{kind: 2, typeName: \"Unique\"}", true
|
|
1129
|
+
default:
|
|
1130
|
+
return "", false
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
func internalTagValueExpr(info *fileInfo, reg *registry, raw string, ctx *typeContext) string {
|
|
1135
|
+
raw = strings.TrimSpace(raw)
|
|
1136
|
+
if raw == "" || raw == "undefined" {
|
|
1137
|
+
return "{kind: 4}"
|
|
1138
|
+
}
|
|
1139
|
+
if isLiteralStringType(raw) || raw == "true" || raw == "false" || raw == "null" {
|
|
1140
|
+
return literalArg(raw)
|
|
1141
|
+
}
|
|
1142
|
+
if _, err := strconv.ParseFloat(raw, 64); err == nil {
|
|
1143
|
+
return literalArg(raw)
|
|
1144
|
+
}
|
|
1145
|
+
return annotationValueExpr(info, reg, raw, ctx)
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
func validationMarker(typeName string, name string, arg string) string {
|
|
1149
|
+
return "{kind: 2, typeName: " + quote(typeName) + ", validation: [{name: " + quote(name) + ", args: [" + arg + "]}]}"
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
func typeAnnotationMarker(typeName string, annotation string, value string) string {
|
|
1153
|
+
return "{kind: 2, typeName: " + quote(typeName) + ", annotations: {" + quote(annotation) + ": " + value + "}}"
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
func importedAliasExpr(reg *registry, ref importRef) string {
|
|
1157
|
+
return "{kind: 2, typeName: " + quote(ref.exportName) + "}"
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
func aliasTypeExprCtx(owner *fileInfo, reg *registry, alias aliasInfo, name string, ctx *typeContext) string {
|
|
1161
|
+
if strings.TrimSpace(alias.metadataText) != "" {
|
|
1162
|
+
return withTypeName(alias.metadataText, name)
|
|
1163
|
+
}
|
|
1164
|
+
return withTypeName(internalTypeExprForNodeCtx(owner, reg, alias.body, alias.typeNode, ctx), name)
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
func ensureAliasMetadata(owner *fileInfo, reg *registry, name string, alias aliasInfo) aliasInfo {
|
|
1168
|
+
if owner == nil || len(alias.params) != 0 || strings.TrimSpace(alias.metadataText) != "" {
|
|
1169
|
+
return alias
|
|
1170
|
+
}
|
|
1171
|
+
if current, ok := owner.aliases[name]; ok {
|
|
1172
|
+
if strings.TrimSpace(current.metadataText) != "" {
|
|
1173
|
+
return current
|
|
1174
|
+
}
|
|
1175
|
+
precomputeAliasMetadata(owner, reg, name, current)
|
|
1176
|
+
if updated, ok := owner.aliases[name]; ok {
|
|
1177
|
+
return updated
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
return alias
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
func importTypeReferenceExpr(info *fileInfo, reg *registry, raw string, ctx *typeContext) (string, bool) {
|
|
1184
|
+
spec, exportName, ok := parseImportTypeReference(raw)
|
|
1185
|
+
if !ok {
|
|
1186
|
+
return "", false
|
|
1187
|
+
}
|
|
1188
|
+
if target := resolveImport(info.file.FileName(), spec, reg); target != nil {
|
|
1189
|
+
if enum, _, _, ok := resolveExportedEnum(target, reg, exportName, map[string]bool{}); ok {
|
|
1190
|
+
return enumTypeExpr(enum, exportName), true
|
|
1191
|
+
}
|
|
1192
|
+
if decl, owner, _, ok := resolveExportedInterfaceDecl(target, reg, exportName, map[string]bool{}); ok {
|
|
1193
|
+
return interfaceObjectLiteralExpr(owner, reg, exportName, decl, ctx), true
|
|
1194
|
+
}
|
|
1195
|
+
if alias, owner, ownerName, ok := resolveExportedAlias(target, reg, exportName, map[string]bool{}); ok {
|
|
1196
|
+
if len(alias.params) > 0 {
|
|
1197
|
+
return "{kind: 2, typeName: " + quote(exportName) + "}", true
|
|
1198
|
+
}
|
|
1199
|
+
alias = ensureAliasMetadata(owner, reg, ownerName, alias)
|
|
1200
|
+
return aliasTypeExprCtx(owner, reg, alias, exportName, ctx), true
|
|
1201
|
+
}
|
|
1202
|
+
if _, ok := chooseClass(target, exportName, 0); ok {
|
|
1203
|
+
return importedClassTypeExpr(info, reg, exportName, spec, exportName, target), true
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return importedClassTypeExpr(info, reg, exportName, spec, exportName, nil), true
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
func parseImportTypeReference(raw string) (string, string, bool) {
|
|
1210
|
+
re := regexp.MustCompile(`^import\s*\(\s*['"]([^'"]+)['"]\s*\)\s*\.\s*([A-Za-z_$][\w$]*)$`)
|
|
1211
|
+
match := re.FindStringSubmatch(strings.TrimSpace(raw))
|
|
1212
|
+
if match == nil {
|
|
1213
|
+
return "", "", false
|
|
1214
|
+
}
|
|
1215
|
+
return match[1], match[2], true
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
func importedClassTypeExpr(info *fileInfo, reg *registry, typeName string, spec string, exportName string, target *fileInfo) string {
|
|
1219
|
+
return "{kind: 16, typeName: " + quote(typeName) + ", classType: () => " + importedRuntimeValueExpr(info, reg, spec, exportName, target) + "}"
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
func externalImportedTypeExpr(ref importRef, typeName string) string {
|
|
1223
|
+
if ref.spec == "" || ref.exportName == "" {
|
|
1224
|
+
return "{kind: 2, typeName: " + quote(typeName) + "}"
|
|
1225
|
+
}
|
|
1226
|
+
return runtimeAliasPlaceholderName + "(" + quote(ref.spec) + ", " + quote(ref.exportName) + ", " + quote(typeName) + ")"
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
func runtimeNamespacePlaceholder(spec string, target *fileInfo) string {
|
|
1230
|
+
targetFile := ""
|
|
1231
|
+
if target != nil && target.file != nil {
|
|
1232
|
+
targetFile = target.file.FileName()
|
|
1233
|
+
}
|
|
1234
|
+
return "__tsf_runtime_namespace__(" + quote(spec) + ", " + quote(targetFile) + ")"
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
func runtimeImportPlaceholder(spec string, exportName string, target *fileInfo) string {
|
|
1238
|
+
targetFile := ""
|
|
1239
|
+
if target != nil && target.file != nil {
|
|
1240
|
+
targetFile = target.file.FileName()
|
|
1241
|
+
}
|
|
1242
|
+
return "__tsf_runtime_import__(" + quote(spec) + ", " + quote(exportName) + ", " + quote(targetFile) + ")"
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
func isExternalImportRef(ref importRef) bool {
|
|
1246
|
+
return ref.spec != "" && !strings.HasPrefix(ref.spec, ".")
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
func isFoundationImportRef(ref importRef) bool {
|
|
1250
|
+
return isExternalImportRef(ref) && (ref.spec == foundationPackageSpec || ref.spec == reflectionPackageSpec)
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
func runtimeArg(info *fileInfo, reg *registry, raw string) string {
|
|
1254
|
+
return "{kind: 10, runtime: () => " + runtimeValueExpr(info, reg, raw) + "}"
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
func runtimeValueExpr(info *fileInfo, reg *registry, raw string) string {
|
|
1258
|
+
raw = strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(raw), "typeof "))
|
|
1259
|
+
if isIdentifierName(raw) {
|
|
1260
|
+
if ref, ok := info.imports[raw]; ok {
|
|
1261
|
+
var target *fileInfo
|
|
1262
|
+
if ref.source != "" {
|
|
1263
|
+
target = reg.byPath[ref.source]
|
|
1264
|
+
}
|
|
1265
|
+
return importedRuntimeValueExpr(info, reg, ref.spec, ref.exportName, target)
|
|
1266
|
+
}
|
|
1267
|
+
return runtimeIdentifierExpr(raw)
|
|
1268
|
+
}
|
|
1269
|
+
return raw
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
func importedRuntimeValueExpr(info *fileInfo, reg *registry, spec string, exportName string, target *fileInfo) string {
|
|
1273
|
+
_ = info
|
|
1274
|
+
_ = reg
|
|
1275
|
+
if spec == "" || exportName == "" {
|
|
1276
|
+
return "undefined"
|
|
1277
|
+
}
|
|
1278
|
+
return runtimeImportPlaceholder(spec, exportName, target)
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
func runtimeIdentifierExpr(name string) string {
|
|
1282
|
+
return "(typeof " + name + " !== \"undefined\" ? " + name + " : (typeof exports !== \"undefined\" ? exports." + name + " : undefined))"
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
func withTypeName(expr string, name string) string {
|
|
1286
|
+
expr = strings.TrimSpace(expr)
|
|
1287
|
+
if !strings.HasPrefix(expr, "{") || !strings.HasSuffix(expr, "}") {
|
|
1288
|
+
return expr
|
|
1289
|
+
}
|
|
1290
|
+
return strings.TrimSuffix(expr, "}") + ", typeName: " + quote(name) + "}"
|
|
1291
|
+
}
|