mirror of
https://github.com/zoriya/typebox.git
synced 2026-05-27 16:43:30 +00:00
Revision 0.33.4 (#953)
* Add Assert and Parse Functions * Documentation * Version * Benchmarks
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@sinclair/typebox",
|
||||
"version": "0.33.3",
|
||||
"version": "0.33.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@sinclair/typebox",
|
||||
"version": "0.33.3",
|
||||
"version": "0.33.4",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "^0.13.2",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@sinclair/typebox",
|
||||
"version": "0.33.3",
|
||||
"version": "0.33.4",
|
||||
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
|
||||
"keywords": [
|
||||
"typescript",
|
||||
|
||||
@@ -74,13 +74,12 @@ License MIT
|
||||
- [Indexed](#types-indexed)
|
||||
- [Mapped](#types-mapped)
|
||||
- [Conditional](#types-conditional)
|
||||
- [Intrinsic](#types-intrinsic)
|
||||
- [Transform](#types-transform)
|
||||
- [Rest](#types-rest)
|
||||
- [Guard](#types-guard)
|
||||
- [Unsafe](#types-unsafe)
|
||||
- [Strict](#types-strict)
|
||||
- [Values](#values)
|
||||
- [Assert](#values-assert)
|
||||
- [Create](#values-create)
|
||||
- [Clone](#values-clone)
|
||||
- [Check](#values-check)
|
||||
@@ -90,6 +89,7 @@ License MIT
|
||||
- [Cast](#values-cast)
|
||||
- [Decode](#values-decode)
|
||||
- [Encode](#values-decode)
|
||||
- [Parse](#values-parse)
|
||||
- [Equal](#values-equal)
|
||||
- [Hash](#values-hash)
|
||||
- [Diff](#values-diff)
|
||||
@@ -176,19 +176,17 @@ type T = Static<typeof T> // type T = {
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
//
|
||||
// ... then use the type both as Json Schema and as a TypeScript type.
|
||||
// ... or use the type to parse JavaScript values.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
||||
import { Value } from '@sinclair/typebox/value'
|
||||
|
||||
function receive(value: T) { // ... as a Static Type
|
||||
|
||||
if(Value.Check(T, value)) { // ... as a Json Schema
|
||||
|
||||
// ok...
|
||||
}
|
||||
}
|
||||
const R = Value.Parse(T, value) // const R: {
|
||||
// id: string,
|
||||
// name: string,
|
||||
// timestamp: number
|
||||
// }
|
||||
```
|
||||
|
||||
<a name='types'></a>
|
||||
@@ -1000,38 +998,6 @@ const C = Type.Exclude( // type C = Exclude<1 | 2 |
|
||||
) // ]>
|
||||
```
|
||||
|
||||
<a name='types-intrinsic'></a>
|
||||
|
||||
### Intrinsic Types
|
||||
|
||||
TypeBox supports the TypeScript intrinsic string manipulation types Uppercase, Lowercase, Capitalize and Uncapitalize. These types can be used to remap Literal, Template Literal and Union of Literal types.
|
||||
|
||||
```typescript
|
||||
// TypeScript
|
||||
type A = Capitalize<'hello'> // type A = 'Hello'
|
||||
|
||||
type B = Capitalize<'hello' | 'world'> // type C = 'Hello' | 'World'
|
||||
|
||||
type C = Capitalize<`hello${1|2|3}`> // type B = 'Hello1' | 'Hello2' | 'Hello3'
|
||||
|
||||
// TypeBox
|
||||
const A = Type.Capitalize(Type.Literal('hello')) // const A: TLiteral<'Hello'>
|
||||
|
||||
const B = Type.Capitalize(Type.Union([ // const B: TUnion<[
|
||||
Type.Literal('hello'), // TLiteral<'Hello'>,
|
||||
Type.Literal('world') // TLiteral<'World'>
|
||||
])) // ]>
|
||||
|
||||
const C = Type.Capitalize( // const C: TTemplateLiteral<[
|
||||
Type.TemplateLiteral('hello${1|2|3}') // TLiteral<'Hello'>,
|
||||
) // TUnion<[
|
||||
// TLiteral<'1'>,
|
||||
// TLiteral<'2'>,
|
||||
// TLiteral<'3'>
|
||||
// ]>
|
||||
// ]>
|
||||
```
|
||||
|
||||
<a name='types-transform'></a>
|
||||
|
||||
### Transform Types
|
||||
@@ -1061,26 +1027,6 @@ type E = StaticEncode<typeof T> // type E = Array<number>
|
||||
type T = Static<typeof T> // type T = Array<number>
|
||||
```
|
||||
|
||||
<a name='types-rest'></a>
|
||||
|
||||
### Rest Types
|
||||
|
||||
TypeBox provides the Rest type to uniformly extract variadic tuples from Intersect, Union and Tuple types. This type can be useful to remap variadic types into different forms. The following uses Rest to remap a Tuple into a Union.
|
||||
|
||||
```typescript
|
||||
const T = Type.Tuple([ // const T: TTuple<[
|
||||
Type.String(), // TString,
|
||||
Type.Number() // TNumber
|
||||
]) // ]>
|
||||
|
||||
const R = Type.Rest(T) // const R: [TString, TNumber]
|
||||
|
||||
const U = Type.Union(R) // const T: TUnion<[
|
||||
// TString,
|
||||
// TNumber
|
||||
// ]>
|
||||
```
|
||||
|
||||
<a name='types-unsafe'></a>
|
||||
|
||||
### Unsafe Types
|
||||
@@ -1171,6 +1117,18 @@ TypeBox provides an optional Value submodule that can be used to perform structu
|
||||
import { Value } from '@sinclair/typebox/value'
|
||||
```
|
||||
|
||||
<a name='values-assert'></a>
|
||||
|
||||
### Assert
|
||||
|
||||
Use the Assert function to assert a value is valid.
|
||||
|
||||
```typescript
|
||||
let value: unknown = 1
|
||||
|
||||
Value.Assert(Type.Number(), value) // throws AssertError if invalid
|
||||
```
|
||||
|
||||
<a name='values-create'></a>
|
||||
|
||||
### Create
|
||||
@@ -1296,6 +1254,32 @@ const A = Value.Encode(Type.String(), 'hello') // const A = 'hello'
|
||||
const B = Value.Encode(Type.String(), 42) // throw
|
||||
```
|
||||
|
||||
<a name='values-parse'></a>
|
||||
|
||||
### Parse
|
||||
|
||||
Use the Parse function to parse a value or throw if invalid. This function internally uses Default, Clean, Convert and Decode to make a best effort attempt to parse the value into the expected type. This function should not be used in performance critical code paths.
|
||||
|
||||
```typescript
|
||||
const T = Type.Object({ x: Type.Number({ default: 0 }), y: Type.Number({ default: 0 }) })
|
||||
|
||||
// Default
|
||||
|
||||
const A = Value.Parse(T, { }) // const A = { x: 0, y: 0 }
|
||||
|
||||
// Convert
|
||||
|
||||
const B = Value.Parse(T, { x: '1', y: '2' }) // const B = { x: 1, y: 2 }
|
||||
|
||||
// Clean
|
||||
|
||||
const C = Value.Parse(T, { x: 1, y: 2, z: 3 }) // const C = { x: 1, y: 2 }
|
||||
|
||||
// Assert
|
||||
|
||||
const D = Value.Parse(T, undefined) // throws AssertError
|
||||
```
|
||||
|
||||
<a name='values-equal'></a>
|
||||
|
||||
### Equal
|
||||
@@ -1716,37 +1700,37 @@ This benchmark measures compilation performance for varying types.
|
||||
|
||||
```typescript
|
||||
┌────────────────────────────┬────────────┬──────────────┬──────────────┬──────────────┐
|
||||
│ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │
|
||||
│ (index) │ Iterations │ Ajv │ TypeCompiler │ Performance │
|
||||
├────────────────────────────┼────────────┼──────────────┼──────────────┼──────────────┤
|
||||
│ Literal_String │ 1000 │ ' 242 ms' │ ' 10 ms' │ ' 24.20 x' │
|
||||
│ Literal_Number │ 1000 │ ' 200 ms' │ ' 8 ms' │ ' 25.00 x' │
|
||||
│ Literal_Boolean │ 1000 │ ' 168 ms' │ ' 6 ms' │ ' 28.00 x' │
|
||||
│ Primitive_Number │ 1000 │ ' 165 ms' │ ' 8 ms' │ ' 20.63 x' │
|
||||
│ Primitive_String │ 1000 │ ' 154 ms' │ ' 6 ms' │ ' 25.67 x' │
|
||||
│ Primitive_String_Pattern │ 1000 │ ' 208 ms' │ ' 14 ms' │ ' 14.86 x' │
|
||||
│ Primitive_Boolean │ 1000 │ ' 142 ms' │ ' 6 ms' │ ' 23.67 x' │
|
||||
│ Primitive_Null │ 1000 │ ' 143 ms' │ ' 6 ms' │ ' 23.83 x' │
|
||||
│ Object_Unconstrained │ 1000 │ ' 1217 ms' │ ' 31 ms' │ ' 39.26 x' │
|
||||
│ Object_Constrained │ 1000 │ ' 1275 ms' │ ' 26 ms' │ ' 49.04 x' │
|
||||
│ Object_Vector3 │ 1000 │ ' 405 ms' │ ' 12 ms' │ ' 33.75 x' │
|
||||
│ Object_Box3D │ 1000 │ ' 1833 ms' │ ' 27 ms' │ ' 67.89 x' │
|
||||
│ Tuple_Primitive │ 1000 │ ' 475 ms' │ ' 13 ms' │ ' 36.54 x' │
|
||||
│ Tuple_Object │ 1000 │ ' 1267 ms' │ ' 30 ms' │ ' 42.23 x' │
|
||||
│ Composite_Intersect │ 1000 │ ' 604 ms' │ ' 18 ms' │ ' 33.56 x' │
|
||||
│ Composite_Union │ 1000 │ ' 545 ms' │ ' 20 ms' │ ' 27.25 x' │
|
||||
│ Math_Vector4 │ 1000 │ ' 829 ms' │ ' 12 ms' │ ' 69.08 x' │
|
||||
│ Math_Matrix4 │ 1000 │ ' 405 ms' │ ' 10 ms' │ ' 40.50 x' │
|
||||
│ Array_Primitive_Number │ 1000 │ ' 372 ms' │ ' 12 ms' │ ' 31.00 x' │
|
||||
│ Array_Primitive_String │ 1000 │ ' 327 ms' │ ' 5 ms' │ ' 65.40 x' │
|
||||
│ Array_Primitive_Boolean │ 1000 │ ' 300 ms' │ ' 4 ms' │ ' 75.00 x' │
|
||||
│ Array_Object_Unconstrained │ 1000 │ ' 1755 ms' │ ' 21 ms' │ ' 83.57 x' │
|
||||
│ Array_Object_Constrained │ 1000 │ ' 1516 ms' │ ' 20 ms' │ ' 75.80 x' │
|
||||
│ Array_Tuple_Primitive │ 1000 │ ' 825 ms' │ ' 14 ms' │ ' 58.93 x' │
|
||||
│ Array_Tuple_Object │ 1000 │ ' 1616 ms' │ ' 16 ms' │ ' 101.00 x' │
|
||||
│ Array_Composite_Intersect │ 1000 │ ' 776 ms' │ ' 16 ms' │ ' 48.50 x' │
|
||||
│ Array_Composite_Union │ 1000 │ ' 820 ms' │ ' 14 ms' │ ' 58.57 x' │
|
||||
│ Array_Math_Vector4 │ 1000 │ ' 1166 ms' │ ' 15 ms' │ ' 77.73 x' │
|
||||
│ Array_Math_Matrix4 │ 1000 │ ' 695 ms' │ ' 8 ms' │ ' 86.88 x' │
|
||||
│ Literal_String │ 1000 │ ' 211 ms' │ ' 8 ms' │ ' 26.38 x' │
|
||||
│ Literal_Number │ 1000 │ ' 185 ms' │ ' 5 ms' │ ' 37.00 x' │
|
||||
│ Literal_Boolean │ 1000 │ ' 195 ms' │ ' 4 ms' │ ' 48.75 x' │
|
||||
│ Primitive_Number │ 1000 │ ' 149 ms' │ ' 7 ms' │ ' 21.29 x' │
|
||||
│ Primitive_String │ 1000 │ ' 135 ms' │ ' 5 ms' │ ' 27.00 x' │
|
||||
│ Primitive_String_Pattern │ 1000 │ ' 193 ms' │ ' 10 ms' │ ' 19.30 x' │
|
||||
│ Primitive_Boolean │ 1000 │ ' 152 ms' │ ' 4 ms' │ ' 38.00 x' │
|
||||
│ Primitive_Null │ 1000 │ ' 147 ms' │ ' 4 ms' │ ' 36.75 x' │
|
||||
│ Object_Unconstrained │ 1000 │ ' 1065 ms' │ ' 26 ms' │ ' 40.96 x' │
|
||||
│ Object_Constrained │ 1000 │ ' 1183 ms' │ ' 26 ms' │ ' 45.50 x' │
|
||||
│ Object_Vector3 │ 1000 │ ' 407 ms' │ ' 9 ms' │ ' 45.22 x' │
|
||||
│ Object_Box3D │ 1000 │ ' 1777 ms' │ ' 24 ms' │ ' 74.04 x' │
|
||||
│ Tuple_Primitive │ 1000 │ ' 485 ms' │ ' 11 ms' │ ' 44.09 x' │
|
||||
│ Tuple_Object │ 1000 │ ' 1344 ms' │ ' 17 ms' │ ' 79.06 x' │
|
||||
│ Composite_Intersect │ 1000 │ ' 606 ms' │ ' 14 ms' │ ' 43.29 x' │
|
||||
│ Composite_Union │ 1000 │ ' 522 ms' │ ' 17 ms' │ ' 30.71 x' │
|
||||
│ Math_Vector4 │ 1000 │ ' 851 ms' │ ' 9 ms' │ ' 94.56 x' │
|
||||
│ Math_Matrix4 │ 1000 │ ' 406 ms' │ ' 10 ms' │ ' 40.60 x' │
|
||||
│ Array_Primitive_Number │ 1000 │ ' 367 ms' │ ' 6 ms' │ ' 61.17 x' │
|
||||
│ Array_Primitive_String │ 1000 │ ' 339 ms' │ ' 7 ms' │ ' 48.43 x' │
|
||||
│ Array_Primitive_Boolean │ 1000 │ ' 325 ms' │ ' 5 ms' │ ' 65.00 x' │
|
||||
│ Array_Object_Unconstrained │ 1000 │ ' 1863 ms' │ ' 21 ms' │ ' 88.71 x' │
|
||||
│ Array_Object_Constrained │ 1000 │ ' 1535 ms' │ ' 18 ms' │ ' 85.28 x' │
|
||||
│ Array_Tuple_Primitive │ 1000 │ ' 829 ms' │ ' 14 ms' │ ' 59.21 x' │
|
||||
│ Array_Tuple_Object │ 1000 │ ' 1674 ms' │ ' 14 ms' │ ' 119.57 x' │
|
||||
│ Array_Composite_Intersect │ 1000 │ ' 789 ms' │ ' 13 ms' │ ' 60.69 x' │
|
||||
│ Array_Composite_Union │ 1000 │ ' 822 ms' │ ' 15 ms' │ ' 54.80 x' │
|
||||
│ Array_Math_Vector4 │ 1000 │ ' 1129 ms' │ ' 14 ms' │ ' 80.64 x' │
|
||||
│ Array_Math_Matrix4 │ 1000 │ ' 673 ms' │ ' 9 ms' │ ' 74.78 x' │
|
||||
└────────────────────────────┴────────────┴──────────────┴──────────────┴──────────────┘
|
||||
```
|
||||
|
||||
@@ -1758,39 +1742,39 @@ This benchmark measures validation performance for varying types.
|
||||
|
||||
```typescript
|
||||
┌────────────────────────────┬────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
|
||||
│ (index) │ Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │
|
||||
│ (index) │ Iterations │ ValueCheck │ Ajv │ TypeCompiler │ Performance │
|
||||
├────────────────────────────┼────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
|
||||
│ Literal_String │ 1000000 │ ' 18 ms' │ ' 5 ms' │ ' 4 ms' │ ' 1.25 x' │
|
||||
│ Literal_Number │ 1000000 │ ' 16 ms' │ ' 18 ms' │ ' 10 ms' │ ' 1.80 x' │
|
||||
│ Literal_Boolean │ 1000000 │ ' 15 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
|
||||
│ Primitive_Number │ 1000000 │ ' 21 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
|
||||
│ Primitive_String │ 1000000 │ ' 22 ms' │ ' 18 ms' │ ' 9 ms' │ ' 2.00 x' │
|
||||
│ Primitive_String_Pattern │ 1000000 │ ' 155 ms' │ ' 41 ms' │ ' 34 ms' │ ' 1.21 x' │
|
||||
│ Primitive_Boolean │ 1000000 │ ' 18 ms' │ ' 17 ms' │ ' 9 ms' │ ' 1.89 x' │
|
||||
│ Primitive_Null │ 1000000 │ ' 19 ms' │ ' 17 ms' │ ' 9 ms' │ ' 1.89 x' │
|
||||
│ Object_Unconstrained │ 1000000 │ ' 1003 ms' │ ' 32 ms' │ ' 24 ms' │ ' 1.33 x' │
|
||||
│ Object_Constrained │ 1000000 │ ' 1265 ms' │ ' 49 ms' │ ' 38 ms' │ ' 1.29 x' │
|
||||
│ Object_Vector3 │ 1000000 │ ' 418 ms' │ ' 22 ms' │ ' 13 ms' │ ' 1.69 x' │
|
||||
│ Object_Box3D │ 1000000 │ ' 2035 ms' │ ' 56 ms' │ ' 49 ms' │ ' 1.14 x' │
|
||||
│ Object_Recursive │ 1000000 │ ' 5243 ms' │ ' 326 ms' │ ' 157 ms' │ ' 2.08 x' │
|
||||
│ Tuple_Primitive │ 1000000 │ ' 153 ms' │ ' 20 ms' │ ' 12 ms' │ ' 1.67 x' │
|
||||
│ Tuple_Object │ 1000000 │ ' 781 ms' │ ' 28 ms' │ ' 18 ms' │ ' 1.56 x' │
|
||||
│ Composite_Intersect │ 1000000 │ ' 742 ms' │ ' 25 ms' │ ' 14 ms' │ ' 1.79 x' │
|
||||
│ Composite_Union │ 1000000 │ ' 558 ms' │ ' 24 ms' │ ' 13 ms' │ ' 1.85 x' │
|
||||
│ Math_Vector4 │ 1000000 │ ' 246 ms' │ ' 22 ms' │ ' 11 ms' │ ' 2.00 x' │
|
||||
│ Math_Matrix4 │ 1000000 │ ' 1052 ms' │ ' 43 ms' │ ' 28 ms' │ ' 1.54 x' │
|
||||
│ Array_Primitive_Number │ 1000000 │ ' 272 ms' │ ' 22 ms' │ ' 12 ms' │ ' 1.83 x' │
|
||||
│ Array_Primitive_String │ 1000000 │ ' 235 ms' │ ' 24 ms' │ ' 14 ms' │ ' 1.71 x' │
|
||||
│ Array_Primitive_Boolean │ 1000000 │ ' 134 ms' │ ' 23 ms' │ ' 14 ms' │ ' 1.64 x' │
|
||||
│ Array_Object_Unconstrained │ 1000000 │ ' 6280 ms' │ ' 65 ms' │ ' 59 ms' │ ' 1.10 x' │
|
||||
│ Array_Object_Constrained │ 1000000 │ ' 6076 ms' │ ' 130 ms' │ ' 119 ms' │ ' 1.09 x' │
|
||||
│ Array_Object_Recursive │ 1000000 │ ' 22738 ms' │ ' 1730 ms' │ ' 635 ms' │ ' 2.72 x' │
|
||||
│ Array_Tuple_Primitive │ 1000000 │ ' 689 ms' │ ' 35 ms' │ ' 30 ms' │ ' 1.17 x' │
|
||||
│ Array_Tuple_Object │ 1000000 │ ' 3266 ms' │ ' 63 ms' │ ' 52 ms' │ ' 1.21 x' │
|
||||
│ Array_Composite_Intersect │ 1000000 │ ' 3310 ms' │ ' 44 ms' │ ' 36 ms' │ ' 1.22 x' │
|
||||
│ Array_Composite_Union │ 1000000 │ ' 2432 ms' │ ' 69 ms' │ ' 33 ms' │ ' 2.09 x' │
|
||||
│ Array_Math_Vector4 │ 1000000 │ ' 1158 ms' │ ' 37 ms' │ ' 24 ms' │ ' 1.54 x' │
|
||||
│ Array_Math_Matrix4 │ 1000000 │ ' 5435 ms' │ ' 132 ms' │ ' 92 ms' │ ' 1.43 x' │
|
||||
│ Literal_String │ 1000000 │ ' 17 ms' │ ' 5 ms' │ ' 5 ms' │ ' 1.00 x' │
|
||||
│ Literal_Number │ 1000000 │ ' 14 ms' │ ' 18 ms' │ ' 9 ms' │ ' 2.00 x' │
|
||||
│ Literal_Boolean │ 1000000 │ ' 14 ms' │ ' 20 ms' │ ' 9 ms' │ ' 2.22 x' │
|
||||
│ Primitive_Number │ 1000000 │ ' 17 ms' │ ' 19 ms' │ ' 9 ms' │ ' 2.11 x' │
|
||||
│ Primitive_String │ 1000000 │ ' 17 ms' │ ' 18 ms' │ ' 10 ms' │ ' 1.80 x' │
|
||||
│ Primitive_String_Pattern │ 1000000 │ ' 172 ms' │ ' 46 ms' │ ' 41 ms' │ ' 1.12 x' │
|
||||
│ Primitive_Boolean │ 1000000 │ ' 14 ms' │ ' 19 ms' │ ' 10 ms' │ ' 1.90 x' │
|
||||
│ Primitive_Null │ 1000000 │ ' 16 ms' │ ' 19 ms' │ ' 9 ms' │ ' 2.11 x' │
|
||||
│ Object_Unconstrained │ 1000000 │ ' 437 ms' │ ' 28 ms' │ ' 14 ms' │ ' 2.00 x' │
|
||||
│ Object_Constrained │ 1000000 │ ' 653 ms' │ ' 46 ms' │ ' 37 ms' │ ' 1.24 x' │
|
||||
│ Object_Vector3 │ 1000000 │ ' 201 ms' │ ' 22 ms' │ ' 12 ms' │ ' 1.83 x' │
|
||||
│ Object_Box3D │ 1000000 │ ' 961 ms' │ ' 37 ms' │ ' 19 ms' │ ' 1.95 x' │
|
||||
│ Object_Recursive │ 1000000 │ ' 3715 ms' │ ' 363 ms' │ ' 174 ms' │ ' 2.09 x' │
|
||||
│ Tuple_Primitive │ 1000000 │ ' 107 ms' │ ' 23 ms' │ ' 11 ms' │ ' 2.09 x' │
|
||||
│ Tuple_Object │ 1000000 │ ' 375 ms' │ ' 28 ms' │ ' 15 ms' │ ' 1.87 x' │
|
||||
│ Composite_Intersect │ 1000000 │ ' 377 ms' │ ' 22 ms' │ ' 12 ms' │ ' 1.83 x' │
|
||||
│ Composite_Union │ 1000000 │ ' 337 ms' │ ' 30 ms' │ ' 17 ms' │ ' 1.76 x' │
|
||||
│ Math_Vector4 │ 1000000 │ ' 137 ms' │ ' 23 ms' │ ' 11 ms' │ ' 2.09 x' │
|
||||
│ Math_Matrix4 │ 1000000 │ ' 576 ms' │ ' 37 ms' │ ' 28 ms' │ ' 1.32 x' │
|
||||
│ Array_Primitive_Number │ 1000000 │ ' 145 ms' │ ' 23 ms' │ ' 12 ms' │ ' 1.92 x' │
|
||||
│ Array_Primitive_String │ 1000000 │ ' 152 ms' │ ' 22 ms' │ ' 13 ms' │ ' 1.69 x' │
|
||||
│ Array_Primitive_Boolean │ 1000000 │ ' 131 ms' │ ' 20 ms' │ ' 13 ms' │ ' 1.54 x' │
|
||||
│ Array_Object_Unconstrained │ 1000000 │ ' 2821 ms' │ ' 62 ms' │ ' 45 ms' │ ' 1.38 x' │
|
||||
│ Array_Object_Constrained │ 1000000 │ ' 2958 ms' │ ' 119 ms' │ ' 134 ms' │ ' 0.89 x' │
|
||||
│ Array_Object_Recursive │ 1000000 │ ' 14695 ms' │ ' 1621 ms' │ ' 635 ms' │ ' 2.55 x' │
|
||||
│ Array_Tuple_Primitive │ 1000000 │ ' 478 ms' │ ' 35 ms' │ ' 28 ms' │ ' 1.25 x' │
|
||||
│ Array_Tuple_Object │ 1000000 │ ' 1623 ms' │ ' 63 ms' │ ' 48 ms' │ ' 1.31 x' │
|
||||
│ Array_Composite_Intersect │ 1000000 │ ' 1582 ms' │ ' 43 ms' │ ' 30 ms' │ ' 1.43 x' │
|
||||
│ Array_Composite_Union │ 1000000 │ ' 1331 ms' │ ' 76 ms' │ ' 40 ms' │ ' 1.90 x' │
|
||||
│ Array_Math_Vector4 │ 1000000 │ ' 564 ms' │ ' 38 ms' │ ' 24 ms' │ ' 1.58 x' │
|
||||
│ Array_Math_Matrix4 │ 1000000 │ ' 2382 ms' │ ' 111 ms' │ ' 83 ms' │ ' 1.34 x' │
|
||||
└────────────────────────────┴────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
|
||||
```
|
||||
|
||||
@@ -1802,13 +1786,13 @@ The following table lists esbuild compiled and minified sizes for each TypeBox m
|
||||
|
||||
```typescript
|
||||
┌──────────────────────┬────────────┬────────────┬─────────────┐
|
||||
│ (index) │ Compiled │ Minified │ Compression │
|
||||
│ (index) │ Compiled │ Minified │ Compression │
|
||||
├──────────────────────┼────────────┼────────────┼─────────────┤
|
||||
│ typebox/compiler │ '126.9 kb' │ ' 55.7 kb' │ '2.28 x' │
|
||||
│ typebox/errors │ ' 46.1 kb' │ ' 20.8 kb' │ '2.22 x' │
|
||||
│ typebox/system │ ' 4.7 kb' │ ' 2.0 kb' │ '2.33 x' │
|
||||
│ typebox/value │ '152.2 kb' │ ' 64.5 kb' │ '2.36 x' │
|
||||
│ typebox │ ' 95.7 kb' │ ' 39.8 kb' │ '2.40 x' │
|
||||
│ typebox/compiler │ '119.6 kb' │ ' 52.6 kb' │ '2.27 x' │
|
||||
│ typebox/errors │ ' 48.6 kb' │ ' 21.9 kb' │ '2.22 x' │
|
||||
│ typebox/system │ ' 7.4 kb' │ ' 3.2 kb' │ '2.33 x' │
|
||||
│ typebox/value │ '157.8 kb' │ ' 66.6 kb' │ '2.37 x' │
|
||||
│ typebox │ ' 98.3 kb' │ ' 40.9 kb' │ '2.40 x' │
|
||||
└──────────────────────┴────────────┴────────────┴─────────────┘
|
||||
```
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ import type { TSymbol } from '../type/symbol/index'
|
||||
import type { TUndefined } from '../type/undefined/index'
|
||||
import type { TUint8Array } from '../type/uint8array/index'
|
||||
import type { TVoid } from '../type/void/index'
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ValueGuard
|
||||
// ------------------------------------------------------------------
|
||||
@@ -104,15 +105,15 @@ export class TypeCheck<T extends TSchema> {
|
||||
return this.checkFunc(value)
|
||||
}
|
||||
/** Decodes a value or throws if error */
|
||||
public Decode(value: unknown): StaticDecode<T> {
|
||||
public Decode<R = StaticDecode<T>>(value: unknown): R {
|
||||
if (!this.checkFunc(value)) throw new TransformDecodeCheckError(this.schema, value, this.Errors(value).First()!)
|
||||
return this.hasTransform ? TransformDecode(this.schema, this.references, value) : value
|
||||
return (this.hasTransform ? TransformDecode(this.schema, this.references, value) : value) as never
|
||||
}
|
||||
/** Encodes a value or throws if error */
|
||||
public Encode(value: unknown): StaticEncode<T> {
|
||||
public Encode<R = StaticEncode<T>>(value: unknown): R {
|
||||
const encoded = this.hasTransform ? TransformEncode(this.schema, this.references, value) : value
|
||||
if (!this.checkFunc(encoded)) throw new TransformEncodeCheckError(this.schema, value, this.Errors(value).First()!)
|
||||
return encoded
|
||||
return encoded as never
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
@sinclair/typebox/value
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import { Errors, ValueErrorIterator, ValueError } from '../../errors/index'
|
||||
import { TypeBoxError } from '../../type/error/error'
|
||||
import { TSchema } from '../../type/schema/index'
|
||||
import { Static } from '../../type/static/index'
|
||||
import { Check } from '../check/check'
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// AssertError
|
||||
// ------------------------------------------------------------------
|
||||
export class AssertError extends TypeBoxError {
|
||||
readonly #iterator: ValueErrorIterator
|
||||
error: ValueError | undefined
|
||||
constructor(iterator: ValueErrorIterator) {
|
||||
const error = iterator.First()
|
||||
super(error === undefined ? 'Invalid Value' : error.message)
|
||||
this.#iterator = iterator
|
||||
this.error = error
|
||||
}
|
||||
/** Returns an iterator for each error in this value. */
|
||||
public Errors(): ValueErrorIterator {
|
||||
return new ValueErrorIterator(this.#Iterator())
|
||||
}
|
||||
*#Iterator(): IterableIterator<ValueError> {
|
||||
if (this.error) yield this.error
|
||||
yield* this.#iterator
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// AssertValue
|
||||
// ------------------------------------------------------------------
|
||||
function AssertValue(schema: TSchema, references: TSchema[], value: unknown): unknown {
|
||||
if (Check(schema, references, value)) return
|
||||
throw new AssertError(Errors(schema, references, value))
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// Assert
|
||||
// ------------------------------------------------------------------
|
||||
/** Asserts a value matches the given type or throws an `AssertError` if invalid */
|
||||
export function Assert<T extends TSchema>(schema: T, references: TSchema[], value: unknown): asserts value is Static<T>
|
||||
/** Asserts a value matches the given type or throws an `AssertError` if invalid */
|
||||
export function Assert<T extends TSchema>(schema: T, value: unknown): asserts value is Static<T>
|
||||
/** Asserts a value matches the given type or throws an `AssertError` if invalid */
|
||||
export function Assert(...args: any[]): unknown {
|
||||
return args.length === 3 ? AssertValue(args[0], args[1], args[2]) : AssertValue(args[0], [], args[1])
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
@sinclair/typebox/value
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
export * from './assert'
|
||||
@@ -26,7 +26,7 @@ THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import { IsStandardObject, IsArray, IsString, IsNumber, IsNull } from '../guard/index'
|
||||
import { IsObject, IsArray, IsString, IsNumber, IsNull } from '../guard/index'
|
||||
import { TypeBoxError } from '../../type/error/index'
|
||||
import { Kind } from '../../type/symbols/index'
|
||||
import { Create } from '../create/index'
|
||||
@@ -135,7 +135,7 @@ function FromConstructor(schema: TConstructor, references: TSchema[], value: any
|
||||
}
|
||||
function FromIntersect(schema: TIntersect, references: TSchema[], value: any): any {
|
||||
const created = Create(schema, references)
|
||||
const mapped = IsStandardObject(created) && IsStandardObject(value) ? { ...(created as any), ...value } : value
|
||||
const mapped = IsObject(created) && IsObject(value) ? { ...(created as any), ...value } : value
|
||||
return Check(schema, references, mapped) ? mapped : Create(schema, references)
|
||||
}
|
||||
function FromNever(schema: TNever, references: TSchema[], value: any): any {
|
||||
|
||||
@@ -47,6 +47,7 @@ import type { TUnion } from '../../type/union/index'
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
import {
|
||||
HasPropertyKey,
|
||||
IsString,
|
||||
IsObject,
|
||||
IsArray,
|
||||
@@ -57,13 +58,13 @@ import {
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
import {
|
||||
IsSchema
|
||||
} from '../../type/guard/type'
|
||||
IsKind
|
||||
} from '../../type/guard/kind'
|
||||
// ------------------------------------------------------------------
|
||||
// IsCheckable
|
||||
// ------------------------------------------------------------------
|
||||
function IsCheckable(schema: unknown): boolean {
|
||||
return IsSchema(schema) && schema[Kind] !== 'Unsafe'
|
||||
return IsKind(schema) && schema[Kind] !== 'Unsafe'
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// Types
|
||||
@@ -76,7 +77,7 @@ function FromIntersect(schema: TIntersect, references: TSchema[], value: unknown
|
||||
const unevaluatedProperties = schema.unevaluatedProperties as TSchema
|
||||
const intersections = schema.allOf.map((schema) => Visit(schema, references, Clone(value)))
|
||||
const composite = intersections.reduce((acc: any, value: any) => (IsObject(value) ? { ...acc, ...value } : value), {})
|
||||
if (!IsObject(value) || !IsObject(composite) || !IsSchema(unevaluatedProperties)) return composite
|
||||
if (!IsObject(value) || !IsObject(composite) || !IsKind(unevaluatedProperties)) return composite
|
||||
const knownkeys = KeyOfPropertyKeys(schema) as string[]
|
||||
for (const key of Object.getOwnPropertyNames(value)) {
|
||||
if (knownkeys.includes(key)) continue
|
||||
@@ -90,11 +91,11 @@ function FromObject(schema: TObject, references: TSchema[], value: unknown): any
|
||||
if (!IsObject(value) || IsArray(value)) return value // Check IsArray for AllowArrayObject configuration
|
||||
const additionalProperties = schema.additionalProperties as TSchema
|
||||
for (const key of Object.getOwnPropertyNames(value)) {
|
||||
if (key in schema.properties) {
|
||||
if (HasPropertyKey(schema.properties, key)) {
|
||||
value[key] = Visit(schema.properties[key], references, value[key])
|
||||
continue
|
||||
}
|
||||
if (IsSchema(additionalProperties) && Check(additionalProperties, references, value[key])) {
|
||||
if (IsKind(additionalProperties) && Check(additionalProperties, references, value[key])) {
|
||||
value[key] = Visit(additionalProperties, references, value[key])
|
||||
continue
|
||||
}
|
||||
@@ -113,7 +114,7 @@ function FromRecord(schema: TRecord, references: TSchema[], value: unknown): any
|
||||
value[key] = Visit(propertySchema, references, value[key])
|
||||
continue
|
||||
}
|
||||
if (IsSchema(additionalProperties) && Check(additionalProperties, references, value[key])) {
|
||||
if (IsKind(additionalProperties) && Check(additionalProperties, references, value[key])) {
|
||||
value[key] = Visit(additionalProperties, references, value[key])
|
||||
continue
|
||||
}
|
||||
|
||||
+20
-12
@@ -26,16 +26,16 @@ THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import type { ObjectType, ArrayType, TypedArrayType, ValueType } from '../guard/index'
|
||||
import type { ObjectType as FromObject, ArrayType as FromArray, TypedArrayType, ValueType } from '../guard/index'
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ValueGuard
|
||||
// ------------------------------------------------------------------
|
||||
import { IsArray, IsDate, IsStandardObject, IsTypedArray, IsValueType } from '../guard/index'
|
||||
import { IsArray, IsDate, IsMap, IsSet, IsObject, IsTypedArray, IsValueType } from '../guard/index'
|
||||
// ------------------------------------------------------------------
|
||||
// Clonable
|
||||
// ------------------------------------------------------------------
|
||||
function ObjectType(value: ObjectType): any {
|
||||
function FromObject(value: FromObject): any {
|
||||
const Acc = {} as Record<PropertyKey, unknown>
|
||||
for (const key of Object.getOwnPropertyNames(value)) {
|
||||
Acc[key] = Clone(value[key])
|
||||
@@ -45,16 +45,22 @@ function ObjectType(value: ObjectType): any {
|
||||
}
|
||||
return Acc
|
||||
}
|
||||
function ArrayType(value: ArrayType): any {
|
||||
function FromArray(value: FromArray): any {
|
||||
return value.map((element: any) => Clone(element))
|
||||
}
|
||||
function TypedArrayType(value: TypedArrayType): any {
|
||||
function FromTypedArray(value: TypedArrayType): any {
|
||||
return value.slice()
|
||||
}
|
||||
function DateType(value: Date): any {
|
||||
function FromMap(value: Map<unknown, unknown>): any {
|
||||
return new Map(Clone([...value.entries()]))
|
||||
}
|
||||
function FromSet(value: Set<unknown>): any {
|
||||
return new Set(Clone([...value.entries()]))
|
||||
}
|
||||
function FromDate(value: Date): any {
|
||||
return new Date(value.toISOString())
|
||||
}
|
||||
function ValueType(value: ValueType): any {
|
||||
function FromValue(value: ValueType): any {
|
||||
return value
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
@@ -62,10 +68,12 @@ function ValueType(value: ValueType): any {
|
||||
// ------------------------------------------------------------------
|
||||
/** Returns a clone of the given value */
|
||||
export function Clone<T extends unknown>(value: T): T {
|
||||
if (IsArray(value)) return ArrayType(value)
|
||||
if (IsDate(value)) return DateType(value)
|
||||
if (IsStandardObject(value)) return ObjectType(value)
|
||||
if (IsTypedArray(value)) return TypedArrayType(value)
|
||||
if (IsValueType(value)) return ValueType(value)
|
||||
if (IsArray(value)) return FromArray(value)
|
||||
if (IsDate(value)) return FromDate(value)
|
||||
if (IsTypedArray(value)) return FromTypedArray(value)
|
||||
if (IsMap(value)) return FromMap(value)
|
||||
if (IsSet(value)) return FromSet(value)
|
||||
if (IsObject(value)) return FromObject(value)
|
||||
if (IsValueType(value)) return FromValue(value)
|
||||
throw new Error('ValueClone: Unable to clone value')
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ function TryConvertLiteral(schema: TLiteral, value: unknown) {
|
||||
IsString(schema.const) ? TryConvertLiteralString(value, schema.const) :
|
||||
IsNumber(schema.const) ? TryConvertLiteralNumber(value, schema.const) :
|
||||
IsBoolean(schema.const) ? TryConvertLiteralBoolean(value, schema.const) :
|
||||
Clone(value)
|
||||
value
|
||||
)
|
||||
}
|
||||
function TryConvertBoolean(value: unknown) {
|
||||
@@ -156,7 +156,7 @@ function TryConvertDate(value: unknown) {
|
||||
// ------------------------------------------------------------------
|
||||
// Default
|
||||
// ------------------------------------------------------------------
|
||||
function Default(value: any) {
|
||||
function Default(value: unknown): unknown {
|
||||
return value
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
@@ -192,26 +192,21 @@ function FromNumber(schema: TNumber, references: TSchema[], value: any): unknown
|
||||
}
|
||||
// prettier-ignore
|
||||
function FromObject(schema: TObject, references: TSchema[], value: any): unknown {
|
||||
const isConvertable = IsObject(value)
|
||||
if(!isConvertable) return value
|
||||
const result: Record<PropertyKey, unknown> = {}
|
||||
for(const key of Object.keys(value)) {
|
||||
result[key] = HasPropertyKey(schema.properties, key)
|
||||
? Visit(schema.properties[key], references, value[key])
|
||||
: value[key]
|
||||
if(!IsObject(value)) return value
|
||||
for(const key of Object.getOwnPropertyNames(schema.properties)) {
|
||||
value[key] = Visit(schema.properties[key], references, value[key])
|
||||
}
|
||||
return result
|
||||
return value
|
||||
}
|
||||
function FromRecord(schema: TRecord, references: TSchema[], value: any): unknown {
|
||||
const isConvertable = IsObject(value)
|
||||
if (!isConvertable) return value
|
||||
const propertyKey = Object.getOwnPropertyNames(schema.patternProperties)[0]
|
||||
const property = schema.patternProperties[propertyKey]
|
||||
const result = {} as Record<string, unknown>
|
||||
for (const [propKey, propValue] of Object.entries(value)) {
|
||||
result[propKey] = Visit(property, references, propValue)
|
||||
value[propKey] = Visit(property, references, propValue)
|
||||
}
|
||||
return result
|
||||
return value
|
||||
}
|
||||
function FromRef(schema: TRef, references: TSchema[], value: any): unknown {
|
||||
return Visit(Deref(schema, references), references, value)
|
||||
@@ -233,21 +228,25 @@ function FromTuple(schema: TTuple, references: TSchema[], value: any): unknown {
|
||||
return (index < schema.items!.length)
|
||||
? Visit(schema.items![index], references, value)
|
||||
: value
|
||||
})
|
||||
})
|
||||
}
|
||||
function FromUndefined(schema: TUndefined, references: TSchema[], value: any): unknown {
|
||||
return TryConvertUndefined(value)
|
||||
}
|
||||
function FromUnion(schema: TUnion, references: TSchema[], value: any): unknown {
|
||||
for (const subschema of schema.anyOf) {
|
||||
const converted = Visit(subschema, references, value)
|
||||
const converted = Visit(subschema, references, Clone(value))
|
||||
if (!Check(subschema, references, converted)) continue
|
||||
return converted
|
||||
}
|
||||
return value
|
||||
}
|
||||
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
|
||||
references.push(schema)
|
||||
return references
|
||||
}
|
||||
function Visit(schema: TSchema, references: TSchema[], value: any): unknown {
|
||||
const references_ = IsString(schema.$id) ? [...references, schema] : references
|
||||
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
|
||||
const schema_ = schema as any
|
||||
switch (schema[Kind]) {
|
||||
case 'Array':
|
||||
@@ -293,14 +292,12 @@ function Visit(schema: TSchema, references: TSchema[], value: any): unknown {
|
||||
// ------------------------------------------------------------------
|
||||
// Convert
|
||||
// ------------------------------------------------------------------
|
||||
/** Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
/** `[Mutable]` Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
export function Convert(schema: TSchema, references: TSchema[], value: unknown): unknown
|
||||
/** Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
/** `[Mutable]` Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
export function Convert(schema: TSchema, value: unknown): unknown
|
||||
/** Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
/** `[Mutable]` Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
// prettier-ignore
|
||||
export function Convert(...args: any[]) {
|
||||
return args.length === 3
|
||||
? Visit(args[0], args[1], args[2])
|
||||
: Visit(args[0], [], args[1])
|
||||
return args.length === 3 ? Visit(args[0], args[1], args[2]) : Visit(args[0], [], args[1])
|
||||
}
|
||||
|
||||
@@ -389,8 +389,12 @@ function FromKind(schema: TSchema, references: TSchema[]): any {
|
||||
throw new Error('User defined types must specify a default value')
|
||||
}
|
||||
}
|
||||
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
|
||||
references.push(schema)
|
||||
return references
|
||||
}
|
||||
function Visit(schema: TSchema, references: TSchema[]): unknown {
|
||||
const references_ = IsString(schema.$id) ? [...references, schema] : references
|
||||
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
|
||||
const schema_ = schema as any
|
||||
switch (schema_[Kind]) {
|
||||
case 'Any':
|
||||
|
||||
@@ -48,7 +48,7 @@ import { IsString, IsObject, IsArray, IsUndefined } from '../guard/index'
|
||||
// ------------------------------------------------------------------
|
||||
// TypeGuard
|
||||
// ------------------------------------------------------------------
|
||||
import { IsSchema } from '../../type/guard/type'
|
||||
import { IsKind } from '../../type/guard/kind'
|
||||
// ------------------------------------------------------------------
|
||||
// ValueOrDefault
|
||||
// ------------------------------------------------------------------
|
||||
@@ -56,16 +56,10 @@ function ValueOrDefault(schema: TSchema, value: unknown) {
|
||||
return value === undefined && 'default' in schema ? Clone(schema.default) : value
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// IsCheckable
|
||||
// HasDefaultProperty
|
||||
// ------------------------------------------------------------------
|
||||
function IsCheckable(schema: unknown): boolean {
|
||||
return IsSchema(schema) && schema[Kind] !== 'Unsafe'
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// IsDefaultSchema
|
||||
// ------------------------------------------------------------------
|
||||
function IsDefaultSchema(value: unknown): value is TSchema {
|
||||
return IsSchema(value) && 'default' in value
|
||||
function HasDefaultProperty(schema: unknown): schema is TSchema {
|
||||
return IsKind(schema) && 'default' in schema
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// Types
|
||||
@@ -92,11 +86,11 @@ function FromObject(schema: TObject, references: TSchema[], value: unknown): any
|
||||
const knownPropertyKeys = Object.getOwnPropertyNames(schema.properties)
|
||||
// properties
|
||||
for (const key of knownPropertyKeys) {
|
||||
if (!IsDefaultSchema(schema.properties[key])) continue
|
||||
if (!HasDefaultProperty(schema.properties[key])) continue
|
||||
defaulted[key] = Visit(schema.properties[key], references, defaulted[key])
|
||||
}
|
||||
// return if not additional properties
|
||||
if (!IsDefaultSchema(additionalPropertiesSchema)) return defaulted
|
||||
if (!HasDefaultProperty(additionalPropertiesSchema)) return defaulted
|
||||
// additional properties
|
||||
for (const key of Object.getOwnPropertyNames(defaulted)) {
|
||||
if (knownPropertyKeys.includes(key)) continue
|
||||
@@ -112,11 +106,11 @@ function FromRecord(schema: TRecord, references: TSchema[], value: unknown): any
|
||||
const knownPropertyKey = new RegExp(propertyKeyPattern)
|
||||
// properties
|
||||
for (const key of Object.getOwnPropertyNames(defaulted)) {
|
||||
if (!(knownPropertyKey.test(key) && IsDefaultSchema(propertySchema))) continue
|
||||
if (!(knownPropertyKey.test(key) && HasDefaultProperty(propertySchema))) continue
|
||||
defaulted[key] = Visit(propertySchema, references, defaulted[key])
|
||||
}
|
||||
// return if not additional properties
|
||||
if (!IsDefaultSchema(additionalPropertiesSchema)) return defaulted
|
||||
if (!HasDefaultProperty(additionalPropertiesSchema)) return defaulted
|
||||
// additional properties
|
||||
for (const key of Object.getOwnPropertyNames(defaulted)) {
|
||||
if (knownPropertyKey.test(key)) continue
|
||||
@@ -143,14 +137,18 @@ function FromUnion(schema: TUnion, references: TSchema[], value: unknown): any {
|
||||
const defaulted = ValueOrDefault(schema, value)
|
||||
for (const inner of schema.anyOf) {
|
||||
const result = Visit(inner, references, defaulted)
|
||||
if (IsCheckable(inner) && Check(inner, result)) {
|
||||
if (Check(inner, result)) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return defaulted
|
||||
}
|
||||
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
|
||||
references.push(schema)
|
||||
return references
|
||||
}
|
||||
function Visit(schema: TSchema, references: TSchema[], value: unknown): any {
|
||||
const references_ = IsString(schema.$id) ? [...references, schema] : references
|
||||
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
|
||||
const schema_ = schema as any
|
||||
switch (schema_[Kind]) {
|
||||
case 'Array':
|
||||
|
||||
@@ -26,14 +26,14 @@ THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import { IsStandardObject, IsDate, IsArray, IsTypedArray, IsValueType } from '../guard/index'
|
||||
import { IsObject, IsDate, IsArray, IsTypedArray, IsValueType } from '../guard/index'
|
||||
import type { ObjectType, ArrayType, TypedArrayType, ValueType } from '../guard/index'
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Equality Checks
|
||||
// ------------------------------------------------------------------
|
||||
function ObjectType(left: ObjectType, right: unknown): boolean {
|
||||
if (!IsStandardObject(right)) return false
|
||||
if (!IsObject(right)) return false
|
||||
const leftKeys = [...Object.keys(left), ...Object.getOwnPropertySymbols(left)]
|
||||
const rightKeys = [...Object.keys(right), ...Object.getOwnPropertySymbols(right)]
|
||||
if (leftKeys.length !== rightKeys.length) return false
|
||||
@@ -58,10 +58,10 @@ function ValueType(left: ValueType, right: unknown): any {
|
||||
// ------------------------------------------------------------------
|
||||
/** Returns true if the left value deep-equals the right */
|
||||
export function Equal<T>(left: T, right: unknown): right is T {
|
||||
if (IsStandardObject(left)) return ObjectType(left, right)
|
||||
if (IsDate(left)) return DateType(left, right)
|
||||
if (IsTypedArray(left)) return TypedArrayType(left, right)
|
||||
if (IsArray(left)) return ArrayType(left, right)
|
||||
if (IsObject(left)) return ObjectType(left, right)
|
||||
if (IsValueType(left)) return ValueType(left, right)
|
||||
throw new Error('ValueEquals: Unable to compare value')
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import { IsArray, IsBoolean, IsBigInt, IsDate, IsNull, IsNumber, IsStandardObject, IsString, IsSymbol, IsUint8Array, IsUndefined } from '../guard/index'
|
||||
import { IsArray, IsBoolean, IsBigInt, IsDate, IsNull, IsNumber, IsObject, IsString, IsSymbol, IsUint8Array, IsUndefined } from '../guard/index'
|
||||
import { TypeBoxError } from '../../type/error/index'
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@@ -140,7 +140,7 @@ function Visit(value: any) {
|
||||
if (IsDate(value)) return DateType(value)
|
||||
if (IsNull(value)) return NullType(value)
|
||||
if (IsNumber(value)) return NumberType(value)
|
||||
if (IsStandardObject(value)) return ObjectType(value)
|
||||
if (IsObject(value)) return ObjectType(value)
|
||||
if (IsString(value)) return StringType(value)
|
||||
if (IsSymbol(value)) return SymbolType(value)
|
||||
if (IsUint8Array(value)) return Uint8ArrayType(value)
|
||||
|
||||
@@ -37,6 +37,7 @@ export * from './guard/index'
|
||||
// ------------------------------------------------------------------
|
||||
// Operators
|
||||
// ------------------------------------------------------------------
|
||||
export * from './assert/index'
|
||||
export * from './cast/index'
|
||||
export * from './check/index'
|
||||
export * from './clean/index'
|
||||
@@ -48,6 +49,7 @@ export * from './delta/index'
|
||||
export * from './equal/index'
|
||||
export * from './hash/index'
|
||||
export * from './mutate/index'
|
||||
export * from './parse/index'
|
||||
export * from './pointer/index'
|
||||
export * from './transform/index'
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@@ -26,7 +26,7 @@ THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import { IsStandardObject, IsArray, IsTypedArray, IsValueType, type TypedArrayType } from '../guard/index'
|
||||
import { IsObject, IsArray, IsTypedArray, IsValueType, type TypedArrayType } from '../guard/index'
|
||||
import { ValuePointer } from '../pointer/index'
|
||||
import { Clone } from '../clone/index'
|
||||
import { TypeBoxError } from '../../type/error/index'
|
||||
@@ -44,7 +44,7 @@ export class ValueMutateError extends TypeBoxError {
|
||||
// ------------------------------------------------------------------
|
||||
export type Mutable = { [key: string]: unknown } | unknown[]
|
||||
function ObjectType(root: Mutable, path: string, current: unknown, next: Record<string, unknown>) {
|
||||
if (!IsStandardObject(current)) {
|
||||
if (!IsObject(current)) {
|
||||
ValuePointer.Set(root, path, Clone(next))
|
||||
} else {
|
||||
const currentKeys = Object.getOwnPropertyNames(current)
|
||||
@@ -90,7 +90,7 @@ function ValueType(root: Mutable, path: string, current: unknown, next: unknown)
|
||||
function Visit(root: Mutable, path: string, current: unknown, next: unknown) {
|
||||
if (IsArray(next)) return ArrayType(root, path, current, next)
|
||||
if (IsTypedArray(next)) return TypedArrayType(root, path, current, next)
|
||||
if (IsStandardObject(next)) return ObjectType(root, path, current, next)
|
||||
if (IsObject(next)) return ObjectType(root, path, current, next)
|
||||
if (IsValueType(next)) return ValueType(root, path, current, next)
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
@@ -102,8 +102,8 @@ function IsNonMutableValue(value: unknown): value is Mutable {
|
||||
function IsMismatchedValue(current: unknown, next: unknown) {
|
||||
// prettier-ignore
|
||||
return (
|
||||
(IsStandardObject(current) && IsArray(next)) ||
|
||||
(IsArray(current) && IsStandardObject(next))
|
||||
(IsObject(current) && IsArray(next)) ||
|
||||
(IsArray(current) && IsObject(next))
|
||||
)
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
@sinclair/typebox/value
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
export * from './parse'
|
||||
@@ -0,0 +1,68 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
@sinclair/typebox/value
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <haydn.developer@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import { TransformDecode, HasTransform } from '../transform/index'
|
||||
import { TSchema } from '../../type/schema/index'
|
||||
import { StaticDecode } from '../../type/static/index'
|
||||
import { Assert } from '../assert/assert'
|
||||
import { Default } from '../default/default'
|
||||
import { Convert } from '../convert/convert'
|
||||
import { Clean } from '../clean/clean'
|
||||
import { Clone } from '../clone/index'
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ParseReducer
|
||||
// ------------------------------------------------------------------
|
||||
type ReducerFunction = (schema: TSchema, references: TSchema[], value: unknown) => unknown
|
||||
|
||||
// prettier-ignore
|
||||
const ParseReducer: ReducerFunction[] = [
|
||||
(_schema, _references, value) => Clone(value),
|
||||
(schema, references, value) => Default(schema, references, value),
|
||||
(schema, references, value) => Clean(schema, references, value),
|
||||
(schema, references, value) => Convert(schema, references, value),
|
||||
(schema, references, value) => { Assert(schema, references, value); return value },
|
||||
(schema, references, value) => (HasTransform(schema, references) ? TransformDecode(schema, references, value) : value),
|
||||
]
|
||||
// ------------------------------------------------------------------
|
||||
// ParseValue
|
||||
// ------------------------------------------------------------------
|
||||
function ParseValue<T extends TSchema, R = StaticDecode<T>>(schema: T, references: TSchema[], value: unknown): R {
|
||||
return ParseReducer.reduce((value, reducer) => reducer(schema, references, value), value) as R
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// Parse
|
||||
// ------------------------------------------------------------------
|
||||
/** Parses a value or throws an `AssertError` if invalid. */
|
||||
export function Parse<T extends TSchema, R = StaticDecode<T>>(schema: T, references: TSchema[], value: unknown): R
|
||||
/** Parses a value or throws an `AssertError` if invalid. */
|
||||
export function Parse<T extends TSchema, R = StaticDecode<T>>(schema: T, value: unknown): R
|
||||
/** Parses a value or throws an `AssertError` if invalid. */
|
||||
export function Parse(...args: any[]): unknown {
|
||||
return args.length === 3 ? ParseValue(args[0], args[1], args[2]) : ParseValue(args[0], [], args[1])
|
||||
}
|
||||
@@ -48,7 +48,7 @@ import type { TUnion } from '../../type/union/index'
|
||||
// ------------------------------------------------------------------
|
||||
// ValueGuard
|
||||
// ------------------------------------------------------------------
|
||||
import { IsStandardObject, IsArray, IsValueType } from '../guard/index'
|
||||
import { IsObject, IsArray, IsValueType } from '../guard/index'
|
||||
// ------------------------------------------------------------------
|
||||
// TypeGuard
|
||||
// ------------------------------------------------------------------
|
||||
@@ -97,7 +97,7 @@ function FromArray(schema: TArray, references: TSchema[], path: string, value: a
|
||||
}
|
||||
// prettier-ignore
|
||||
function FromIntersect(schema: TIntersect, references: TSchema[], path: string, value: any) {
|
||||
if (!IsStandardObject(value) || IsValueType(value)) return Default(schema, path, value)
|
||||
if (!IsObject(value) || IsValueType(value)) return Default(schema, path, value)
|
||||
const knownEntries = KeyOfPropertyEntries(schema)
|
||||
const knownKeys = knownEntries.map(entry => entry[0])
|
||||
const knownProperties = { ...value } as Record<PropertyKey, unknown>
|
||||
@@ -120,7 +120,7 @@ function FromNot(schema: TNot, references: TSchema[], path: string, value: any)
|
||||
}
|
||||
// prettier-ignore
|
||||
function FromObject(schema: TObject, references: TSchema[], path: string, value: any) {
|
||||
if (!IsStandardObject(value)) return Default(schema, path, value)
|
||||
if (!IsObject(value)) return Default(schema, path, value)
|
||||
const knownKeys = KeyOfPropertyKeys(schema)
|
||||
const knownProperties = { ...value } as Record<PropertyKey, unknown>
|
||||
for(const key of knownKeys) if(key in knownProperties) {
|
||||
@@ -139,7 +139,7 @@ function FromObject(schema: TObject, references: TSchema[], path: string, value:
|
||||
}
|
||||
// prettier-ignore
|
||||
function FromRecord(schema: TRecord, references: TSchema[], path: string, value: any) {
|
||||
if (!IsStandardObject(value)) return Default(schema, path, value)
|
||||
if (!IsObject(value)) return Default(schema, path, value)
|
||||
const pattern = Object.getOwnPropertyNames(schema.patternProperties)[0]
|
||||
const knownKeys = new RegExp(pattern)
|
||||
const knownProperties = { ...value } as Record<PropertyKey, unknown>
|
||||
@@ -183,9 +183,13 @@ function FromUnion(schema: TUnion, references: TSchema[], path: string, value: a
|
||||
}
|
||||
return Default(schema, path, value)
|
||||
}
|
||||
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
|
||||
references.push(schema)
|
||||
return references
|
||||
}
|
||||
// prettier-ignore
|
||||
function Visit(schema: TSchema, references: TSchema[], path: string, value: any): any {
|
||||
const references_ = typeof schema.$id === 'string' ? [...references, schema] : references
|
||||
const references_ = typeof schema.$id === 'string' ? AddReference(references, schema) : references
|
||||
const schema_ = schema as any
|
||||
switch (schema[Kind]) {
|
||||
case 'Array':
|
||||
|
||||
@@ -48,7 +48,7 @@ import type { TUnion } from '../../type/union/index'
|
||||
// ------------------------------------------------------------------
|
||||
// ValueGuard
|
||||
// ------------------------------------------------------------------
|
||||
import { IsStandardObject, IsArray, IsValueType } from '../guard/index'
|
||||
import { IsObject, IsArray, IsValueType } from '../guard/index'
|
||||
// ------------------------------------------------------------------
|
||||
// TypeGuard
|
||||
// ------------------------------------------------------------------
|
||||
@@ -98,7 +98,7 @@ function FromArray(schema: TArray, references: TSchema[], path: string, value: a
|
||||
// prettier-ignore
|
||||
function FromIntersect(schema: TIntersect, references: TSchema[], path: string, value: any) {
|
||||
const defaulted = Default(schema, path, value)
|
||||
if (!IsStandardObject(value) || IsValueType(value)) return defaulted
|
||||
if (!IsObject(value) || IsValueType(value)) return defaulted
|
||||
const knownEntries = KeyOfPropertyEntries(schema)
|
||||
const knownKeys = knownEntries.map(entry => entry[0])
|
||||
const knownProperties = { ...defaulted } as Record<PropertyKey, unknown>
|
||||
@@ -123,7 +123,7 @@ function FromNot(schema: TNot, references: TSchema[], path: string, value: any)
|
||||
// prettier-ignore
|
||||
function FromObject(schema: TObject, references: TSchema[], path: string, value: any) {
|
||||
const defaulted = Default(schema, path, value)
|
||||
if (!IsStandardObject(defaulted)) return defaulted
|
||||
if (!IsObject(defaulted)) return defaulted
|
||||
const knownKeys = KeyOfPropertyKeys(schema) as string[]
|
||||
const knownProperties = { ...defaulted } as Record<PropertyKey, unknown>
|
||||
for(const key of knownKeys) if(key in knownProperties) {
|
||||
@@ -143,7 +143,7 @@ function FromObject(schema: TObject, references: TSchema[], path: string, value:
|
||||
// prettier-ignore
|
||||
function FromRecord(schema: TRecord, references: TSchema[], path: string, value: any) {
|
||||
const defaulted = Default(schema, path, value) as Record<PropertyKey, unknown>
|
||||
if (!IsStandardObject(value)) return defaulted
|
||||
if (!IsObject(value)) return defaulted
|
||||
const pattern = Object.getOwnPropertyNames(schema.patternProperties)[0]
|
||||
const knownKeys = new RegExp(pattern)
|
||||
const knownProperties = {...defaulted } as Record<PropertyKey, unknown>
|
||||
@@ -151,7 +151,7 @@ function FromRecord(schema: TRecord, references: TSchema[], path: string, value:
|
||||
knownProperties[key] = Visit(schema.patternProperties[pattern], references, `${path}/${key}`, knownProperties[key])
|
||||
}
|
||||
if (!IsSchema(schema.additionalProperties)) {
|
||||
return Default(schema, path, knownProperties)
|
||||
return knownProperties
|
||||
}
|
||||
const unknownKeys = Object.getOwnPropertyNames(knownProperties)
|
||||
const additionalProperties = schema.additionalProperties as TSchema
|
||||
@@ -194,9 +194,13 @@ function FromUnion(schema: TUnion, references: TSchema[], path: string, value: a
|
||||
}
|
||||
return Default(schema, path, value)
|
||||
}
|
||||
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
|
||||
references.push(schema)
|
||||
return references
|
||||
}
|
||||
// prettier-ignore
|
||||
function Visit(schema: TSchema, references: TSchema[], path: string, value: any): any {
|
||||
const references_ = typeof schema.$id === 'string' ? [...references, schema] : references
|
||||
const references_ = typeof schema.$id === 'string' ? AddReference(references, schema) : references
|
||||
const schema_ = schema as any
|
||||
switch (schema[Kind]) {
|
||||
case 'Array':
|
||||
|
||||
@@ -120,9 +120,13 @@ function FromTuple(schema: TTuple, references: TSchema[]) {
|
||||
function FromUnion(schema: TUnion, references: TSchema[]) {
|
||||
return IsTransform(schema) || schema.anyOf.some((schema) => Visit(schema, references))
|
||||
}
|
||||
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
|
||||
references.push(schema)
|
||||
return references
|
||||
}
|
||||
// prettier-ignore
|
||||
function Visit(schema: TSchema, references: TSchema[]): boolean {
|
||||
const references_ = IsString(schema.$id) ? [...references, schema] : references
|
||||
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
|
||||
const schema_ = schema as any
|
||||
if (schema.$id && visited.has(schema.$id)) return false
|
||||
if (schema.$id) visited.add(schema.$id)
|
||||
|
||||
+30
-12
@@ -27,6 +27,7 @@ THE SOFTWARE.
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import { HasTransform, TransformDecode, TransformEncode, TransformDecodeCheckError, TransformEncodeCheckError } from '../transform/index'
|
||||
import { Assert as AssertValue } from '../assert/index'
|
||||
import { Mutate as MutateValue, type Mutable } from '../mutate/index'
|
||||
import { Hash as HashValue } from '../hash/index'
|
||||
import { Equal as EqualValue } from '../equal/index'
|
||||
@@ -36,6 +37,7 @@ import { Convert as ConvertValue } from '../convert/index'
|
||||
import { Create as CreateValue } from '../create/index'
|
||||
import { Clean as CleanValue } from '../clean/index'
|
||||
import { Check as CheckValue } from '../check/index'
|
||||
import { Parse as ParseValue } from '../parse/index'
|
||||
import { Default as DefaultValue } from '../default/index'
|
||||
import { Diff as DiffValue, Patch as PatchValue, Edit } from '../delta/index'
|
||||
import { Errors as ValueErrors, ValueErrorIterator } from '../../errors/index'
|
||||
@@ -43,12 +45,20 @@ import { Errors as ValueErrors, ValueErrorIterator } from '../../errors/index'
|
||||
import type { TSchema } from '../../type/schema/index'
|
||||
import type { Static, StaticDecode, StaticEncode } from '../../type/static/index'
|
||||
|
||||
/** Asserts a value matches the given type or throws an `AssertError` if invalid. */
|
||||
export function Assert<T extends TSchema, R = Static<T>>(schema: T, references: TSchema[], value: unknown): asserts value is R
|
||||
/** Asserts a value matches the given type or throws an `AssertError` if invalid. */
|
||||
export function Assert<T extends TSchema, R = Static<T>>(schema: T, value: unknown): asserts value is R
|
||||
/** Asserts a value matches the given type or throws an `AssertError` if invalid. */
|
||||
export function Assert(...args: any[]): any {
|
||||
return AssertValue.apply(AssertValue, args as any)
|
||||
}
|
||||
/** Casts a value into a given type. The return value will retain as much information of the original value as possible. */
|
||||
export function Cast<T extends TSchema>(schema: T, references: TSchema[], value: unknown): Static<T>
|
||||
/** Casts a value into a given type. The return value will retain as much information of the original value as possible. */
|
||||
export function Cast<T extends TSchema>(schema: T, value: unknown): Static<T>
|
||||
/** Casts a value into a given type. The return value will retain as much information of the original value as possible. */
|
||||
export function Cast(...args: any[]) {
|
||||
export function Cast(...args: any[]): any {
|
||||
return CastValue.apply(CastValue, args as any)
|
||||
}
|
||||
/** Creates a value from the given type and references */
|
||||
@@ -56,7 +66,7 @@ export function Create<T extends TSchema>(schema: T, references: TSchema[]): Sta
|
||||
/** Creates a value from the given type */
|
||||
export function Create<T extends TSchema>(schema: T): Static<T>
|
||||
/** Creates a value from the given type */
|
||||
export function Create(...args: any[]) {
|
||||
export function Create(...args: any[]): any {
|
||||
return CreateValue.apply(CreateValue, args as any)
|
||||
}
|
||||
/** Returns true if the value matches the given type and references */
|
||||
@@ -64,7 +74,7 @@ export function Check<T extends TSchema>(schema: T, references: TSchema[], value
|
||||
/** Returns true if the value matches the given type */
|
||||
export function Check<T extends TSchema>(schema: T, value: unknown): value is Static<T>
|
||||
/** Returns true if the value matches the given type */
|
||||
export function Check(...args: any[]) {
|
||||
export function Check(...args: any[]): any {
|
||||
return CheckValue.apply(CheckValue, args as any)
|
||||
}
|
||||
/** `[Mutable]` Removes excess properties from a value and returns the result. This function does not check the value and returns an unknown type. You should Check the result before use. Clean is a mutable operation. To avoid mutation, Clone the value first. */
|
||||
@@ -72,15 +82,15 @@ export function Clean(schema: TSchema, references: TSchema[], value: unknown): u
|
||||
/** `[Mutable]` Removes excess properties from a value and returns the result. This function does not check the value and returns an unknown type. You should Check the result before use. Clean is a mutable operation. To avoid mutation, Clone the value first. */
|
||||
export function Clean(schema: TSchema, value: unknown): unknown
|
||||
/** `[Mutable]` Removes excess properties from a value and returns the result. This function does not check the value and returns an unknown type. You should Check the result before use. Clean is a mutable operation. To avoid mutation, Clone the value first. */
|
||||
export function Clean(...args: any[]) {
|
||||
export function Clean(...args: any[]): any {
|
||||
return CleanValue.apply(CleanValue, args as any)
|
||||
}
|
||||
/** Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
/** `[Mutable]` Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
export function Convert(schema: TSchema, references: TSchema[], value: unknown): unknown
|
||||
/** Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
/** `[Mutable]` Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
export function Convert(schema: TSchema, value: unknown): unknown
|
||||
/** Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
export function Convert(...args: any[]) {
|
||||
/** `[Mutable]` Converts any type mismatched values to their target type if a reasonable conversion is possible. */
|
||||
export function Convert(...args: any[]): any {
|
||||
return ConvertValue.apply(ConvertValue, args as any)
|
||||
}
|
||||
/** Returns a structural clone of the given value */
|
||||
@@ -92,7 +102,7 @@ export function Decode<T extends TSchema, R = StaticDecode<T>>(schema: T, refere
|
||||
/** Decodes a value or throws if error */
|
||||
export function Decode<T extends TSchema, R = StaticDecode<T>>(schema: T, value: unknown): R
|
||||
/** Decodes a value or throws if error */
|
||||
export function Decode(...args: any[]) {
|
||||
export function Decode(...args: any[]): any {
|
||||
const [schema, references, value] = args.length === 3 ? [args[0], args[1], args[2]] : [args[0], [], args[1]]
|
||||
if (!Check(schema, references, value)) throw new TransformDecodeCheckError(schema, value, Errors(schema, references, value).First()!)
|
||||
return HasTransform(schema, references) ? TransformDecode(schema, references, value) : value
|
||||
@@ -102,7 +112,7 @@ export function Default(schema: TSchema, references: TSchema[], value: unknown):
|
||||
/** `[Mutable]` Generates missing properties on a value using default schema annotations if available. This function does not check the value and returns an unknown type. You should Check the result before use. Default is a mutable operation. To avoid mutation, Clone the value first. */
|
||||
export function Default(schema: TSchema, value: unknown): unknown
|
||||
/** `[Mutable]` Generates missing properties on a value using default schema annotations if available. This function does not check the value and returns an unknown type. You should Check the result before use. Default is a mutable operation. To avoid mutation, Clone the value first. */
|
||||
export function Default(...args: any[]) {
|
||||
export function Default(...args: any[]): any {
|
||||
return DefaultValue.apply(DefaultValue, args as any)
|
||||
}
|
||||
/** Encodes a value or throws if error */
|
||||
@@ -110,18 +120,26 @@ export function Encode<T extends TSchema, R = StaticEncode<T>>(schema: T, refere
|
||||
/** Encodes a value or throws if error */
|
||||
export function Encode<T extends TSchema, R = StaticEncode<T>>(schema: T, value: unknown): R
|
||||
/** Encodes a value or throws if error */
|
||||
export function Encode(...args: any[]) {
|
||||
export function Encode(...args: any[]): any {
|
||||
const [schema, references, value] = args.length === 3 ? [args[0], args[1], args[2]] : [args[0], [], args[1]]
|
||||
const encoded = HasTransform(schema, references) ? TransformEncode(schema, references, value) : value
|
||||
if (!Check(schema, references, encoded)) throw new TransformEncodeCheckError(schema, encoded, Errors(schema, references, encoded).First()!)
|
||||
return encoded
|
||||
}
|
||||
/** Parses a value or throws an `AssertError` if invalid. */
|
||||
export function Parse<T extends TSchema, R = StaticDecode<T>>(schema: T, references: TSchema[], value: unknown): R
|
||||
/** Parses a value or throws an `AssertError` if invalid. */
|
||||
export function Parse<T extends TSchema, R = StaticDecode<T>>(schema: T, value: unknown): R
|
||||
/** Parses a value or throws an `AssertError` if invalid. */
|
||||
export function Parse(...args: any[]): unknown {
|
||||
return ParseValue.apply(ParseValue, args as any)
|
||||
}
|
||||
/** Returns an iterator for each error in this value. */
|
||||
export function Errors<T extends TSchema>(schema: T, references: TSchema[], value: unknown): ValueErrorIterator
|
||||
/** Returns an iterator for each error in this value. */
|
||||
export function Errors<T extends TSchema>(schema: T, value: unknown): ValueErrorIterator
|
||||
/** Returns an iterator for each error in this value. */
|
||||
export function Errors(...args: any[]) {
|
||||
export function Errors(...args: any[]): any {
|
||||
return ValueErrors.apply(ValueErrors, args as any)
|
||||
}
|
||||
/** Returns true if left and right values are structurally equal */
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Value, AssertError } from '@sinclair/typebox/value'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
import { Assert } from '../../assert/index'
|
||||
|
||||
describe('value/Assert', () => {
|
||||
it('Should Assert', () => {
|
||||
Assert.Throws(() => Value.Assert(Type.String(), 1))
|
||||
})
|
||||
it('Should throw AssertError', () => {
|
||||
try {
|
||||
Value.Assert(Type.String(), 1)
|
||||
} catch (error) {
|
||||
if (error instanceof AssertError) {
|
||||
return
|
||||
}
|
||||
throw error
|
||||
}
|
||||
})
|
||||
it('Should throw AssertError and produce Iterator', () => {
|
||||
try {
|
||||
Value.Assert(Type.String(), 1)
|
||||
} catch (error) {
|
||||
if (error instanceof AssertError) {
|
||||
const first = error.Errors().First()
|
||||
Assert.HasProperty(first, 'type')
|
||||
Assert.HasProperty(first, 'schema')
|
||||
Assert.HasProperty(first, 'path')
|
||||
Assert.HasProperty(first, 'value')
|
||||
Assert.HasProperty(first, 'message')
|
||||
return
|
||||
}
|
||||
throw error
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
import './assert'
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Value } from '@sinclair/typebox/value'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
import { Type, Kind, TypeRegistry } from '@sinclair/typebox'
|
||||
import { Assert } from '../../assert/index'
|
||||
|
||||
describe('value/default/Union', () => {
|
||||
@@ -86,25 +86,29 @@ describe('value/default/Union', () => {
|
||||
// Interior Unsafe
|
||||
// ----------------------------------------------------------------
|
||||
it('Should default interior unsafe 1', () => {
|
||||
TypeRegistry.Set('DefaultUnsafe', (schema, value) => typeof value === 'string')
|
||||
const T = Type.Union([
|
||||
Type.Object({
|
||||
x: Type.Number({ default: 1 }),
|
||||
y: Type.Number({ default: 2 }),
|
||||
}),
|
||||
Type.Unsafe({ default: 'hello' }),
|
||||
Type.Unsafe({ [Kind]: 'DefaultUnsafe', default: 'hello' }),
|
||||
])
|
||||
const R = Value.Default(T, undefined)
|
||||
Assert.IsEqual(R, undefined)
|
||||
Assert.IsEqual(R, 'hello')
|
||||
TypeRegistry.Delete('DefaultUnsafe')
|
||||
})
|
||||
it('Should default interior unsafe 2', () => {
|
||||
TypeRegistry.Set('DefaultUnsafe', (schema, value) => typeof value === 'string')
|
||||
const T = Type.Union([
|
||||
Type.Object({
|
||||
x: Type.Number({ default: 1 }),
|
||||
y: Type.Number({ default: 2 }),
|
||||
}),
|
||||
Type.Unsafe({ default: 'hello' }),
|
||||
Type.Unsafe({ [Kind]: 'DefaultUnsafe', default: 'hello' }),
|
||||
])
|
||||
const R = Value.Default(T, 'world')
|
||||
Assert.IsEqual(R, 'world')
|
||||
TypeRegistry.Delete('DefaultUnsafe')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import './assert'
|
||||
import './cast'
|
||||
import './check'
|
||||
import './clean'
|
||||
@@ -10,5 +11,6 @@ import './equal'
|
||||
import './guard'
|
||||
import './hash'
|
||||
import './mutate'
|
||||
import './parse'
|
||||
import './pointer'
|
||||
import './transform'
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import './parse'
|
||||
@@ -0,0 +1,90 @@
|
||||
import { Value, AssertError } from '@sinclair/typebox/value'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
import { Assert } from '../../assert/index'
|
||||
|
||||
// prettier-ignore
|
||||
describe('value/Parse', () => {
|
||||
it('Should Parse', () => {
|
||||
const A = Value.Parse(Type.Literal('hello'), 'hello')
|
||||
Assert.IsEqual(A, 'hello')
|
||||
})
|
||||
it('Should not Parse', () => {
|
||||
Assert.Throws(() => Value.Parse(Type.Literal('hello'), 'world'))
|
||||
})
|
||||
it('Should throw AssertError', () => {
|
||||
try {
|
||||
Value.Parse(Type.Literal('hello'), 'world')
|
||||
} catch(error) {
|
||||
if(error instanceof AssertError) {
|
||||
return
|
||||
}
|
||||
throw error
|
||||
}
|
||||
})
|
||||
it('Should throw AssertError and produce Iterator', () => {
|
||||
try {
|
||||
Value.Parse(Type.Literal('hello'), 'world')
|
||||
} catch(error) {
|
||||
if(error instanceof AssertError) {
|
||||
const first = error.Errors().First()
|
||||
Assert.HasProperty(first, 'type')
|
||||
Assert.HasProperty(first, 'schema')
|
||||
Assert.HasProperty(first, 'path')
|
||||
Assert.HasProperty(first, 'value')
|
||||
Assert.HasProperty(first, 'message')
|
||||
return
|
||||
}
|
||||
throw error
|
||||
}
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Default
|
||||
// ----------------------------------------------------------------
|
||||
it('Should use Default values', () => {
|
||||
const X = Value.Parse(Type.Object({
|
||||
x: Type.Number({ default: 1 }),
|
||||
y: Type.Number({ default: 2 })
|
||||
}), { })
|
||||
Assert.IsEqual(X, { x: 1, y: 2 })
|
||||
})
|
||||
it('Should throw on invalid Default values', () => {
|
||||
Assert.Throws(() => Value.Parse(Type.Object({
|
||||
x: Type.Number({ default: null }),
|
||||
y: Type.Number({ default: null })
|
||||
}), { }))
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Convert
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Convert value 1', () => {
|
||||
const X = Value.Parse(Type.Object({
|
||||
x: Type.Number(),
|
||||
y: Type.Number()
|
||||
}), { x: '1', y: '2' })
|
||||
Assert.IsEqual(X, { x: 1, y: 2 })
|
||||
})
|
||||
it('Should Convert value 2', () => {
|
||||
const X = Value.Parse(Type.Array(Type.String()), [1, 2, 3, 4])
|
||||
Assert.IsEqual(X, ['1', '2', '3', '4'])
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Clean
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Clean value', () => {
|
||||
const X = Value.Parse(Type.Object({
|
||||
x: Type.Number(),
|
||||
y: Type.Number()
|
||||
}), { x: 1, y: 2, z: 3 })
|
||||
Assert.IsEqual(X, { x: 1, y: 2 })
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Decode
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Decode value', () => {
|
||||
const T = Type.Transform(Type.String())
|
||||
.Decode(value => 'hello')
|
||||
.Encode(value => value)
|
||||
const X = Value.Parse(T, 'world')
|
||||
Assert.IsEqual(X, 'hello')
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as Encoder from './_encoder'
|
||||
import { Assert } from '../../assert'
|
||||
import { Value } from '@sinclair/typebox/value'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
|
||||
describe('value/transform/Record', () => {
|
||||
|
||||
Reference in New Issue
Block a user