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,147 @@
|
|
|
1
|
+
package utils
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"math"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestNumberUtilReadsJavaScriptNumberGrammar verifies NumberUtil.Read against
|
|
9
|
+
// JavaScript's `Number()`.
|
|
10
|
+
//
|
|
11
|
+
// Tag values and JSDoc extensions are TypeScript source, so the grammar that
|
|
12
|
+
// reads them is JavaScript's StringNumericLiteral. The expectations below are
|
|
13
|
+
// what `Number(text)` returns in JavaScript (samchon/typia#2442), not what the
|
|
14
|
+
// Go float parser accepts; the Go-only spellings (`NaN`, `Inf`, `0x1p4`,
|
|
15
|
+
// `1_000`) are the cases that used to leak through. Text without digits is the
|
|
16
|
+
// one deliberate difference: `Number("")` is 0, but it names no number here.
|
|
17
|
+
//
|
|
18
|
+
// 1. Read decimal, signed, exponent, and point-edge spellings.
|
|
19
|
+
// 2. Read hexadecimal, octal, and binary integers, and reject signed ones.
|
|
20
|
+
// 3. Classify `Infinity`, overflow, and underflow by finiteness.
|
|
21
|
+
// 4. Reject Go-only spellings, separators, and empty or blank text.
|
|
22
|
+
// 5. Spell values back exactly as JavaScript's `String()` does.
|
|
23
|
+
// 6. Read integer spellings exactly, beyond double precision.
|
|
24
|
+
func TestNumberUtilReadsJavaScriptNumberGrammar(t *testing.T) {
|
|
25
|
+
finite := func(value float64) NumberUtil_Reading {
|
|
26
|
+
return NumberUtil_Reading{Value: value, Numeric: true, Finite: true}
|
|
27
|
+
}
|
|
28
|
+
infinite := func(sign int) NumberUtil_Reading {
|
|
29
|
+
return NumberUtil_Reading{Value: math.Inf(sign), Numeric: true, Finite: false}
|
|
30
|
+
}
|
|
31
|
+
invalid := NumberUtil_Reading{}
|
|
32
|
+
for _, item := range []struct {
|
|
33
|
+
text string
|
|
34
|
+
expected NumberUtil_Reading
|
|
35
|
+
}{
|
|
36
|
+
// Decimal notation, including every point and sign edge `Number()` admits.
|
|
37
|
+
{"0", finite(0)},
|
|
38
|
+
{"3", finite(3)},
|
|
39
|
+
{"-2.5", finite(-2.5)},
|
|
40
|
+
{"+5", finite(5)},
|
|
41
|
+
{".5", finite(0.5)},
|
|
42
|
+
{"5.", finite(5)},
|
|
43
|
+
{"1e3", finite(1000)},
|
|
44
|
+
{"1E-3", finite(0.001)},
|
|
45
|
+
{"-0", finite(0)},
|
|
46
|
+
{" 12\t", finite(12)},
|
|
47
|
+
{"\u00a012\u2028", finite(12)},
|
|
48
|
+
{"007", finite(7)},
|
|
49
|
+
// Non-decimal integers: unsigned only, any letter case in the prefix.
|
|
50
|
+
{"0x10", finite(16)},
|
|
51
|
+
{"0XfF", finite(255)},
|
|
52
|
+
{"0o7", finite(7)},
|
|
53
|
+
{"0b101", finite(5)},
|
|
54
|
+
{"-0x10", invalid},
|
|
55
|
+
{"+0x10", invalid},
|
|
56
|
+
{"0o8", invalid},
|
|
57
|
+
{"0b2", invalid},
|
|
58
|
+
{"0x", invalid},
|
|
59
|
+
// Non-finite values are numeric but not finite.
|
|
60
|
+
{"Infinity", infinite(1)},
|
|
61
|
+
{"+Infinity", infinite(1)},
|
|
62
|
+
{"-Infinity", infinite(-1)},
|
|
63
|
+
{"1e400", infinite(1)},
|
|
64
|
+
{"-1e400", infinite(-1)},
|
|
65
|
+
{"1e-400", finite(0)},
|
|
66
|
+
// Go-only spellings and separators: NaN in JavaScript.
|
|
67
|
+
{"NaN", invalid},
|
|
68
|
+
{"nan", invalid},
|
|
69
|
+
{"Inf", invalid},
|
|
70
|
+
{"inf", invalid},
|
|
71
|
+
{"-inf", invalid},
|
|
72
|
+
{"infinity", invalid},
|
|
73
|
+
{"0x1p4", invalid},
|
|
74
|
+
{"1_000", invalid},
|
|
75
|
+
{"1e", invalid},
|
|
76
|
+
{".", invalid},
|
|
77
|
+
{"1.2.3", invalid},
|
|
78
|
+
{"12px", invalid},
|
|
79
|
+
// No digits at all.
|
|
80
|
+
{"", invalid},
|
|
81
|
+
{" ", invalid},
|
|
82
|
+
{"+", invalid},
|
|
83
|
+
} {
|
|
84
|
+
actual := NumberUtil.Read(item.text)
|
|
85
|
+
if actual != item.expected || math.Signbit(actual.Value) != math.Signbit(item.expected.Value) {
|
|
86
|
+
t.Fatalf("Read(%q) = %+v, expected %+v", item.text, actual, item.expected)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// String: the oracle is JavaScript's `String(value)`.
|
|
91
|
+
for _, item := range []struct {
|
|
92
|
+
value float64
|
|
93
|
+
expected string
|
|
94
|
+
}{
|
|
95
|
+
{0, "0"},
|
|
96
|
+
{math.Copysign(0, -1), "0"},
|
|
97
|
+
{16, "16"},
|
|
98
|
+
{-2.5, "-2.5"},
|
|
99
|
+
{0.001, "0.001"},
|
|
100
|
+
{0.000001, "0.000001"},
|
|
101
|
+
{1e6, "1000000"},
|
|
102
|
+
{123456789012345680000, "123456789012345680000"},
|
|
103
|
+
{1e21, "1e+21"},
|
|
104
|
+
{1e-7, "1e-7"},
|
|
105
|
+
{-1e-7, "-1e-7"},
|
|
106
|
+
{1.23e-18, "1.23e-18"},
|
|
107
|
+
{1.5e300, "1.5e+300"},
|
|
108
|
+
{9007199254740993, "9007199254740992"},
|
|
109
|
+
{math.NaN(), "NaN"},
|
|
110
|
+
{math.Inf(1), "Infinity"},
|
|
111
|
+
{math.Inf(-1), "-Infinity"},
|
|
112
|
+
} {
|
|
113
|
+
if actual := NumberUtil.String(item.value); actual != item.expected {
|
|
114
|
+
t.Fatalf("String(%v) = %q, expected %q", item.value, actual, item.expected)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Integer: exact digits for integer spellings, nothing for the rest.
|
|
119
|
+
for _, item := range []struct {
|
|
120
|
+
text string
|
|
121
|
+
expected string
|
|
122
|
+
ok bool
|
|
123
|
+
}{
|
|
124
|
+
{"9007199254740993", "9007199254740993", true},
|
|
125
|
+
{"-12", "-12", true},
|
|
126
|
+
{"+5", "5", true},
|
|
127
|
+
{"007", "7", true},
|
|
128
|
+
{"-0", "0", true},
|
|
129
|
+
{" 42 ", "42", true},
|
|
130
|
+
{"0x10", "16", true},
|
|
131
|
+
{"0b101", "5", true},
|
|
132
|
+
{"0o17", "15", true},
|
|
133
|
+
{"0xffffffffffffffffff", "4722366482869645213695", true},
|
|
134
|
+
{"1e3", "", false},
|
|
135
|
+
{"1.0", "", false},
|
|
136
|
+
{"-0x10", "", false},
|
|
137
|
+
{"0o8", "", false},
|
|
138
|
+
{"", "", false},
|
|
139
|
+
{"Infinity", "", false},
|
|
140
|
+
} {
|
|
141
|
+
integer, ok := NumberUtil.Integer(item.text)
|
|
142
|
+
if ok != item.ok || (ok && integer.String() != item.expected) {
|
|
143
|
+
t.Fatalf("Integer(%q) = %v, %v; expected %q, %v", item.text, integer, ok, item.expected, item.ok)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typia",
|
|
3
|
-
"version": "15.0.
|
|
3
|
+
"version": "15.0.1",
|
|
4
4
|
"description": "Superfast runtime validators with only one line",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"homepage": "https://typia.io",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"randexp": "^0.5.3",
|
|
46
|
-
"@typia/
|
|
47
|
-
"@typia/
|
|
46
|
+
"@typia/interface": "^15.0.1",
|
|
47
|
+
"@typia/utils": "^15.0.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"ttsc": ">=0.19.2"
|
package/src/http.ts
CHANGED
|
@@ -22,7 +22,10 @@ import { NoTransformConfigurationError } from "./transformers/NoTransformConfigu
|
|
|
22
22
|
* Decodes `FormData` into type `T`.
|
|
23
23
|
*
|
|
24
24
|
* Parses a `FormData` instance with automatic type casting. Properties typed as
|
|
25
|
-
* `boolean` or `
|
|
25
|
+
* `boolean`, `bigint`, or `number` are cast from their text, and `Blob` and
|
|
26
|
+
* `File` properties are read as given, except that the text `null` reads as
|
|
27
|
+
* `null`: as `undefined` instead for an optional single property whose type
|
|
28
|
+
* does not admit `null`, and always as `null` for an array element.
|
|
26
29
|
*
|
|
27
30
|
* Type `T` constraints:
|
|
28
31
|
*
|
|
@@ -32,6 +35,11 @@ import { NoTransformConfigurationError } from "./transformers/NoTransformConfigu
|
|
|
32
35
|
* types allowed
|
|
33
36
|
* 4. No union types allowed
|
|
34
37
|
*
|
|
38
|
+
* An absent key decodes a required array to `[]`, a nullable one to `null`, and
|
|
39
|
+
* an optional one to `undefined`. A string property keeps the text `null`
|
|
40
|
+
* unless its type admits `null`, and a blank numeric value decodes to
|
|
41
|
+
* `undefined`.
|
|
42
|
+
*
|
|
35
43
|
* Does not validate the decoded value. For validation, use:
|
|
36
44
|
*
|
|
37
45
|
* - {@link assertFormData} — Throws on type mismatch
|
|
@@ -164,8 +172,8 @@ export function validateFormData(): never {
|
|
|
164
172
|
* Decodes URL query string into type `T`.
|
|
165
173
|
*
|
|
166
174
|
* Parses a query string or `URLSearchParams` instance with automatic type
|
|
167
|
-
* casting. Properties typed as `boolean` or `number` are cast to
|
|
168
|
-
* during decoding.
|
|
175
|
+
* casting. Properties typed as `boolean`, `bigint`, or `number` are cast to
|
|
176
|
+
* expected types during decoding.
|
|
169
177
|
*
|
|
170
178
|
* Type `T` constraints:
|
|
171
179
|
*
|
|
@@ -174,6 +182,12 @@ export function validateFormData(): never {
|
|
|
174
182
|
* 3. Only `boolean`, `bigint`, `number`, `string` or their array types allowed
|
|
175
183
|
* 4. No union types allowed
|
|
176
184
|
*
|
|
185
|
+
* An absent key decodes a required array to `[]`, a nullable one to `null`, and
|
|
186
|
+
* an optional one to `undefined`, since a query string has no other spelling
|
|
187
|
+
* for an empty array. An absent required non-array property throws
|
|
188
|
+
* `Error("missing <key>")`. A string property keeps the text `null` unless its
|
|
189
|
+
* type admits `null`, and a blank numeric value decodes to `undefined`.
|
|
190
|
+
*
|
|
177
191
|
* Does not validate the decoded value. For validation, use:
|
|
178
192
|
*
|
|
179
193
|
* - {@link assertQuery} — Throws on type mismatch
|
|
@@ -308,14 +322,15 @@ export function validateQuery(): never {
|
|
|
308
322
|
* Decodes HTTP headers into type `T`.
|
|
309
323
|
*
|
|
310
324
|
* Parses HTTP headers object with automatic type casting. Properties typed as
|
|
311
|
-
* `boolean` or `number` are cast to expected types during decoding.
|
|
312
|
-
* with Express and Fastify request headers.
|
|
325
|
+
* `boolean`, `bigint`, or `number` are cast to expected types during decoding.
|
|
326
|
+
* Compatible with Express and Fastify request headers.
|
|
313
327
|
*
|
|
314
328
|
* Type `T` constraints:
|
|
315
329
|
*
|
|
316
330
|
* 1. Must be an object type
|
|
317
331
|
* 2. No dynamic properties allowed
|
|
318
|
-
* 3. Property keys
|
|
332
|
+
* 3. Property keys are read by their lowercase name; two keys that differ only by
|
|
333
|
+
* case are not allowed
|
|
319
334
|
* 4. Property values cannot be `null` (but `undefined` is allowed)
|
|
320
335
|
* 5. Only `boolean`, `bigint`, `number`, `string` or their array types allowed
|
|
321
336
|
* 6. No union types allowed
|
|
@@ -326,6 +341,10 @@ export function validateQuery(): never {
|
|
|
326
341
|
* `max-forwards`, `proxy-authorization`, `referer`, `retry-after`, `server`,
|
|
327
342
|
* `user-agent`
|
|
328
343
|
*
|
|
344
|
+
* An absent optional array header, or one given as an empty array, is omitted,
|
|
345
|
+
* and an absent required one decodes to `[]`. `set-cookie` values are never
|
|
346
|
+
* split. A blank numeric header decodes to `undefined`.
|
|
347
|
+
*
|
|
329
348
|
* Does not validate the decoded value. For validation, use:
|
|
330
349
|
*
|
|
331
350
|
* - {@link assertHeaders} — Throws on type mismatch
|
|
@@ -357,7 +376,8 @@ export function headers(): never {
|
|
|
357
376
|
*
|
|
358
377
|
* 1. Must be an object type
|
|
359
378
|
* 2. No dynamic properties allowed
|
|
360
|
-
* 3. Property keys
|
|
379
|
+
* 3. Property keys are read by their lowercase name; two keys that differ only by
|
|
380
|
+
* case are not allowed
|
|
361
381
|
* 4. Property values cannot be `null` (but `undefined` is allowed)
|
|
362
382
|
* 5. Only `boolean`, `bigint`, `number`, `string` or their array types allowed
|
|
363
383
|
* 6. No union types allowed
|
|
@@ -403,7 +423,8 @@ export function assertHeaders(): never {
|
|
|
403
423
|
*
|
|
404
424
|
* 1. Must be an object type
|
|
405
425
|
* 2. No dynamic properties allowed
|
|
406
|
-
* 3. Property keys
|
|
426
|
+
* 3. Property keys are read by their lowercase name; two keys that differ only by
|
|
427
|
+
* case are not allowed
|
|
407
428
|
* 4. Property values cannot be `null` (but `undefined` is allowed)
|
|
408
429
|
* 5. Only `boolean`, `bigint`, `number`, `string` or their array types allowed
|
|
409
430
|
* 6. No union types allowed
|
|
@@ -446,7 +467,8 @@ export function isHeaders(): never {
|
|
|
446
467
|
*
|
|
447
468
|
* 1. Must be an object type
|
|
448
469
|
* 2. No dynamic properties allowed
|
|
449
|
-
* 3. Property keys
|
|
470
|
+
* 3. Property keys are read by their lowercase name; two keys that differ only by
|
|
471
|
+
* case are not allowed
|
|
450
472
|
* 4. Property values cannot be `null` (but `undefined` is allowed)
|
|
451
473
|
* 5. Only `boolean`, `bigint`, `number`, `string` or their array types allowed
|
|
452
474
|
* 6. No union types allowed
|
|
@@ -484,12 +506,15 @@ export function validateHeaders(): never {
|
|
|
484
506
|
* Decodes URL path parameter into type `T`.
|
|
485
507
|
*
|
|
486
508
|
* Parses a path parameter string with automatic type casting. When type `T` is
|
|
487
|
-
* `boolean` or `number`, casts the string value to the expected
|
|
488
|
-
* performs type assertion via {@link assert}, throwing
|
|
489
|
-
* mismatch.
|
|
509
|
+
* `boolean`, `bigint`, or `number`, casts the string value to the expected
|
|
510
|
+
* type. Also performs type assertion via {@link assert}, throwing
|
|
511
|
+
* {@link TypeGuardError} on mismatch.
|
|
490
512
|
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
513
|
+
* A blank value is not a number, and a string parameter keeps the text `null`
|
|
514
|
+
* unless `T` admits `null`.
|
|
515
|
+
*
|
|
516
|
+
* @template T Target atomic type (`boolean`, `bigint`, `number`, or `string`),
|
|
517
|
+
* optionally with `null`
|
|
493
518
|
* @param input Path parameter string
|
|
494
519
|
* @returns Decoded value of type `T`
|
|
495
520
|
* @throws {TypeGuardError} When decoded value doesn't conform to type `T`
|
|
@@ -521,10 +546,12 @@ export function createFormData(): never;
|
|
|
521
546
|
* @template T Target object type
|
|
522
547
|
* @returns Reusable decoder function
|
|
523
548
|
*/
|
|
524
|
-
export function createFormData<T extends object>(): (
|
|
549
|
+
export function createFormData<T extends object>(): (
|
|
550
|
+
input: FormData,
|
|
551
|
+
) => Resolved<T>;
|
|
525
552
|
|
|
526
553
|
/** @internal */
|
|
527
|
-
export function createFormData<T>(): (input: FormData) => T {
|
|
554
|
+
export function createFormData<T>(): (input: FormData) => Resolved<T> {
|
|
528
555
|
NoTransformConfigurationError("http.createFormData");
|
|
529
556
|
}
|
|
530
557
|
|
|
@@ -553,13 +580,13 @@ export function createAssertFormData<T extends object>(
|
|
|
553
580
|
): (
|
|
554
581
|
input: FormData,
|
|
555
582
|
errorFactory?: undefined | ((props: TypeGuardError.IProps) => Error),
|
|
556
|
-
) => T
|
|
583
|
+
) => Resolved<T>;
|
|
557
584
|
|
|
558
585
|
/** @internal */
|
|
559
586
|
export function createAssertFormData<T>(): (
|
|
560
587
|
input: FormData,
|
|
561
588
|
errorFactory?: undefined | ((props: TypeGuardError.IProps) => Error),
|
|
562
|
-
) => T {
|
|
589
|
+
) => Resolved<T> {
|
|
563
590
|
NoTransformConfigurationError("http.createAssertFormData");
|
|
564
591
|
}
|
|
565
592
|
|
|
@@ -579,10 +606,10 @@ export function createIsFormData(): never;
|
|
|
579
606
|
*/
|
|
580
607
|
export function createIsFormData<T extends object>(): (
|
|
581
608
|
input: FormData,
|
|
582
|
-
) => T | null;
|
|
609
|
+
) => Resolved<T> | null;
|
|
583
610
|
|
|
584
611
|
/** @internal */
|
|
585
|
-
export function createIsFormData<T>(): (input: FormData) => T | null {
|
|
612
|
+
export function createIsFormData<T>(): (input: FormData) => Resolved<T> | null {
|
|
586
613
|
NoTransformConfigurationError("http.createIsFormData");
|
|
587
614
|
}
|
|
588
615
|
|
|
@@ -627,12 +654,12 @@ export function createQuery(): never;
|
|
|
627
654
|
*/
|
|
628
655
|
export function createQuery<T extends object>(): (
|
|
629
656
|
input: string | IReadableURLSearchParams,
|
|
630
|
-
) => T
|
|
657
|
+
) => Resolved<T>;
|
|
631
658
|
|
|
632
659
|
/** @internal */
|
|
633
660
|
export function createQuery<T>(): (
|
|
634
661
|
input: string | IReadableURLSearchParams,
|
|
635
|
-
) => T {
|
|
662
|
+
) => Resolved<T> {
|
|
636
663
|
NoTransformConfigurationError("http.createQuery");
|
|
637
664
|
}
|
|
638
665
|
|
|
@@ -661,13 +688,13 @@ export function createAssertQuery<T extends object>(
|
|
|
661
688
|
): (
|
|
662
689
|
input: string | IReadableURLSearchParams,
|
|
663
690
|
errorFactory?: undefined | ((props: TypeGuardError.IProps) => Error),
|
|
664
|
-
) => T
|
|
691
|
+
) => Resolved<T>;
|
|
665
692
|
|
|
666
693
|
/** @internal */
|
|
667
694
|
export function createAssertQuery<T>(): (
|
|
668
695
|
input: string | IReadableURLSearchParams,
|
|
669
696
|
errorFactory?: undefined | ((props: TypeGuardError.IProps) => Error),
|
|
670
|
-
) => T {
|
|
697
|
+
) => Resolved<T> {
|
|
671
698
|
NoTransformConfigurationError("http.createAssertQuery");
|
|
672
699
|
}
|
|
673
700
|
|
|
@@ -687,12 +714,12 @@ export function createIsQuery(): never;
|
|
|
687
714
|
*/
|
|
688
715
|
export function createIsQuery<T extends object>(): (
|
|
689
716
|
input: string | IReadableURLSearchParams,
|
|
690
|
-
) => T | null;
|
|
717
|
+
) => Resolved<T> | null;
|
|
691
718
|
|
|
692
719
|
/** @internal */
|
|
693
720
|
export function createIsQuery<T>(): (
|
|
694
721
|
input: string | IReadableURLSearchParams,
|
|
695
|
-
) => T | null {
|
|
722
|
+
) => Resolved<T> | null {
|
|
696
723
|
NoTransformConfigurationError("http.createIsQuery");
|
|
697
724
|
}
|
|
698
725
|
|
|
@@ -737,12 +764,12 @@ export function createHeaders(): never;
|
|
|
737
764
|
*/
|
|
738
765
|
export function createHeaders<T extends object>(): (
|
|
739
766
|
input: Record<string, string | string[] | undefined>,
|
|
740
|
-
) => T
|
|
767
|
+
) => Resolved<T>;
|
|
741
768
|
|
|
742
769
|
/** @internal */
|
|
743
770
|
export function createHeaders<T>(): (
|
|
744
771
|
input: Record<string, string | string[] | undefined>,
|
|
745
|
-
) => T {
|
|
772
|
+
) => Resolved<T> {
|
|
746
773
|
NoTransformConfigurationError("http.createHeaders");
|
|
747
774
|
}
|
|
748
775
|
|
|
@@ -771,13 +798,13 @@ export function createAssertHeaders<T extends object>(
|
|
|
771
798
|
): (
|
|
772
799
|
input: Record<string, string | string[] | undefined>,
|
|
773
800
|
errorFactory?: undefined | ((props: TypeGuardError.IProps) => Error),
|
|
774
|
-
) => T
|
|
801
|
+
) => Resolved<T>;
|
|
775
802
|
|
|
776
803
|
/** @internal */
|
|
777
804
|
export function createAssertHeaders<T>(): (
|
|
778
805
|
input: Record<string, string | string[] | undefined>,
|
|
779
806
|
errorFactory?: undefined | ((props: TypeGuardError.IProps) => Error),
|
|
780
|
-
) => T {
|
|
807
|
+
) => Resolved<T> {
|
|
781
808
|
NoTransformConfigurationError("http.createAssertHeaders");
|
|
782
809
|
}
|
|
783
810
|
|
|
@@ -797,12 +824,12 @@ export function createIsHeaders(): never;
|
|
|
797
824
|
*/
|
|
798
825
|
export function createIsHeaders<T extends object>(): (
|
|
799
826
|
input: Record<string, string | string[] | undefined>,
|
|
800
|
-
) => T | null;
|
|
827
|
+
) => Resolved<T> | null;
|
|
801
828
|
|
|
802
829
|
/** @internal */
|
|
803
830
|
export function createIsHeaders<T>(): (
|
|
804
831
|
input: Record<string, string | string[] | undefined>,
|
|
805
|
-
) => T | null {
|
|
832
|
+
) => Resolved<T> | null {
|
|
806
833
|
NoTransformConfigurationError("http.createIsHeaders");
|
|
807
834
|
}
|
|
808
835
|
|
|
@@ -847,11 +874,11 @@ export function createParameter(): never;
|
|
|
847
874
|
*/
|
|
848
875
|
export function createParameter<T extends Atomic.Type | null>(): (
|
|
849
876
|
input: string,
|
|
850
|
-
) => T
|
|
877
|
+
) => Resolved<T>;
|
|
851
878
|
|
|
852
879
|
/** @internal */
|
|
853
880
|
export function createParameter<T extends Atomic.Type | null>(): (
|
|
854
881
|
input: string,
|
|
855
|
-
) => T {
|
|
882
|
+
) => Resolved<T> {
|
|
856
883
|
NoTransformConfigurationError("http.createParameter");
|
|
857
884
|
}
|
|
@@ -3,7 +3,9 @@ export const _httpFormDataReadBigint = (
|
|
|
3
3
|
): bigint | null | undefined =>
|
|
4
4
|
input instanceof File
|
|
5
5
|
? (input as any)
|
|
6
|
-
:
|
|
6
|
+
: // Blank text is absent, as the empty string always was: `BigInt(" ")`
|
|
7
|
+
// is 0n, which would read a whitespace value as a real zero (#2448).
|
|
8
|
+
typeof input === "string" && input.trim().length !== 0
|
|
7
9
|
? input === "null"
|
|
8
10
|
? null
|
|
9
11
|
: (toBigint(input) as any)
|
|
@@ -3,7 +3,9 @@ export const _httpFormDataReadBoolean = (
|
|
|
3
3
|
): boolean | null | undefined =>
|
|
4
4
|
input instanceof File
|
|
5
5
|
? (input as any)
|
|
6
|
-
:
|
|
6
|
+
: // `undefined` is as absent as `null`, which `FormData.get` returns; a
|
|
7
|
+
// stand-in that answers `undefined` must not throw on `.length`.
|
|
8
|
+
input === null || input === undefined
|
|
7
9
|
? undefined
|
|
8
10
|
: input === "null"
|
|
9
11
|
? null
|
|
@@ -3,7 +3,9 @@ export const _httpFormDataReadNumber = (
|
|
|
3
3
|
): number | null | undefined =>
|
|
4
4
|
input instanceof File
|
|
5
5
|
? (input as any)
|
|
6
|
-
:
|
|
6
|
+
: // Blank text is absent, as the empty string always was: `Number(" ")`
|
|
7
|
+
// is 0, which would read a whitespace value as a real zero (#2448).
|
|
8
|
+
typeof input === "string" && input.trim().length !== 0
|
|
7
9
|
? input === "null"
|
|
8
10
|
? null
|
|
9
11
|
: (toNumber(input) as any)
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads one form field as a string.
|
|
3
|
+
*
|
|
4
|
+
* The text `"null"` spells `null` only where the property's type admits `null`;
|
|
5
|
+
* elsewhere it is the string `"null"` (#2450). The emitter passes `false` for a
|
|
6
|
+
* string whose type does not admit `null` and omits the argument otherwise, so
|
|
7
|
+
* code emitted before the parameter existed keeps its reading.
|
|
8
|
+
*/
|
|
1
9
|
export const _httpFormDataReadString = (
|
|
2
10
|
input: string | File | null,
|
|
11
|
+
nullable: boolean = true,
|
|
3
12
|
): string | null | undefined =>
|
|
4
13
|
input instanceof File
|
|
5
14
|
? (input as any)
|
|
6
15
|
: input === null
|
|
7
16
|
? undefined
|
|
8
|
-
: input === "null"
|
|
17
|
+
: nullable === true && input === "null"
|
|
9
18
|
? null
|
|
10
19
|
: input;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export const _httpHeaderReadBigint = (value: string | undefined) =>
|
|
2
|
-
|
|
2
|
+
// A blank header, or a blank element of a header list, is absent: `BigInt("")`
|
|
3
|
+
// is 0n, which let validators accept an empty header as a real zero (#2448).
|
|
4
|
+
value !== undefined && isBlank(value) === false ? toBigint(value) : undefined;
|
|
5
|
+
|
|
6
|
+
const isBlank = (value: string): boolean =>
|
|
7
|
+
typeof value === "string" && value.trim().length === 0;
|
|
3
8
|
|
|
4
9
|
const toBigint = (str: string): bigint | string => {
|
|
5
10
|
try {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export const _httpHeaderReadNumber = (value: string | undefined) =>
|
|
2
|
-
|
|
2
|
+
// A blank header, or a blank element of a header list, is absent: `Number("")`
|
|
3
|
+
// is 0, which let validators accept an empty header as a real zero (#2448).
|
|
4
|
+
value !== undefined && isBlank(value) === false ? toNumber(value) : undefined;
|
|
5
|
+
|
|
6
|
+
const isBlank = (value: string): boolean =>
|
|
7
|
+
typeof value === "string" && value.trim().length === 0;
|
|
3
8
|
|
|
4
9
|
const toNumber = (str: string): number | string => {
|
|
5
10
|
const value: number = Number(str);
|
|
@@ -2,6 +2,9 @@ export const _httpParameterReadBigint = (value: string) =>
|
|
|
2
2
|
value !== "null" ? toBigint(value) : null;
|
|
3
3
|
|
|
4
4
|
const toBigint = (str: string): bigint | string => {
|
|
5
|
+
// Blank text stays text, so the assertion rejects it: `BigInt(" ")` is 0n,
|
|
6
|
+
// which read a blank path segment as a real zero (#2448).
|
|
7
|
+
if (str.trim().length === 0) return str;
|
|
5
8
|
try {
|
|
6
9
|
return BigInt(str);
|
|
7
10
|
} catch {
|
|
@@ -2,6 +2,9 @@ export const _httpParameterReadNumber = (value: string) =>
|
|
|
2
2
|
value !== "null" ? toNumber(value) : null;
|
|
3
3
|
|
|
4
4
|
const toNumber = (str: string): number | string => {
|
|
5
|
+
// Blank text stays text, so the assertion rejects it: `Number(" ")` is 0,
|
|
6
|
+
// which read a blank path segment as a real zero (#2448).
|
|
7
|
+
if (str.trim().length === 0) return str;
|
|
5
8
|
const value: number = Number(str);
|
|
6
9
|
return isNaN(value) ? str : value;
|
|
7
10
|
};
|
|
@@ -1,2 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Reads one path parameter as a string.
|
|
3
|
+
*
|
|
4
|
+
* The text `"null"` spells `null` only where the parameter's type admits
|
|
5
|
+
* `null`; elsewhere it is the string `"null"` (#2450). The emitter passes
|
|
6
|
+
* `false` for a string whose type does not admit `null` and omits the argument
|
|
7
|
+
* otherwise, so code emitted before the parameter existed keeps its reading.
|
|
8
|
+
*/
|
|
9
|
+
export const _httpParameterReadString = (
|
|
10
|
+
value: string,
|
|
11
|
+
nullable: boolean = true,
|
|
12
|
+
) => (nullable === true && value === "null" ? null : value);
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export const _httpQueryReadBigint = (
|
|
2
2
|
str: string | null,
|
|
3
3
|
): bigint | null | undefined =>
|
|
4
|
-
|
|
4
|
+
// Blank text is absent, as the empty string always was: `BigInt(" ")` is 0n,
|
|
5
|
+
// which would read a whitespace value as a real zero (#2448).
|
|
6
|
+
typeof str === "string" && str.trim().length !== 0
|
|
7
|
+
? str === "null"
|
|
8
|
+
? null
|
|
9
|
+
: (toBigint(str) as any)
|
|
10
|
+
: undefined;
|
|
5
11
|
|
|
6
12
|
const toBigint = (str: string): bigint | string => {
|
|
7
13
|
try {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export const _httpQueryReadBoolean = (
|
|
2
2
|
str: string | null,
|
|
3
3
|
): boolean | null | undefined =>
|
|
4
|
-
|
|
4
|
+
// `undefined` is as absent as `null`, which the contract returns; a
|
|
5
|
+
// stand-in reader that answers `undefined` must not throw on `.length`.
|
|
6
|
+
str === null || str === undefined
|
|
5
7
|
? undefined
|
|
6
8
|
: str === "null"
|
|
7
9
|
? null
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export const _httpQueryReadNumber = (
|
|
2
2
|
str: string | null,
|
|
3
3
|
): number | null | undefined =>
|
|
4
|
-
|
|
4
|
+
// Blank text is absent, as the empty string always was: `Number(" ")` is 0,
|
|
5
|
+
// which would read a whitespace value as a real zero (#2448).
|
|
6
|
+
typeof str === "string" && str.trim().length !== 0
|
|
7
|
+
? str === "null"
|
|
8
|
+
? null
|
|
9
|
+
: (toNumber(str) as any)
|
|
10
|
+
: undefined;
|
|
5
11
|
|
|
6
12
|
const toNumber = (str: string): number | string => {
|
|
7
13
|
const value: number = Number(str);
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads one query value as a string.
|
|
3
|
+
*
|
|
4
|
+
* The text `"null"` spells `null` only where the property's type admits `null`;
|
|
5
|
+
* elsewhere it is the string `"null"` (#2450). The emitter passes `false` for a
|
|
6
|
+
* string whose type does not admit `null` and omits the argument otherwise, so
|
|
7
|
+
* code emitted before the parameter existed keeps its reading.
|
|
8
|
+
*/
|
|
1
9
|
export const _httpQueryReadString = (
|
|
2
10
|
str: string | null,
|
|
11
|
+
nullable: boolean = true,
|
|
3
12
|
): string | null | undefined =>
|
|
4
|
-
str === null ? undefined : str === "null" ? null : str;
|
|
13
|
+
str === null ? undefined : nullable === true && str === "null" ? null : str;
|