typia 15.0.0 → 15.0.1
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/lib/http.d.ts +49 -24
- package/lib/http.js.map +1 -1
- package/lib/http.mjs.map +1 -1
- package/lib/internal/_httpFormDataReadBigint.js +7 -5
- package/lib/internal/_httpFormDataReadBigint.js.map +1 -1
- package/lib/internal/_httpFormDataReadBigint.mjs +1 -1
- package/lib/internal/_httpFormDataReadBigint.mjs.map +1 -1
- package/lib/internal/_httpFormDataReadBoolean.js +12 -10
- package/lib/internal/_httpFormDataReadBoolean.js.map +1 -1
- package/lib/internal/_httpFormDataReadBoolean.mjs +1 -1
- package/lib/internal/_httpFormDataReadBoolean.mjs.map +1 -1
- package/lib/internal/_httpFormDataReadNumber.js +7 -5
- package/lib/internal/_httpFormDataReadNumber.js.map +1 -1
- package/lib/internal/_httpFormDataReadNumber.mjs +1 -1
- package/lib/internal/_httpFormDataReadNumber.mjs.map +1 -1
- package/lib/internal/_httpFormDataReadString.d.ts +9 -1
- package/lib/internal/_httpFormDataReadString.js +10 -2
- package/lib/internal/_httpFormDataReadString.js.map +1 -1
- package/lib/internal/_httpFormDataReadString.mjs +9 -1
- package/lib/internal/_httpFormDataReadString.mjs.map +1 -1
- package/lib/internal/_httpHeaderReadBigint.js +5 -1
- package/lib/internal/_httpHeaderReadBigint.js.map +1 -1
- package/lib/internal/_httpHeaderReadBigint.mjs +2 -1
- package/lib/internal/_httpHeaderReadBigint.mjs.map +1 -1
- package/lib/internal/_httpHeaderReadNumber.js +5 -1
- package/lib/internal/_httpHeaderReadNumber.js.map +1 -1
- package/lib/internal/_httpHeaderReadNumber.mjs +2 -1
- package/lib/internal/_httpHeaderReadNumber.mjs.map +1 -1
- package/lib/internal/_httpParameterReadBigint.js +4 -0
- package/lib/internal/_httpParameterReadBigint.js.map +1 -1
- package/lib/internal/_httpParameterReadBigint.mjs +1 -0
- package/lib/internal/_httpParameterReadBigint.mjs.map +1 -1
- package/lib/internal/_httpParameterReadNumber.js +4 -0
- package/lib/internal/_httpParameterReadNumber.js.map +1 -1
- package/lib/internal/_httpParameterReadNumber.mjs +1 -0
- package/lib/internal/_httpParameterReadNumber.mjs.map +1 -1
- package/lib/internal/_httpParameterReadString.d.ts +9 -1
- package/lib/internal/_httpParameterReadString.js +9 -1
- package/lib/internal/_httpParameterReadString.js.map +1 -1
- package/lib/internal/_httpParameterReadString.mjs +9 -1
- package/lib/internal/_httpParameterReadString.mjs.map +1 -1
- package/lib/internal/_httpQueryReadBigint.js +8 -1
- package/lib/internal/_httpQueryReadBigint.js.map +1 -1
- package/lib/internal/_httpQueryReadBigint.mjs +1 -1
- package/lib/internal/_httpQueryReadBigint.mjs.map +1 -1
- package/lib/internal/_httpQueryReadBoolean.js +4 -1
- package/lib/internal/_httpQueryReadBoolean.js.map +1 -1
- package/lib/internal/_httpQueryReadBoolean.mjs +1 -1
- package/lib/internal/_httpQueryReadBoolean.mjs.map +1 -1
- package/lib/internal/_httpQueryReadNumber.js +8 -1
- package/lib/internal/_httpQueryReadNumber.js.map +1 -1
- package/lib/internal/_httpQueryReadNumber.mjs +1 -1
- package/lib/internal/_httpQueryReadNumber.mjs.map +1 -1
- package/lib/internal/_httpQueryReadString.d.ts +9 -1
- package/lib/internal/_httpQueryReadString.js +9 -1
- package/lib/internal/_httpQueryReadString.js.map +1 -1
- package/lib/internal/_httpQueryReadString.mjs +9 -1
- package/lib/internal/_httpQueryReadString.mjs.map +1 -1
- package/lib/internal/_randomBigint.d.ts +12 -1
- package/lib/internal/_randomBigint.js +90 -2
- package/lib/internal/_randomBigint.js.map +1 -1
- package/lib/internal/_randomBigint.mjs +70 -2
- package/lib/internal/_randomBigint.mjs.map +1 -1
- package/lib/internal/_randomInteger.js +21 -12
- package/lib/internal/_randomInteger.js.map +1 -1
- package/lib/internal/_randomInteger.mjs +21 -16
- package/lib/internal/_randomInteger.mjs.map +1 -1
- package/lib/internal/_randomNumber.js +19 -10
- package/lib/internal/_randomNumber.js.map +1 -1
- package/lib/internal/_randomNumber.mjs +19 -14
- package/lib/internal/_randomNumber.mjs.map +1 -1
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_invalid_probability_test.go +9 -0
- package/native/cmd/ttsc-typia/random_recursive_min_items_diagnostic_test.go +18 -1
- package/native/core/factories/ExpressionFactory.go +16 -1
- package/native/core/factories/MetadataCommentTagFactory.go +177 -29
- package/native/core/factories/expression_factory_number_spells_non_finite_values_test.go +69 -0
- package/native/core/factories/metadata_comment_tag_factory_holds_bigint_tags_exact_test.go +168 -0
- package/native/core/factories/metadata_comment_tag_factory_reads_javascript_numbers_test.go +158 -0
- package/native/core/programmers/functional/FunctionalAssertParametersProgrammer.go +1 -3
- package/native/core/programmers/functional/FunctionalIsParametersProgrammer.go +107 -9
- package/native/core/programmers/functional/FunctionalValidateParametersProgrammer.go +1 -3
- package/native/core/programmers/http/HttpFormDataProgrammer.go +41 -2
- package/native/core/programmers/http/HttpHeadersProgrammer.go +56 -4
- package/native/core/programmers/http/HttpParameterProgrammer.go +1 -3
- package/native/core/programmers/http/HttpQueryProgrammer.go +26 -43
- package/native/core/programmers/iterate/json_schema_jsDocTags.go +10 -3
- package/native/core/programmers/iterate/json_schema_jsdoc_tags_cast_reads_javascript_numbers_test.go +64 -0
- package/native/core/programmers/llm/LlmEvaluationProgrammer.go +6 -2
- package/native/core/programmers/llm/LlmSchemaProgrammer.go +34 -4
- package/native/core/utils/NumberUtil.go +195 -0
- package/native/core/utils/number_util_rational_keeps_written_value_test.go +62 -0
- package/native/core/utils/number_util_reads_javascript_number_grammar_test.go +147 -0
- package/package.json +3 -3
- package/src/http.ts +61 -34
- package/src/internal/_httpFormDataReadBigint.ts +3 -1
- package/src/internal/_httpFormDataReadBoolean.ts +3 -1
- package/src/internal/_httpFormDataReadNumber.ts +3 -1
- package/src/internal/_httpFormDataReadString.ts +10 -1
- package/src/internal/_httpHeaderReadBigint.ts +6 -1
- package/src/internal/_httpHeaderReadNumber.ts +6 -1
- package/src/internal/_httpParameterReadBigint.ts +3 -0
- package/src/internal/_httpParameterReadNumber.ts +3 -0
- package/src/internal/_httpParameterReadString.ts +12 -2
- package/src/internal/_httpQueryReadBigint.ts +7 -1
- package/src/internal/_httpQueryReadBoolean.ts +3 -1
- package/src/internal/_httpQueryReadNumber.ts +7 -1
- package/src/internal/_httpQueryReadString.ts +10 -1
- package/src/internal/_randomBigint.ts +111 -3
- package/src/internal/_randomInteger.ts +31 -16
- package/src/internal/_randomNumber.ts +23 -12
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
package factories
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"reflect"
|
|
5
|
+
"testing"
|
|
6
|
+
|
|
7
|
+
schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// TestMetadataCommentTagFactoryReadsJavaScriptNumbers verifies numeric JSDoc
|
|
11
|
+
// comment tags read JavaScript numbers and splice their values.
|
|
12
|
+
//
|
|
13
|
+
// The tags used Go's float syntax, and each record spliced the raw tag text into
|
|
14
|
+
// the emitted validator (samchon/typia#2442). Go-only spellings therefore became
|
|
15
|
+
// broken JavaScript: `@minimum inf` emitted `inf <= $input`, a ReferenceError,
|
|
16
|
+
// while `@minimum 0x10`, which JavaScript reads as 16, was rejected. The bigint
|
|
17
|
+
// splice appended `n` to the text, so an integer spelled `1e3` emitted `1e3n`,
|
|
18
|
+
// which is no BigInt literal. A non-finite value has no JSON spelling for the
|
|
19
|
+
// schema keyword and is reported (samchon/typia#2452). The expectations are the
|
|
20
|
+
// values `Number(text)` yields in JavaScript.
|
|
21
|
+
//
|
|
22
|
+
// 1. Read `0x10`, `1e3`, `+5`, and `.5` as their JavaScript values, and splice
|
|
23
|
+
// the value into both the number and the bigint records, with integer
|
|
24
|
+
// spellings keeping their exact digits.
|
|
25
|
+
// 2. Report Go-only spellings as invalid numbers and infinities as non-finite.
|
|
26
|
+
// 3. Keep ordinary spellings byte-identical, and every tag name in its source
|
|
27
|
+
// spelling.
|
|
28
|
+
func TestMetadataCommentTagFactoryReadsJavaScriptNumbers(t *testing.T) {
|
|
29
|
+
parse := func(name string, value string) (metadataCommentTagFactory_TagRecord, []string) {
|
|
30
|
+
messages := []string{}
|
|
31
|
+
record := metadataCommentTagFactory_parse(struct {
|
|
32
|
+
Report func(msg string) any
|
|
33
|
+
Tag schemametadata.IJsDocTagInfo
|
|
34
|
+
}{
|
|
35
|
+
Report: func(msg string) any {
|
|
36
|
+
messages = append(messages, msg)
|
|
37
|
+
return nil
|
|
38
|
+
},
|
|
39
|
+
Tag: schemametadata.IJsDocTagInfo{
|
|
40
|
+
Name: name,
|
|
41
|
+
Text: []schemametadata.IJsDocTagInfo_IText{{Text: value, Kind: "text"}},
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
return record, messages
|
|
45
|
+
}
|
|
46
|
+
single := func(record metadataCommentTagFactory_TagRecord, target string) schemametadata.IMetadataTypeTag {
|
|
47
|
+
t.Helper()
|
|
48
|
+
tags := record[target]
|
|
49
|
+
if len(tags) != 1 {
|
|
50
|
+
t.Fatalf("expected one %s record, got %#v", target, record)
|
|
51
|
+
}
|
|
52
|
+
return tags[0]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//----
|
|
56
|
+
// 1. JavaScript spellings, spliced as values
|
|
57
|
+
//----
|
|
58
|
+
for _, item := range []struct {
|
|
59
|
+
name string
|
|
60
|
+
value string
|
|
61
|
+
target string
|
|
62
|
+
number float64
|
|
63
|
+
validate string
|
|
64
|
+
}{
|
|
65
|
+
{"minimum", "0x10", "number", 16, "16 <= $input"},
|
|
66
|
+
{"minimum", "0x10", "bigint", 16, "16 <= $input"},
|
|
67
|
+
{"maximum", "+5", "number", 5, "$input <= 5"},
|
|
68
|
+
{"exclusiveMinimum", ".5", "number", 0.5, "0.5 < $input"},
|
|
69
|
+
{"multipleOf", "1e3", "bigint", 1000, "$input % 1000n === 0n"},
|
|
70
|
+
{"multipleOf", "1.0", "bigint", 1, "$input % 1n === 0n"},
|
|
71
|
+
{"multipleOf", "1e3", "number", 1000, "$importInternal(\"_isMultipleOf\")($input, 1000)"},
|
|
72
|
+
{"minItems", "0b11", "array", 3, "3 <= $input.length"},
|
|
73
|
+
{"minLength", "0o7", "string", 7, "$importInternal(\"_stringLengthGte\")($input, 7)"},
|
|
74
|
+
{"multipleOf", "+5", "bigint", 5, "$input % 5n === 0n"},
|
|
75
|
+
{"multipleOf", "007", "bigint", 7, "$input % 7n === 0n"},
|
|
76
|
+
// Beyond 2^53 a bigint keeps an integer a double represents exactly; any
|
|
77
|
+
// other value gets an empty bigint record, which `Analyze` reports
|
|
78
|
+
// (samchon/typia#2457).
|
|
79
|
+
{"multipleOf", "18014398509481984", "bigint", 18014398509481984, "$input % 18014398509481984n === 0n"},
|
|
80
|
+
{"maximum", "0.0000001", "number", 1e-7, "$input <= 1e-7"},
|
|
81
|
+
} {
|
|
82
|
+
record, messages := parse(item.name, item.value)
|
|
83
|
+
if len(messages) != 0 {
|
|
84
|
+
t.Fatalf("@%s %s must be accepted, reports=%#v", item.name, item.value, messages)
|
|
85
|
+
}
|
|
86
|
+
tag := single(record, item.target)
|
|
87
|
+
if tag.Validate != item.validate {
|
|
88
|
+
t.Fatalf("@%s %s on %s should validate %q, got %q", item.name, item.value, item.target, item.validate, tag.Validate)
|
|
89
|
+
}
|
|
90
|
+
var value float64
|
|
91
|
+
switch v := tag.Value.(type) {
|
|
92
|
+
case float64:
|
|
93
|
+
value = v
|
|
94
|
+
case int64:
|
|
95
|
+
value = float64(v)
|
|
96
|
+
default:
|
|
97
|
+
t.Fatalf("@%s %s on %s carried a %T value", item.name, item.value, item.target, tag.Value)
|
|
98
|
+
}
|
|
99
|
+
if value != item.number {
|
|
100
|
+
t.Fatalf("@%s %s on %s should carry %v, got %v", item.name, item.value, item.target, item.number, value)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//----
|
|
105
|
+
// 2. Go-only spellings and infinities
|
|
106
|
+
//----
|
|
107
|
+
for _, item := range []struct {
|
|
108
|
+
name string
|
|
109
|
+
value string
|
|
110
|
+
message string
|
|
111
|
+
}{
|
|
112
|
+
{"minimum", "inf", "invalid number"},
|
|
113
|
+
{"minimum", "NaN", "invalid number"},
|
|
114
|
+
{"minimum", "0x1p4", "invalid number"},
|
|
115
|
+
{"maximum", "1_000", "invalid number"},
|
|
116
|
+
{"multipleOf", "-0x10", "invalid number"},
|
|
117
|
+
{"minimum", "Infinity", "non-finite number"},
|
|
118
|
+
{"exclusiveMaximum", "-Infinity", "non-finite number"},
|
|
119
|
+
{"maximum", "1e400", "non-finite number"},
|
|
120
|
+
} {
|
|
121
|
+
_, messages := parse(item.name, item.value)
|
|
122
|
+
found := false
|
|
123
|
+
for _, message := range messages {
|
|
124
|
+
if message == item.message {
|
|
125
|
+
found = true
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if found == false {
|
|
129
|
+
t.Fatalf("@%s %s should report %q, got %#v", item.name, item.value, item.message, messages)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//----
|
|
134
|
+
// 3. ordinary spellings are unchanged
|
|
135
|
+
//----
|
|
136
|
+
record, messages := parse("minimum", "3")
|
|
137
|
+
if len(messages) != 0 {
|
|
138
|
+
t.Fatalf("@minimum 3 must be accepted, reports=%#v", messages)
|
|
139
|
+
}
|
|
140
|
+
expected := schemametadata.IMetadataTypeTag{
|
|
141
|
+
Name: "Minimum<3>",
|
|
142
|
+
Target: "number",
|
|
143
|
+
Kind: "minimum",
|
|
144
|
+
Value: float64(3),
|
|
145
|
+
Validate: "3 <= $input",
|
|
146
|
+
Exclusive: metadataCommentTagFactory_exclusive("minimum"),
|
|
147
|
+
Schema: map[string]any{"minimum": float64(3)},
|
|
148
|
+
}
|
|
149
|
+
if actual := single(record, "number"); reflect.DeepEqual(actual, expected) == false {
|
|
150
|
+
t.Fatalf("@minimum 3 changed:\nexpected %#v\nactual %#v", expected, actual)
|
|
151
|
+
}
|
|
152
|
+
// Only the splice is respelled; the tag name keeps the source spelling, so
|
|
153
|
+
// validation messages and reflected metadata do not change.
|
|
154
|
+
record, _ = parse("minimum", "1.0")
|
|
155
|
+
if tag := single(record, "number"); tag.Name != "Minimum<1.0>" || tag.Validate != "1 <= $input" {
|
|
156
|
+
t.Fatalf("@minimum 1.0 should keep its name and splice 1, got %q / %q", tag.Name, tag.Validate)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -96,9 +96,7 @@ func (functionalAssertParametersProgrammerNamespace) Decompose(props FunctionalA
|
|
|
96
96
|
Equals: props.Config.Equals,
|
|
97
97
|
Guard: false,
|
|
98
98
|
},
|
|
99
|
-
Type: props.Context
|
|
100
|
-
functionalIsProgrammer_parameterType(p, nativefactories.TypeFactory.Keyword("any", props.Context.Emit)),
|
|
101
|
-
),
|
|
99
|
+
Type: functionalIsProgrammer_parameterCheckerType(props.Context, p),
|
|
102
100
|
Init: FunctionalAssertFunctionProgrammer.HookPath(struct {
|
|
103
101
|
Context nativecontext.ITypiaContext
|
|
104
102
|
Wrapper string
|
|
@@ -2,6 +2,7 @@ package functional
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
5
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
5
6
|
shimprinter "github.com/microsoft/typescript-go/shim/printer"
|
|
6
7
|
nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
|
|
7
8
|
nativefactories "github.com/samchon/typia/packages/typia/native/core/factories"
|
|
@@ -91,9 +92,7 @@ func (functionalIsParametersProgrammerNamespace) Decompose(props FunctionalIsPar
|
|
|
91
92
|
Context: props.Context,
|
|
92
93
|
Modulo: props.Modulo,
|
|
93
94
|
Config: nativeprogrammers.IsProgrammer_IConfig{Equals: props.Config.Equals},
|
|
94
|
-
Type:
|
|
95
|
-
functionalIsProgrammer_parameterType(p, nativefactories.TypeFactory.Keyword("any", props.Context.Emit)),
|
|
96
|
-
),
|
|
95
|
+
Type: functionalIsProgrammer_parameterCheckerType(props.Context, p),
|
|
97
96
|
}),
|
|
98
97
|
}, props.Context.Emit))
|
|
99
98
|
statements = append(statements, f.NewIfStatement(
|
|
@@ -157,7 +156,7 @@ func functionalIsProgrammer_function(
|
|
|
157
156
|
nil,
|
|
158
157
|
nil,
|
|
159
158
|
nil,
|
|
160
|
-
|
|
159
|
+
functionalIsProgrammer_wrapperParameters(declaration, context.Emit),
|
|
161
160
|
returnType,
|
|
162
161
|
nil,
|
|
163
162
|
body,
|
|
@@ -184,13 +183,84 @@ func functionalIsProgrammer_parameterIdentifiers(declaration *shimast.Node, emit
|
|
|
184
183
|
parameters := functionalIsProgrammer_parameterNodes(declaration)
|
|
185
184
|
output := make([]*shimast.Node, 0, len(parameters))
|
|
186
185
|
for _, p := range parameters {
|
|
187
|
-
|
|
186
|
+
identifier := f.NewIdentifier(functionalIsProgrammer_parameterName(p))
|
|
187
|
+
// a rest parameter received its arguments as an array; spread them back
|
|
188
|
+
if p.Kind == shimast.KindParameter && p.AsParameterDeclaration().DotDotDotToken != nil {
|
|
189
|
+
identifier = f.NewSpreadElement(identifier)
|
|
190
|
+
}
|
|
191
|
+
output = append(output, identifier)
|
|
188
192
|
}
|
|
189
193
|
return output
|
|
190
194
|
}
|
|
191
195
|
|
|
196
|
+
// functionalIsProgrammer_wrapperParameters is the declaration's parameter list
|
|
197
|
+
// for the wrapper, a destructuring pattern renamed to the identifier
|
|
198
|
+
// functionalIsProgrammer_parameterName gives it: the wrapper validates and
|
|
199
|
+
// forwards the whole argument, and a pattern names no single value.
|
|
200
|
+
func functionalIsProgrammer_wrapperParameters(declaration *shimast.Node, emit ...*shimprinter.EmitContext) *shimast.ParameterList {
|
|
201
|
+
f := nativecontext.EmitFactoryOf(functionalIsProgrammer_factory, emit...)
|
|
202
|
+
list := functionalIsProgrammer_parameters(declaration, emit...)
|
|
203
|
+
if list == nil {
|
|
204
|
+
return list
|
|
205
|
+
}
|
|
206
|
+
if functionalIsProgrammer_hasBindingPattern(declaration) == false {
|
|
207
|
+
return list
|
|
208
|
+
}
|
|
209
|
+
// A default may read a name an earlier pattern binds (`({ a }, b = a)`),
|
|
210
|
+
// which the renamed wrapper no longer binds. So no default is copied: the
|
|
211
|
+
// wrapper forwards what it received, the function applies its own
|
|
212
|
+
// defaults, and a defaulted argument may be `undefined`; see
|
|
213
|
+
// functionalIsProgrammer_parameterCheckerType.
|
|
214
|
+
output := make([]*shimast.Node, 0, len(list.Nodes))
|
|
215
|
+
for _, param := range list.Nodes {
|
|
216
|
+
if param.Kind == shimast.KindParameter && param.Name() != nil && functionalIsProgrammer_parameterName(param) != "this" {
|
|
217
|
+
data := param.AsParameterDeclaration()
|
|
218
|
+
param = f.NewParameterDeclaration(
|
|
219
|
+
nil,
|
|
220
|
+
data.DotDotDotToken,
|
|
221
|
+
f.NewIdentifier(functionalIsProgrammer_parameterName(param)),
|
|
222
|
+
data.QuestionToken,
|
|
223
|
+
data.Type,
|
|
224
|
+
nil,
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
output = append(output, param)
|
|
228
|
+
}
|
|
229
|
+
return f.NewNodeList(output)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// functionalIsProgrammer_hasBindingPattern reports whether any parameter of
|
|
233
|
+
// declaration destructures its argument.
|
|
234
|
+
func functionalIsProgrammer_hasBindingPattern(declaration *shimast.Node) bool {
|
|
235
|
+
if list := functionalIsProgrammer_parameters(declaration); list != nil {
|
|
236
|
+
for _, param := range list.Nodes {
|
|
237
|
+
if param.Name() != nil && functionalIsProgrammer_isBindingPattern(param.Name()) {
|
|
238
|
+
return true
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return false
|
|
243
|
+
}
|
|
244
|
+
|
|
192
245
|
func functionalIsProgrammer_parameterName(param *shimast.Node) string {
|
|
193
246
|
if param != nil && param.Name() != nil {
|
|
247
|
+
// A destructuring pattern has no name; the wrapper gives it one by its
|
|
248
|
+
// position (samchon/typia#2461), apart from every other parameter's name,
|
|
249
|
+
// or the wrapper would declare it twice.
|
|
250
|
+
if functionalIsProgrammer_isBindingPattern(param.Name()) {
|
|
251
|
+
index := 0
|
|
252
|
+
names := []string{}
|
|
253
|
+
if parent := param.Parent; parent != nil && parent.FunctionLikeData() != nil && parent.FunctionLikeData().Parameters != nil {
|
|
254
|
+
for i, sibling := range parent.FunctionLikeData().Parameters.Nodes {
|
|
255
|
+
if sibling == param {
|
|
256
|
+
index = i
|
|
257
|
+
} else if sibling.Name() != nil && functionalIsProgrammer_isBindingPattern(sibling.Name()) == false {
|
|
258
|
+
names = append(names, sibling.Name().Text())
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return functionalIsProgrammer_escapeDuplicate(names, "__param"+functionalIsProgrammer_itoa(index))
|
|
263
|
+
}
|
|
194
264
|
text := param.Name().Text()
|
|
195
265
|
if text != "" {
|
|
196
266
|
return text
|
|
@@ -200,13 +270,34 @@ func functionalIsProgrammer_parameterName(param *shimast.Node) string {
|
|
|
200
270
|
return "input"
|
|
201
271
|
}
|
|
202
272
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
273
|
+
// functionalIsProgrammer_parameterCheckerType is the type an argument must
|
|
274
|
+
// satisfy: the parameter symbol's type, which adds `undefined` to an optional
|
|
275
|
+
// parameter and reads a type inferred from a default. The written annotation
|
|
276
|
+
// alone made `y?: string` require a `string` (samchon/typia#2461).
|
|
277
|
+
func functionalIsProgrammer_parameterCheckerType(context nativecontext.ITypiaContext, param *shimast.Node) *shimchecker.Type {
|
|
278
|
+
typ := functionalIsProgrammer_declaredType(context, param)
|
|
279
|
+
// A wrapper beside a destructured parameter copies no default, so a
|
|
280
|
+
// defaulted argument arrives as sent, `undefined` included.
|
|
281
|
+
if param.Kind == shimast.KindParameter &&
|
|
282
|
+
param.AsParameterDeclaration().Initializer != nil &&
|
|
283
|
+
functionalIsProgrammer_hasBindingPattern(param.Parent) {
|
|
284
|
+
return context.Checker.GetUnionType([]*shimchecker.Type{typ, context.Checker.GetUndefinedType()})
|
|
285
|
+
}
|
|
286
|
+
return typ
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
func functionalIsProgrammer_declaredType(context nativecontext.ITypiaContext, param *shimast.Node) *shimchecker.Type {
|
|
290
|
+
if symbol := param.Symbol(); symbol != nil {
|
|
291
|
+
if typ := context.Checker.GetTypeOfSymbol(symbol); typ != nil {
|
|
206
292
|
return typ
|
|
207
293
|
}
|
|
208
294
|
}
|
|
209
|
-
|
|
295
|
+
if param.Kind == shimast.KindParameter {
|
|
296
|
+
if typ := param.AsParameterDeclaration().Type; typ != nil {
|
|
297
|
+
return context.Checker.GetTypeFromTypeNode(typ)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return context.Checker.GetAnyType()
|
|
210
301
|
}
|
|
211
302
|
|
|
212
303
|
func functionalIsProgrammer_asyncModifiers(async bool, emit ...*shimprinter.EmitContext) *shimast.ModifierList {
|
|
@@ -255,3 +346,10 @@ func functionalIsProgrammer_itoa(value int) string {
|
|
|
255
346
|
}
|
|
256
347
|
return string(digits)
|
|
257
348
|
}
|
|
349
|
+
|
|
350
|
+
// functionalIsProgrammer_isBindingPattern reports whether name destructures
|
|
351
|
+
// an object or an array. It compares the kind itself because the shim of the
|
|
352
|
+
// oldest supported ttsc exports no IsBindingPattern.
|
|
353
|
+
func functionalIsProgrammer_isBindingPattern(name *shimast.Node) bool {
|
|
354
|
+
return name.Kind == shimast.KindObjectBindingPattern || name.Kind == shimast.KindArrayBindingPattern
|
|
355
|
+
}
|
|
@@ -97,9 +97,7 @@ func (functionalValidateParametersProgrammerNamespace) Decompose(props Functiona
|
|
|
97
97
|
Context: props.Context,
|
|
98
98
|
Modulo: props.Modulo,
|
|
99
99
|
Config: nativeprogrammers.ValidateProgrammer_IConfig{Equals: props.Config.Equals},
|
|
100
|
-
Type:
|
|
101
|
-
functionalIsProgrammer_parameterType(p, nativefactories.TypeFactory.Keyword("any", props.Context.Emit)),
|
|
102
|
-
),
|
|
100
|
+
Type: functionalIsProgrammer_parameterCheckerType(props.Context, p),
|
|
103
101
|
}),
|
|
104
102
|
}, props.Context.Emit))
|
|
105
103
|
results = append(results, f.NewAsExpression(
|
|
@@ -5,6 +5,7 @@ import (
|
|
|
5
5
|
|
|
6
6
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
7
7
|
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
8
|
+
shimprinter "github.com/microsoft/typescript-go/shim/printer"
|
|
8
9
|
nativecontext "github.com/samchon/typia/packages/typia/native/core/context"
|
|
9
10
|
nativefactories "github.com/samchon/typia/packages/typia/native/core/factories"
|
|
10
11
|
nativehelpers "github.com/samchon/typia/packages/typia/native/core/programmers/helpers"
|
|
@@ -240,11 +241,13 @@ func httpFormDataProgrammer_decode_regular_property(props struct {
|
|
|
240
241
|
httpFormDataProgrammer_decode_value(struct {
|
|
241
242
|
Context nativecontext.ITypiaContext
|
|
242
243
|
Type string
|
|
244
|
+
Nullable bool
|
|
243
245
|
Coalesce bool
|
|
244
246
|
Input *shimast.Node
|
|
245
247
|
}{
|
|
246
248
|
Context: props.Context,
|
|
247
249
|
Type: typ,
|
|
250
|
+
Nullable: httpProgrammer_decode_nullable(value),
|
|
248
251
|
Coalesce: false,
|
|
249
252
|
Input: f.NewIdentifier("elem"),
|
|
250
253
|
}),
|
|
@@ -265,12 +268,14 @@ func httpFormDataProgrammer_decode_regular_property(props struct {
|
|
|
265
268
|
input = httpFormDataProgrammer_decode_value(struct {
|
|
266
269
|
Context nativecontext.ITypiaContext
|
|
267
270
|
Type string
|
|
271
|
+
Nullable bool
|
|
268
272
|
Coalesce bool
|
|
269
273
|
Input *shimast.Node
|
|
270
274
|
}{
|
|
271
275
|
Context: props.Context,
|
|
272
276
|
Type: typ,
|
|
273
|
-
|
|
277
|
+
Nullable: httpProgrammer_decode_nullable(value),
|
|
278
|
+
Coalesce: value.Nullable == false && value.Any == false && value.IsRequired() == false,
|
|
274
279
|
Input: input,
|
|
275
280
|
})
|
|
276
281
|
}
|
|
@@ -286,6 +291,7 @@ func httpFormDataProgrammer_decode_regular_property(props struct {
|
|
|
286
291
|
func httpFormDataProgrammer_decode_value(props struct {
|
|
287
292
|
Context nativecontext.ITypiaContext
|
|
288
293
|
Type string
|
|
294
|
+
Nullable bool
|
|
289
295
|
Coalesce bool
|
|
290
296
|
Input *shimast.Node
|
|
291
297
|
}) *shimast.Node {
|
|
@@ -294,7 +300,7 @@ func httpFormDataProgrammer_decode_value(props struct {
|
|
|
294
300
|
httpParameterProgrammer_internal(props.Context, "httpFormDataRead"+httpParameterProgrammer_capitalize(props.Type)),
|
|
295
301
|
nil,
|
|
296
302
|
nil,
|
|
297
|
-
f.NewNodeList(
|
|
303
|
+
f.NewNodeList(httpProgrammer_read_arguments(props.Type, props.Nullable, props.Input, props.Context.Emit)),
|
|
298
304
|
shimast.NodeFlagsNone,
|
|
299
305
|
)
|
|
300
306
|
if props.Coalesce == false {
|
|
@@ -373,6 +379,39 @@ func httpProgrammer_property_key(property *schemametadata.MetadataProperty) stri
|
|
|
373
379
|
return ""
|
|
374
380
|
}
|
|
375
381
|
|
|
382
|
+
// httpProgrammer_decode_nullable tells whether one decoded unit admits `null`:
|
|
383
|
+
// the element for an array property, the property itself otherwise. `any` and
|
|
384
|
+
// `unknown` admit it as well, and decode through the string reader.
|
|
385
|
+
func httpProgrammer_decode_nullable(value *schemametadata.MetadataSchema) bool {
|
|
386
|
+
admits := func(unit *schemametadata.MetadataSchema) bool {
|
|
387
|
+
return unit != nil && (unit.Nullable || unit.Any)
|
|
388
|
+
}
|
|
389
|
+
if value == nil {
|
|
390
|
+
return false
|
|
391
|
+
}
|
|
392
|
+
if len(value.Arrays) != 0 {
|
|
393
|
+
return admits(value.Arrays[0].Type.Value)
|
|
394
|
+
}
|
|
395
|
+
if len(value.Tuples) != 0 && len(value.Tuples[0].Type.Elements) != 0 {
|
|
396
|
+
return admits(value.Tuples[0].Type.Elements[0])
|
|
397
|
+
}
|
|
398
|
+
return admits(value)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// httpProgrammer_read_arguments lists the arguments of one `_http*Read*` call.
|
|
402
|
+
//
|
|
403
|
+
// A string reader turns the text `"null"` into `null` unless told the type does
|
|
404
|
+
// not admit it (samchon/typia#2450), so a non-nullable string passes `false`.
|
|
405
|
+
// Every other call keeps the single argument, and so does a nullable string,
|
|
406
|
+
// whose emit stays byte-identical to what earlier versions produced.
|
|
407
|
+
func httpProgrammer_read_arguments(typ string, nullable bool, input *shimast.Node, emit ...*shimprinter.EmitContext) []*shimast.Node {
|
|
408
|
+
if typ != "string" || nullable {
|
|
409
|
+
return []*shimast.Node{input}
|
|
410
|
+
}
|
|
411
|
+
f := nativecontext.EmitFactoryOf(httpFormDataProgrammer_factory, emit...)
|
|
412
|
+
return []*shimast.Node{input, f.NewKeywordExpression(shimast.KindFalseKeyword)}
|
|
413
|
+
}
|
|
414
|
+
|
|
376
415
|
func httpProgrammer_decode_type(value *schemametadata.MetadataSchema, blob bool) (string, bool) {
|
|
377
416
|
return httpProgrammer_decode_type_from_metadata(value, blob, false)
|
|
378
417
|
}
|
|
@@ -243,7 +243,13 @@ func httpHeadersProgrammer_decode_object(props struct {
|
|
|
243
243
|
nativefactories.ExpressionFactory.Number(0, props.Context.Emit),
|
|
244
244
|
nil,
|
|
245
245
|
f.NewToken(shimast.KindEqualsEqualsEqualsToken),
|
|
246
|
-
|
|
246
|
+
f.NewBinaryExpression(
|
|
247
|
+
nil,
|
|
248
|
+
nativefactories.IdentifierFactory.Access(props.Context.Emit, access, "length", true),
|
|
249
|
+
nil,
|
|
250
|
+
f.NewToken(shimast.KindQuestionQuestionToken),
|
|
251
|
+
nativefactories.ExpressionFactory.Number(0, props.Context.Emit),
|
|
252
|
+
),
|
|
247
253
|
),
|
|
248
254
|
f.NewExpressionStatement(
|
|
249
255
|
f.NewDeleteExpression(access),
|
|
@@ -272,8 +278,10 @@ func httpHeadersProgrammer_decode_regular_property(props struct {
|
|
|
272
278
|
)
|
|
273
279
|
var decoded *shimast.Node
|
|
274
280
|
if isArray {
|
|
275
|
-
|
|
276
|
-
|
|
281
|
+
// The input is read by the key's lowercase name, so a declared
|
|
282
|
+
// `"Set-Cookie": string[]` is the same header.
|
|
283
|
+
if strings.ToLower(key) == "set-cookie" {
|
|
284
|
+
decoded = httpHeadersProgrammer_decode_set_cookie(props.Context, typ, input, value.IsRequired())
|
|
277
285
|
} else {
|
|
278
286
|
decoded = httpHeadersProgrammer_decode_array(struct {
|
|
279
287
|
Context nativecontext.ITypiaContext
|
|
@@ -309,6 +317,50 @@ func httpHeadersProgrammer_decode_regular_property(props struct {
|
|
|
309
317
|
)
|
|
310
318
|
}
|
|
311
319
|
|
|
320
|
+
// httpHeadersProgrammer_decode_set_cookie decodes `set-cookie` without the
|
|
321
|
+
// list decoder: cookie attributes such as `Expires` contain `", "`, so a value
|
|
322
|
+
// is never split or trimmed. It still yields an array like every other array
|
|
323
|
+
// header does: a lone string is one cookie, an absent required header is `[]`
|
|
324
|
+
// (samchon/typia#2447), and a non-string element type is read by the same
|
|
325
|
+
// reader other array headers use.
|
|
326
|
+
func httpHeadersProgrammer_decode_set_cookie(context nativecontext.ITypiaContext, typ string, input *shimast.Node, required bool) *shimast.Node {
|
|
327
|
+
f := nativecontext.EmitFactoryOf(httpHeadersProgrammer_factory, context.Emit)
|
|
328
|
+
array := input
|
|
329
|
+
single := input
|
|
330
|
+
if typ != "string" {
|
|
331
|
+
reader := httpParameterProgrammer_internal(context, "httpHeaderRead"+httpParameterProgrammer_capitalize(typ))
|
|
332
|
+
array = f.NewCallExpression(
|
|
333
|
+
nativefactories.IdentifierFactory.Access(context.Emit, input, "map"),
|
|
334
|
+
nil,
|
|
335
|
+
nil,
|
|
336
|
+
f.NewNodeList([]*shimast.Node{reader}),
|
|
337
|
+
shimast.NodeFlagsNone,
|
|
338
|
+
)
|
|
339
|
+
single = f.NewCallExpression(reader, nil, nil, f.NewNodeList([]*shimast.Node{input}), shimast.NodeFlagsNone)
|
|
340
|
+
}
|
|
341
|
+
absent := f.NewIdentifier("undefined")
|
|
342
|
+
if required {
|
|
343
|
+
absent = f.NewArrayLiteralExpression(f.NewNodeList(nil), false)
|
|
344
|
+
}
|
|
345
|
+
return nativefactories.ExpressionFactory.Conditional(
|
|
346
|
+
nativefactories.ExpressionFactory.IsArray(input, context.Emit),
|
|
347
|
+
array,
|
|
348
|
+
nativefactories.ExpressionFactory.Conditional(
|
|
349
|
+
f.NewBinaryExpression(
|
|
350
|
+
nil,
|
|
351
|
+
f.NewIdentifier("undefined"),
|
|
352
|
+
nil,
|
|
353
|
+
f.NewToken(shimast.KindExclamationEqualsEqualsToken),
|
|
354
|
+
input,
|
|
355
|
+
),
|
|
356
|
+
f.NewArrayLiteralExpression(f.NewNodeList([]*shimast.Node{single}), false),
|
|
357
|
+
absent,
|
|
358
|
+
context.Emit,
|
|
359
|
+
),
|
|
360
|
+
context.Emit,
|
|
361
|
+
)
|
|
362
|
+
}
|
|
363
|
+
|
|
312
364
|
func httpHeadersProgrammer_decode_value(props struct {
|
|
313
365
|
Context nativecontext.ITypiaContext
|
|
314
366
|
Type string
|
|
@@ -362,7 +414,7 @@ func httpHeadersProgrammer_decode_array(props struct {
|
|
|
362
414
|
reader = httpParameterProgrammer_internal(props.Context, "httpHeaderRead"+httpParameterProgrammer_capitalize(props.Type))
|
|
363
415
|
}
|
|
364
416
|
delimiter := ", "
|
|
365
|
-
if props.Key == "cookie" {
|
|
417
|
+
if strings.ToLower(props.Key) == "cookie" {
|
|
366
418
|
delimiter = "; "
|
|
367
419
|
}
|
|
368
420
|
split := f.NewCallExpression(
|
|
@@ -68,9 +68,7 @@ func (httpParameterProgrammerNamespace) Write(props nativecontext.IProgrammerPro
|
|
|
68
68
|
httpParameterProgrammer_internal(props.Context, "httpParameterRead"+httpParameterProgrammer_capitalize(atomic)),
|
|
69
69
|
nil,
|
|
70
70
|
nil,
|
|
71
|
-
f.NewNodeList(
|
|
72
|
-
f.NewIdentifier("input"),
|
|
73
|
-
}),
|
|
71
|
+
f.NewNodeList(httpProgrammer_read_arguments(atomic, result.Data.Nullable, f.NewIdentifier("input"), props.Context.Emit)),
|
|
74
72
|
shimast.NodeFlagsNone,
|
|
75
73
|
),
|
|
76
74
|
}, props.Context.Emit),
|