This commit is contained in:
sinclair
2025-12-24 15:44:34 +09:00
commit 13d553220c
1047 changed files with 80931 additions and 0 deletions

View File

@@ -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
}
})
})

View File

@@ -0,0 +1 @@
import './assert'

View File

@@ -0,0 +1,52 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Any', () => {
const T = Type.Any()
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from boolean', () => {
const value = false
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result.getTime(100), 100)
})
it('Should preserve', () => {
const value = { a: 1, b: 2 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { a: 1, b: 2 })
})
})

View File

@@ -0,0 +1,118 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Array', () => {
const T = Type.Array(Type.Number(), { default: [1, 2, 3] })
const E = [1, 2, 3]
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [1])
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = [6, 7, 8]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [6, 7, 8])
})
it('Should preserve with invalid element set to default', () => {
const value = [6, 7, 8, 'hello', 9]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [6, 7, 8, 0, 9])
})
// -----------------------------------------------------------------
// Constraints: Ranges
// -----------------------------------------------------------------
it('Should cast array and truncate to maxItems from value', () => {
const result = Value.Cast(Type.Array(Type.Number(), { maxItems: 3 }), [0, 1, 2, 4, 5, 6])
Assert.IsEqual(result, [0, 1, 2])
})
it('Should cast arrays and append array to minItems from value', () => {
const result = Value.Cast(Type.Array(Type.Number(), { minItems: 6 }), [0, 1, 2])
Assert.IsEqual(result, [0, 1, 2, 0, 0, 0])
})
it('Should cast array and truncate to maxItems from default value', () => {
const result = Value.Cast(Type.Array(Type.Number(), { maxItems: 3, default: [0, 1, 2, 4, 5, 6] }), null)
Assert.IsEqual(result, [0, 1, 2])
})
it('Should cast arrays and append array to minItems from default value', () => {
const result = Value.Cast(Type.Array(Type.Number({ default: 1 }), { minItems: 6, default: [0, 1, 2] }), null)
Assert.IsEqual(result, [0, 1, 2, 1, 1, 1])
})
// -----------------------------------------------------------------
// Constraints: Unique
// -----------------------------------------------------------------
it('Should cast arrays with uniqueItems with unique default value', () => {
const result = Value.Cast(Type.Array(Type.Number(), { uniqueItems: true, default: [0, 1, 2] }), null)
Assert.IsEqual(result, [0, 1, 2])
})
it('Should cast arrays with uniqueItems with unique value', () => {
const result = Value.Cast(Type.Array(Type.Number(), { uniqueItems: true }), [0, 1, 2])
Assert.IsEqual(result, [0, 1, 2])
})
it('Should throw when casting arrays with uniqueItems and no value or default value', () => {
Assert.Throws(() => Value.Cast(Type.Array(Type.Number(), { uniqueItems: true }), null))
})
it('Should throw when casting arrays with uniqueItems and not enough values to populate set', () => {
Assert.Throws(() => Value.Cast(Type.Array(Type.Number(), { minItems: 3, uniqueItems: true }), [0, 1]))
})
it('Should throw when casting arrays with uniqueItems and not enough default values to populate set', () => {
Assert.Throws(() => Value.Cast(Type.Array(Type.Number(), { minItems: 3, uniqueItems: true, default: [0, 1] }), null))
})
// -----------------------------------------------------------------
// Suggestion: https://github.com/sinclairzx81/typebox/issues/239
// -----------------------------------------------------------------
it('Should remove duplicates if uniqueItems is true', () => {
const T = Type.Array(Type.Number(), { uniqueItems: true })
const value = [1, 1, 2, 2]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [1, 2])
})
it('Should should fill up with defaults to minItems', () => {
const T = Type.Array(Type.Number(), { minItems: 3 })
const value = [1, 2]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [1, 2, 0])
})
it('Should should truncate to maxItems', () => {
const T = Type.Array(Type.Number(), { maxItems: 3 })
const value = [1, 2, 3, 4]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [1, 2, 3])
})
})

View File

@@ -0,0 +1,37 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/AsyncIterator', () => {
const T = Type.AsyncIterator(Type.Any())
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.asyncIterator in result)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.asyncIterator in result)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.asyncIterator in result)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.asyncIterator in result)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.asyncIterator in result)
})
it('Should preseve', () => {
const value = (async function* () {})()
const result = Value.Cast(T, value)
Assert.IsTrue(value === result)
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/BigInt', () => {
const T = Type.BigInt()
const E = BigInt(0)
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 0
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = BigInt(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, BigInt(100))
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Boolean', () => {
const T = Type.Boolean()
const E = false
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 0
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, true)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, true)
})
})

View File

@@ -0,0 +1,89 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Composite', () => {
const A = Type.Object({
x: Type.Number({ default: 0 }),
y: Type.Number({ default: 1 }),
z: Type.Number({ default: 2 }),
})
const B = Type.Object({
a: Type.Number({ default: 'a' }),
b: Type.Number({ default: 'b' }),
c: Type.Number({ default: 'c' }),
})
const T = Type.Composite([A, B])
const E = {
x: 0,
y: 1,
z: 2,
a: 'a',
b: 'b',
c: 'c',
}
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = E
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast and preserve object', () => {
const value = { x: 7, y: 8, z: 9 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, {
x: 7,
y: 8,
z: 9,
a: 'a',
b: 'b',
c: 'c',
})
})
it('Should upcast and preserve from incorrect properties', () => {
const value = { x: {}, y: 8, z: 9 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, {
x: 0,
y: 8,
z: 9,
a: 'a',
b: 'b',
c: 'c',
})
})
})

View File

@@ -0,0 +1,38 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Date', () => {
const T = Type.Date()
const E = new Date(0)
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.InRange(result.getTime(), new Date().getTime(), 1000)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.InRange(result.getTime(), new Date().getTime(), 1000)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.InRange(result.getTime(), new Date().getTime(), 1000)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.InRange(result.getTime(), new Date().getTime(), 1000)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.InRange(result.getTime(), new Date().getTime(), 1000)
})
it('Should preseve', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result.getTime(), 100)
})
})

View File

@@ -0,0 +1,62 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Boolean', () => {
enum Foo {
A,
B,
}
const T = Type.Enum(Foo)
const E = Foo.A
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 123
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from enum A', () => {
const value = Foo.A
const result = Value.Cast(T, value)
Assert.IsEqual(result, Foo.A)
})
it('Should upcast from enum B', () => {
const value = Foo.B
const result = Value.Cast(T, value)
Assert.IsEqual(result, Foo.B)
})
})

View File

@@ -0,0 +1,51 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Import', () => {
const T = Type.Module({
A: Type.Number(),
}).Import('A')
const E = 0
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, 1)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preseve', () => {
const value = 123
const result = Value.Cast(T, value)
Assert.IsEqual(result, 123)
})
})

View File

@@ -0,0 +1,32 @@
import './any'
import './array'
import './async-iterator'
import './bigint'
import './boolean'
import './composite'
import './date'
import './enum'
import './import'
import './integer'
import './intersect'
import './iterator'
import './keyof'
import './kind'
import './literal'
import './never'
import './not'
import './null'
import './number'
import './object'
import './recursive'
import './record'
import './regexp'
import './string'
import './symbol'
import './template-literal'
import './tuple'
import './uint8array'
import './undefined'
import './union'
import './unknown'
import './void'

View File

@@ -0,0 +1,43 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Integer', () => {
const T = Type.Integer()
const E = 0
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, 1)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
})

View File

@@ -0,0 +1,112 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Intersect', () => {
it('Should cast from an invalid object', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const V = Value.Cast(T, 1)
Assert.IsEqual(V, { x: 0, y: 0 })
})
it('Should cast from an partial object and preserve', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const V = Value.Cast(T, { x: 1 })
Assert.IsEqual(V, { x: 1, y: 0 })
})
it('Should cast and use default values', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number({ default: 42 }) })
])
const V = Value.Cast(T, { x: 1 })
Assert.IsEqual(V, { x: 1, y: 42 })
})
it('Should throw with an illogical intersect', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ x: Type.String() })
])
Assert.Throws(() => Value.Cast(T, { x: 1 }))
})
it('Should throw with an illogical intersect (primative)', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Number(),
Type.String()
])
Assert.Throws(() => Value.Cast(T, { x: 1 }))
})
it('Should use last intersected default for equivalent sub schemas', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ x: Type.Number({ default: 1000 }) })
])
const V = Value.Cast(T, null)
Assert.IsEqual(V, { x: 1000 })
})
it('Should use last intersected default for equivalent sub schemas (primitives)', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Number(),
Type.Number({ default: 1000 })
])
const V = Value.Cast(T, null)
Assert.IsEqual(V, 1000)
})
it('Should preserve if default is specified', () => {
// prettier-ignore
const T = Type.Intersect([
Type.Number(),
Type.Number({ default: 1000 })
])
const V = Value.Cast(T, 2000)
Assert.IsEqual(V, 2000)
})
// ----------------------------------------------------------------
// https://github.com/sinclairzx81/typebox/issues/1264
// ----------------------------------------------------------------
it('Should preserve intersected properties', () => {
const T = Type.Intersect([
Type.Object({}),
Type.Object({
name: Type.String(),
age: Type.Optional(Type.Number()),
location: Type.Object({
lat: Type.Number(),
long: Type.Number(),
}),
greeting: Type.String(),
}),
])
const V0 = Value.Cast(T, { greeting: 'Hello' })
const V1 = Value.Cast(T, { location: null, greeting: 'Hello' })
const V2 = Value.Cast(T, { location: { lat: 1 }, greeting: 'Hello' })
const V3 = Value.Cast(T, { location: { lat: 1, long: 1 }, greeting: 'Hello' })
Assert.IsEqual(V0, { name: '', location: { lat: 0, long: 0 }, greeting: 'Hello' })
Assert.IsEqual(V1, { name: '', location: { lat: 0, long: 0 }, greeting: 'Hello' })
Assert.IsEqual(V2, { name: '', location: { lat: 1, long: 0 }, greeting: 'Hello' })
Assert.IsEqual(V3, { name: '', location: { lat: 1, long: 1 }, greeting: 'Hello' })
})
// --------------------------------------------------------------------------
// https://github.com/sinclairzx81/typebox/issues/1269#issuecomment-2993924180
// --------------------------------------------------------------------------
it('Should Cast with intersected Record', () => {
const T = Type.Intersect([Type.Record(Type.TemplateLiteral('x-${string}'), Type.Unknown()), Type.Object({ name: Type.String() })])
const R = Value.Cast(T, {})
Assert.IsEqual(R, { name: '' })
})
})

View File

@@ -0,0 +1,37 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Iterator', () => {
const T = Type.Iterator(Type.Any())
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.iterator in result)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.iterator in result)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.iterator in result)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.iterator in result)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsTrue(Symbol.iterator in result)
})
it('Should preseve', () => {
const value = (function* () {})()
const result = Value.Cast(T, value)
Assert.IsTrue(value === result)
})
})

View File

@@ -0,0 +1,59 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/KeyOf', () => {
const T = Type.KeyOf(
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
const E = 'x'
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = 'y'
const result = Value.Cast(T, value)
Assert.IsEqual(result, 'y')
})
})

View File

@@ -0,0 +1,62 @@
import { Value } from '@sinclair/typebox/value'
import { Type, Kind, TypeRegistry } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Kind', () => {
// ---------------------------------------------------------
// Fixtures
// ---------------------------------------------------------
before(() => TypeRegistry.Set('Kind', (schema, value) => value === 'hello' || value === 'world'))
after(() => TypeRegistry.Clear())
// ---------------------------------------------------------
// Tests
// ---------------------------------------------------------
const T = Type.Unsafe({ [Kind]: 'Kind', default: 'hello' })
const E = 'hello'
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = false
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = { a: 'hello', b: 'world' }
const result = Value.Cast(
Type.Object({
a: T,
b: T,
}),
value,
)
Assert.IsEqual(result, { a: 'hello', b: 'world' })
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Literal', () => {
const T = Type.Literal('hello')
const E = 'hello'
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preseve', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, 'hello')
})
})

View File

@@ -0,0 +1,39 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Never', () => {
const T = Type.Never()
it('Should throw from string', () => {
const value = 'hello'
Assert.Throws(() => Value.Cast(T, value))
})
it('Should throw from number', () => {
const value = 1
Assert.Throws(() => Value.Cast(T, value))
})
it('Should throw from boolean', () => {
const value = false
Assert.Throws(() => Value.Cast(T, value))
})
it('Should throw from object', () => {
const value = {}
Assert.Throws(() => Value.Cast(T, value))
})
it('Should throw from array', () => {
const value = [1]
Assert.Throws(() => Value.Cast(T, value))
})
it('Should throw from undefined', () => {
const value = undefined
Assert.Throws(() => Value.Cast(T, value))
})
it('Should throw from null', () => {
const value = null
Assert.Throws(() => Value.Cast(T, value))
})
it('Should upcast from date', () => {
const value = null
Assert.Throws(() => Value.Cast(T, value))
})
})

View File

@@ -0,0 +1,52 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Not', () => {
const T = Type.Not(Type.String(), { default: 0 })
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, 0) // default
})
it('Should upcast from number', () => {
const value = 0
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should preserve', () => {
const value = 100
const result = Value.Cast(T, value)
Assert.IsEqual(result, 100)
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Null', () => {
const T = Type.Null()
const E = null
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preseve', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, null)
})
})

View File

@@ -0,0 +1,48 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Number', () => {
const T = Type.Number()
const E = 0
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, 1)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preseve', () => {
const value = 123
const result = Value.Cast(T, value)
Assert.IsEqual(result, 123)
})
})

View File

@@ -0,0 +1,162 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Object', () => {
const T = Type.Object({
a: Type.Number({ default: 'a' }),
b: Type.Number({ default: 'b' }),
c: Type.Number({ default: 'c' }),
x: Type.Number({ default: 0 }),
y: Type.Number({ default: 1 }),
z: Type.Number({ default: 2 }),
})
const E = {
x: 0,
y: 1,
z: 2,
a: 'a',
b: 'b',
c: 'c',
}
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = E
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = { x: 7, y: 8, z: 9, a: 10, b: 11, c: 12 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, {
x: 7,
y: 8,
z: 9,
a: 10,
b: 11,
c: 12,
})
})
it('Should upcast and preserve partial object', () => {
const value = { x: 7, y: 8, z: 9 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, {
x: 7,
y: 8,
z: 9,
a: 'a',
b: 'b',
c: 'c',
})
})
it('Should upcast and preserve partial object with incorrect properties', () => {
const value = { x: {}, y: 8, z: 9 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, {
x: 0,
y: 8,
z: 9,
a: 'a',
b: 'b',
c: 'c',
})
})
it('Should upcast and preserve partial object and omit unknown properties', () => {
const value = { x: 7, y: 8, z: 9, unknown: 'foo' }
const result = Value.Cast(T, value)
Assert.IsEqual(result, {
x: 7,
y: 8,
z: 9,
a: 'a',
b: 'b',
c: 'c',
})
})
it('Should upcast and create invalid additional properties', () => {
const result = Value.Cast(
Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.Object({
a: Type.Number(),
b: Type.Number(),
}),
},
),
{
x: 1,
y: 2,
z: true,
},
)
Assert.IsEqual(result, {
x: 1,
y: 2,
z: { a: 0, b: 0 },
})
})
it('Should upcast and preserve additional properties', () => {
const result = Value.Cast(
Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.Object({
a: Type.Number(),
b: Type.Number(),
}),
},
),
{
x: 1,
y: 2,
z: { b: 1 },
},
)
Assert.IsEqual(result, {
x: 1,
y: 2,
z: { a: 0, b: 1 },
})
})
})

View File

@@ -0,0 +1,80 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Record', () => {
const T = Type.Record(
Type.String(),
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
const E = {}
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = E
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = {
a: { x: 1, y: 2, z: 3 },
b: { x: 4, y: 5, z: 6 },
}
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should preserve and patch invalid records', () => {
const value = {
a: { x: 1, y: 2, z: 3 },
b: { x: 4, y: 5, z: {} },
c: [1, 2, 3],
d: 1,
e: { x: 1, y: 2, w: 9000 },
}
const result = Value.Cast(T, value)
Assert.IsEqual(result, {
a: { x: 1, y: 2, z: 3 },
b: { x: 4, y: 5, z: 0 },
c: { x: 0, y: 0, z: 0 },
d: { x: 0, y: 0, z: 0 },
e: { x: 1, y: 2, z: 0 },
})
})
})

View File

@@ -0,0 +1,98 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Recursive', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const E = { id: '', nodes: [] }
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = E
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = {
id: 'A',
nodes: [
{ id: 'B', nodes: [] },
{ id: 'C', nodes: [] },
{ id: 'D', nodes: [] },
],
}
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from varying types', () => {
const TypeA = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const TypeB = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
name: Type.String({ default: 'test' }),
nodes: Type.Array(This),
}),
)
const ValueA = {
id: 'A',
nodes: [
{ id: 'B', nodes: [] },
{ id: 'C', nodes: [] },
{ id: 'D', nodes: [] },
],
}
const ValueB = Value.Cast(TypeB, ValueA)
// Assert.isEqual(ValueB, {
// id: 'A',
// name: 'test',
// nodes: [
// { id: 'B', name: 'test', nodes: [] },
// { id: 'C', name: 'test', nodes: [] },
// { id: 'D', name: 'test', nodes: [] },
// ],
// })
})
})

View File

@@ -0,0 +1,60 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/RegExp', () => {
const T = Type.RegExp(/foo/, { default: 'foo' })
const E = 'foo'
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, 'foo')
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = 'foo'
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
// ----------------------------------------------------------------
// Throw
// ----------------------------------------------------------------
it('Should throw with no default', () => {
const T = Type.RegExp(/foo/)
Assert.Throws(() => Value.Cast(T, null))
})
})

View File

@@ -0,0 +1,43 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/String', () => {
const T = Type.String()
const E = ''
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, 'hello')
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = 'foo'
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
})

View File

@@ -0,0 +1,52 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Symbol', () => {
const T = Type.Symbol()
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should upcast from number', () => {
const value = 0
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsTypeOf(result, 'symbol')
})
it('Should preserve', () => {
const value = Symbol('hello')
const result = Value.Cast(T, value)
Assert.IsEqual(result.description, value.description)
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/TemplateLiteral', () => {
const T = Type.TemplateLiteral([Type.Literal('hello'), Type.Literal('world')])
const E = 'helloworld'
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preseve', () => {
const value = 'helloworld'
const result = Value.Cast(T, value)
Assert.IsEqual(result, 'helloworld')
})
})

View File

@@ -0,0 +1,73 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Tuple', () => {
const T = Type.Tuple([Type.Number(), Type.String()])
const E = [0, '']
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [1, ''])
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = [42, 'world']
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast with empty', () => {
const value = [] as any[]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should append with less than tuple length', () => {
const value = [42]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [42, ''])
})
it('Should truncate with greater than tuple length', () => {
const value = [42, '', true]
const result = Value.Cast(T, value)
Assert.IsEqual(result, [42, ''])
})
it('Should preserve and patch invalid element', () => {
const value = [{}, 'hello']
const result = Value.Cast(T, value)
Assert.IsEqual(result, [0, 'hello'])
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Uint8Array', () => {
const T = Type.Uint8Array({ default: new Uint8Array([0, 1, 2, 3]) })
const E = new Uint8Array([0, 1, 2, 3])
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = new Uint8Array([6, 7, 8, 9, 10])
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Undefined', () => {
const T = Type.Undefined()
const E = undefined
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preseve', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, undefined)
})
})

View File

@@ -0,0 +1,435 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Union', () => {
const A = Type.Object(
{
type: Type.Literal('A'),
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
},
{ additionalProperties: false },
)
const B = Type.Object(
{
type: Type.Literal('B'),
a: Type.String(),
b: Type.String(),
c: Type.String(),
},
{ additionalProperties: false },
)
const T = Type.Union([A, B])
const E = {
type: 'A',
x: 0,
y: 0,
z: 0,
}
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve A', () => {
const value = { type: 'A', x: 1, y: 2, z: 3 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should preserve B', () => {
const value = { type: 'B', a: 'a', b: 'b', c: 'c' }
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should infer through heuristics #1', () => {
const value = { type: 'A', a: 'a', b: 'b', c: 'c' }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { type: 'A', x: 0, y: 0, z: 0 })
})
it('Should infer through heuristics #2', () => {
const value = { type: 'B', x: 1, y: 2, z: 3 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { type: 'B', a: '', b: '', c: '' })
})
it('Should infer through heuristics #3', () => {
const value = { type: 'A', a: 'a', b: 'b', c: null }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { type: 'A', x: 0, y: 0, z: 0 })
})
it('Should infer through heuristics #4', () => {
const value = { type: 'B', x: 1, y: 2, z: {} }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { type: 'B', a: '', b: '', c: '' })
})
it('Should infer through heuristics #5', () => {
const value = { type: 'B', x: 1, y: 2, z: null }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { type: 'B', a: '', b: '', c: '' })
})
it('Should infer through heuristics #6', () => {
const value = { x: 1 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { type: 'A', x: 1, y: 0, z: 0 })
})
it('Should infer through heuristics #7', () => {
const value = { a: null } // property existing should contribute
const result = Value.Cast(T, value)
Assert.IsEqual(result, { type: 'B', a: '', b: '', c: '' })
})
it('Should cast with default value (create)', () => {
const result = Value.Cast(
Type.Object({
id: Type.Number(),
value: Type.Union([Type.Literal('A'), Type.Literal('B'), Type.Literal('C')], { default: 'C' }),
}),
{
id: 42,
value: 'D',
},
)
Assert.IsEqual(result, {
id: 42,
value: 'C',
})
})
it('Should cast with default value (preserve)', () => {
const result = Value.Cast(
Type.Object({
id: Type.Number(),
value: Type.Union([Type.Literal('A'), Type.Literal('B'), Type.Literal('C')], { default: 'C' }),
}),
{
id: 42,
value: 'B',
},
)
Assert.IsEqual(result, {
id: 42,
value: 'B',
})
})
// ----------------------------------------------------------------
// https://github.com/sinclairzx81/typebox/issues/880
// ----------------------------------------------------------------
// prettier-ignore
it('Should dereference union variants', () => {
const A = Type.Object({ type: Type.Literal('A') }, { $id: 'A' })
const B = Type.Object({ type: Type.Literal('B'), value: Type.Number() }, { $id: 'B' })
const RA = Type.Union([A, B])
const RB = Type.Union([Type.Ref('A'), Type.Ref('B')])
// variant 0
Assert.IsEqual(Value.Cast(RA, [A, B], { type: 'B' }), { type: 'B', value: 0 })
Assert.IsEqual(Value.Cast(RB, [A, B], { type: 'B' }), { type: 'B', value: 0 })
// variant 1
Assert.IsEqual(Value.Cast(RA, [A, B], { type: 'A' }), { type: 'A' })
Assert.IsEqual(Value.Cast(RB, [A, B], { type: 'A' }), { type: 'A' })
})
// ------------------------------------------------------------------------
// ref: https://github.com/sinclairzx81/typebox/issues/1268
// ------------------------------------------------------------------------
it('should correctly score nested union types #1', () => {
const A = Type.Union([
Type.Union([
Type.Object({
type: Type.Literal('a'),
name: Type.String(),
in: Type.String(),
}),
Type.Object({
type: Type.Literal('b'),
description: Type.Optional(Type.String()),
nested: Type.Object({
a: Type.String(),
b: Type.Optional(Type.String()),
}),
}),
]),
Type.Object({
$ref: Type.String(),
description: Type.Optional(Type.String()),
}),
])
Assert.IsEqual(
Value.Cast(A, {
type: 'b',
description: 'Hello World',
nested: {
b: 'hello',
},
}),
{
type: 'b',
description: 'Hello World',
nested: { a: '', b: 'hello' },
},
)
})
it('should correctly score nested union types #2', () => {
const A = Type.Union([
Type.Union([
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop3: Type.String(),
}),
Type.Object({
prop1: Type.String(),
prop4: Type.String(),
prop5: Type.String(),
}),
]),
Type.Union([
Type.Object({
prop6: Type.String(),
prop7: Type.String(),
prop8: Type.String(),
}),
Type.Object({
prop1: Type.String(),
prop9: Type.String(),
prop10: Type.String(),
}),
]),
])
// Picks the first union variant when the score is equal
Assert.IsEqual(
Value.Cast(A, {
prop1: '',
}),
{
prop1: '',
prop2: '',
prop3: '',
},
)
Assert.IsEqual(
Value.Cast(A, {
prop1: '',
prop4: '',
}),
{
prop1: '',
prop4: '',
prop5: '',
},
)
Assert.IsEqual(
Value.Cast(A, {
prop6: '',
}),
{
prop6: '',
prop7: '',
prop8: '',
},
)
})
it('should correctly score nested union types #3', () => {
const A = Type.Union([
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop3: Type.String(),
}),
Type.Object({
prop4: Type.String(),
prop5: Type.String(),
prop6: Type.String(),
}),
Type.Union([
Type.Object({
prop4: Type.String(),
prop5: Type.String(),
prop6: Type.String(),
}),
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop7: Type.String(),
prop8: Type.String(),
}),
]),
])
Assert.IsEqual(
Value.Cast(A, {
prop1: '',
prop2: '',
prop7: '',
}),
{
prop1: '',
prop2: '',
prop7: '',
prop8: '',
},
)
})
it('should correctly score nested union types #4', () => {
const A = Type.Union([
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop3: Type.String(),
}),
Type.Union([
Type.Object({
prop4: Type.String(),
prop5: Type.String(),
prop6: Type.String(),
}),
Type.Union([
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop7: Type.String(),
prop8: Type.String(),
}),
Type.Union([
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop9: Type.String(),
prop10: Type.String(),
}),
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop11: Type.String(),
prop12: Type.String(),
}),
]),
]),
]),
])
Assert.IsEqual(
Value.Cast(A, {
prop1: '',
prop2: '',
prop9: '',
}),
{
prop1: '',
prop2: '',
prop9: '',
prop10: '',
},
)
})
// ------------------------------------------------------------------------
// ref: https://github.com/sinclairzx81/typebox/issues/1292
// ------------------------------------------------------------------------
it('should correctly score object unions with shared properties #1', () => {
const schema = Type.Union([
Type.Object({
summary: Type.Optional(Type.String()),
description: Type.Optional(Type.String()),
parameters: Type.Optional(Type.Array(Type.Any())),
responses: Type.Optional(Type.Record(Type.String(), Type.Any())),
requestBody: Type.Optional(Type.Any()),
}),
Type.Object({
$ref: Type.String(),
summary: Type.Optional(Type.String()),
}),
])
Assert.IsEqual(
Value.Cast(schema, {
summary: 'Test Summary',
parameters: {},
}),
{
summary: 'Test Summary',
parameters: [],
},
)
})
it('should correctly score object unions with shared properties #2', () => {
const A = Type.Union([
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop3: Type.String(),
}),
Type.Object({
prop1: Type.String(),
prop2: Type.String(),
prop4: Type.String(),
prop5: Type.String(),
prop6: Type.String(),
prop7: Type.String(),
prop8: Type.String(),
prop9: Type.String(),
prop10: Type.String(),
}),
])
Assert.IsEqual(
Value.Cast(A, {
prop1: '',
prop2: '',
prop7: '',
}),
{
prop1: '',
prop2: '',
prop4: '',
prop5: '',
prop6: '',
prop7: '',
prop8: '',
prop9: '',
prop10: '',
},
)
})
})

View File

@@ -0,0 +1,52 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Unknown', () => {
const T = Type.Unknown()
it('Should upcast from string', () => {
const value = 'hello'
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from boolean', () => {
const value = false
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, value)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result: any = Value.Cast(T, value)
Assert.IsEqual(result.getTime(), 100)
})
it('Should preserve', () => {
const value = { a: 1, b: 2 }
const result = Value.Cast(T, value)
Assert.IsEqual(result, { a: 1, b: 2 })
})
})

View File

@@ -0,0 +1,53 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/cast/Void', () => {
const T = Type.Void()
const E = undefined
it('Should upcast from string', () => {
const value = 'world'
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from number', () => {
const value = 1
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from boolean', () => {
const value = true
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from object', () => {
const value = {}
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from array', () => {
const value = [1]
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from undefined', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from null', () => {
const value = null
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should upcast from date', () => {
const value = new Date(100)
const result = Value.Cast(T, value)
Assert.IsEqual(result, E)
})
it('Should preserve', () => {
const value = undefined
const result = Value.Cast(T, value)
Assert.IsEqual(result, undefined)
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Any', () => {
const T = Type.Any()
it('Should pass string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Argument', () => {
const T = Type.Argument(0)
it('Should pass string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
})

View File

@@ -0,0 +1,155 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Array', () => {
it('Should pass number array', () => {
const T = Type.Array(Type.Number())
const value = [1, 2, 3]
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail number array', () => {
const T = Type.Array(Type.Number())
const value = ['a', 'b', 'c']
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass object array', () => {
const T = Type.Array(Type.Object({ x: Type.Number() }))
const value = [{ x: 1 }, { x: 1 }, { x: 1 }]
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail object array', () => {
const T = Type.Array(Type.Object({ x: Type.Number() }))
const value = [{ x: 1 }, { x: 1 }, 1]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(Type.Array(Type.Any()), value)
Assert.IsEqual(result, false)
})
it('Should validate array with unique primitive items', () => {
const T = Type.Array(Type.Number(), { uniqueItems: true })
const result = Value.Check(T, [0, 1, 2])
Assert.IsEqual(result, true)
})
it('Should not validate array with non-unique primitive items', () => {
const T = Type.Array(Type.Number(), { uniqueItems: true })
const result = Value.Check(T, [0, 0, 2])
Assert.IsEqual(result, false)
})
it('Should validate array with unique object items', () => {
const T = Type.Array(Type.Object({ x: Type.Number(), y: Type.Number() }), { uniqueItems: true })
const result = Value.Check(T, [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
])
Assert.IsEqual(result, true)
})
it('Should not validate array with non-unique object items', () => {
const T = Type.Array(Type.Object({ x: Type.Number(), y: Type.Number() }), { uniqueItems: true })
const result = Value.Check(T, [
{ x: 1, y: 1 },
{ x: 1, y: 1 },
{ x: 3, y: 3 },
])
Assert.IsEqual(result, false)
})
// ---------------------------------------------------------
// Contains
// ---------------------------------------------------------
it('Should validate for contains', () => {
const T = Type.Array(Type.Number(), { contains: Type.Literal(1) })
Assert.IsTrue(Value.Check(T, [1]))
Assert.IsTrue(Value.Check(T, [1, 2]))
Assert.IsFalse(Value.Check(T, []))
Assert.IsFalse(Value.Check(T, [2]))
})
it('Should validate for minContains', () => {
const T = Type.Array(Type.Number(), { contains: Type.Literal(1), minContains: 3 })
Assert.IsTrue(Value.Check(T, [1, 1, 1, 2]))
Assert.IsTrue(Value.Check(T, [2, 1, 1, 1, 2]))
Assert.IsTrue(Value.Check(T, [1, 1, 1]))
Assert.IsFalse(Value.Check(T, []))
Assert.IsFalse(Value.Check(T, [1, 1]))
Assert.IsFalse(Value.Check(T, [2]))
})
it('Should validate for maxContains', () => {
const T = Type.Array(Type.Number(), { contains: Type.Literal(1), maxContains: 3 })
Assert.IsTrue(Value.Check(T, [1, 1, 1]))
Assert.IsTrue(Value.Check(T, [1, 1]))
Assert.IsTrue(Value.Check(T, [2, 2, 2, 2, 1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1]))
})
it('Should validate for minContains and maxContains', () => {
const T = Type.Array(Type.Number(), { contains: Type.Literal(1), minContains: 3, maxContains: 5 })
Assert.IsFalse(Value.Check(T, [1, 1]))
Assert.IsTrue(Value.Check(T, [1, 1, 1]))
Assert.IsTrue(Value.Check(T, [1, 1, 1, 1]))
Assert.IsTrue(Value.Check(T, [1, 1, 1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1, 1, 1]))
})
it('Should not validate minContains and maxContains when contains is unspecified', () => {
const T = Type.Array(Type.Number(), { minContains: 3, maxContains: 5 })
Assert.IsFalse(Value.Check(T, [1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1, 1, 1]))
})
it('Should produce illogical schema when contains is not sub type of items', () => {
const T = Type.Array(Type.Number(), { contains: Type.String(), minContains: 3, maxContains: 5 })
Assert.IsFalse(Value.Check(T, [1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1, 1]))
Assert.IsFalse(Value.Check(T, [1, 1, 1, 1, 1, 1]))
})
// ----------------------------------------------------------------
// Issue: https://github.com/sinclairzx81/typebox/discussions/607
// ----------------------------------------------------------------
it('Should correctly handle undefined array properties', () => {
const Answer = Type.Object({
text: Type.String(),
isCorrect: Type.Boolean(),
})
const Question = Type.Object({
text: Type.String(),
options: Type.Array(Answer, {
minContains: 1,
maxContains: 1,
contains: Type.Object({
text: Type.String(),
isCorrect: Type.Literal(true),
}),
}),
})
Assert.IsFalse(Value.Check(Question, { text: 'A' }))
Assert.IsFalse(Value.Check(Question, { text: 'A', options: [] }))
Assert.IsTrue(Value.Check(Question, { text: 'A', options: [{ text: 'A', isCorrect: true }] }))
Assert.IsTrue(
Value.Check(Question, {
text: 'A',
options: [
{ text: 'A', isCorrect: true },
{ text: 'B', isCorrect: false },
],
}),
)
Assert.IsFalse(Value.Check(Question, { text: 'A', options: [{ text: 'A', isCorrect: false }] }))
Assert.IsFalse(
Value.Check(Question, {
text: 'A',
options: [
{ text: 'A', isCorrect: true },
{ text: 'B', isCorrect: true },
],
}),
)
})
})

View File

@@ -0,0 +1,24 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/AsyncIterator', () => {
it('Should pass async iterator 1', () => {
async function* f() {}
const T = Type.AsyncIterator(Type.Any())
const result = Value.Check(T, f())
Assert.IsEqual(result, true)
})
it('Should pass async iterator 2', () => {
const T = Type.AsyncIterator(Type.Any())
const result = Value.Check(T, {
[Symbol.asyncIterator]: () => {},
})
Assert.IsEqual(result, true)
})
it('Should pass async iterator', () => {
const T = Type.AsyncIterator(Type.Any())
const result = Value.Check(T, {})
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,41 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/BigInt', () => {
const T = Type.BigInt()
it('Should not validate NaN', () => {
const T = Type.BigInt()
const result = Value.Check(T, NaN)
Assert.IsEqual(result, false)
})
it('Should not validate +Infinity', () => {
const T = Type.BigInt()
const result = Value.Check(T, Infinity)
Assert.IsEqual(result, false)
})
it('Should not validate -Infinity', () => {
const T = Type.BigInt()
const result = Value.Check(T, -Infinity)
Assert.IsEqual(result, false)
})
it('Should fail integer', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail integer', () => {
const value = 3.14
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass bigint', () => {
const result = Value.Check(T, BigInt(0))
Assert.IsEqual(result, true)
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Boolean', () => {
const T = Type.Boolean()
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,77 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Composite', () => {
const A = Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
})
const B = Type.Object({
a: Type.String(),
b: Type.String(),
c: Type.String(),
})
const T = Type.Composite([A, B])
it('Should pass composite', () => {
const value = {
x: 1,
y: 1,
z: 1,
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail intersect with invalid property', () => {
const value = {
x: true,
y: 1,
z: 1,
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail intersect with missing property', () => {
const value = {
y: 1,
z: 1,
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail intersect with primitive value', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass intersect with optional properties', () => {
const A = Type.Object({
x: Type.Optional(Type.Number()),
y: Type.Optional(Type.Number()),
z: Type.Optional(Type.Number()),
})
const B = Type.Object({
a: Type.String(),
b: Type.String(),
c: Type.String(),
})
const T = Type.Composite([A, B])
const value = {
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
})

View File

@@ -0,0 +1,42 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Const', () => {
it('Should validate 1', () => {
const T = Type.Const(1)
Assert.IsTrue(Value.Check(T, 1))
})
it('Should validate 2', () => {
const T = Type.Const('hello')
Assert.IsTrue(Value.Check(T, 'hello'))
})
it('Should validate 3', () => {
const T = Type.Const(true)
Assert.IsTrue(Value.Check(T, true))
})
it('Should validate 4', () => {
const T = Type.Const({ x: 1, y: 2 })
Assert.IsTrue(Value.Check(T, { x: 1, y: 2 }))
})
it('Should validate 5', () => {
const T = Type.Const([1, 2, 3])
Assert.IsTrue(Value.Check(T, [1, 2, 3]))
})
it('Should validate 6', () => {
const T = Type.Const([1, true, 'hello'])
Assert.IsTrue(Value.Check(T, [1, true, 'hello']))
})
it('Should validate 7', () => {
const T = Type.Const({
x: [1, 2, 3, 4],
y: { x: 1, y: 2, z: 3 },
})
Assert.IsTrue(
Value.Check(T, {
x: [1, 2, 3, 4],
y: { x: 1, y: 2, z: 3 },
}),
)
})
})

View File

@@ -0,0 +1,87 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Constructor', () => {
it('Should validate constructor 1', () => {
const T = Type.Constructor([], Type.Object({}))
Assert.IsTrue(Value.Check(T, class {}))
})
it('Should validate constructor 2', () => {
const T = Type.Constructor([Type.Number()], Type.Object({}))
// note: constructor arguments are non-checkable
Assert.IsTrue(Value.Check(T, class {}))
})
it('Should validate constructor 3', () => {
const T = Type.Constructor(
[Type.Number()],
Type.Object({
method: Type.Function([], Type.Void()),
}),
)
Assert.IsTrue(
Value.Check(
T,
class {
method() {}
},
),
)
})
it('Should validate constructor 4', () => {
const T = Type.Constructor(
[Type.Number()],
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
Assert.IsTrue(
Value.Check(
T,
class {
get x() {
return 1
}
get y() {
return 1
}
get z() {
return 1
}
},
),
)
})
it('Should not validate constructor 1', () => {
const T = Type.Constructor([Type.Number()], Type.Object({}))
Assert.IsFalse(Value.Check(T, 1))
})
it('Should not validate constructor 2', () => {
const T = Type.Constructor(
[Type.Number()],
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
Assert.IsFalse(
Value.Check(
T,
class {
get x() {
return null
}
get y() {
return null
}
get z() {
return null
}
},
),
)
})
})

View File

@@ -0,0 +1,87 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Date', () => {
const T = Type.Date()
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should fail null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should fail undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should pass Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsTrue(result)
})
it('Should not validate Date if is invalid', () => {
const value = new Date('not-a-valid-date')
const result = Value.Check(T, value)
Assert.IsFalse(result)
})
it('Should validate Date minimumTimestamp', () => {
const T = Type.Date({ minimumTimestamp: 10 })
const R1 = Value.Check(T, new Date(9))
const R2 = Value.Check(T, new Date(10))
Assert.IsFalse(R1)
Assert.IsTrue(R2)
})
it('Should validate Date maximumTimestamp', () => {
const T = Type.Date({ maximumTimestamp: 10 })
const R1 = Value.Check(T, new Date(11))
const R2 = Value.Check(T, new Date(10))
Assert.IsFalse(R1)
Assert.IsTrue(R2)
})
it('Should validate Date exclusiveMinimumTimestamp', () => {
const T = Type.Date({ exclusiveMinimumTimestamp: 10 })
const R1 = Value.Check(T, new Date(10))
const R2 = Value.Check(T, new Date(11))
Assert.IsFalse(R1)
Assert.IsTrue(R2)
})
it('Should validate Date exclusiveMaximumTimestamp', () => {
const T = Type.Date({ exclusiveMaximumTimestamp: 10 })
const R1 = Value.Check(T, new Date(10))
const R2 = Value.Check(T, new Date(9))
Assert.IsFalse(R1)
Assert.IsTrue(R2)
})
it('Should validate Date multipleOfTimestamp', () => {
const T = Type.Date({ multipleOfTimestamp: 2 })
const R1 = Value.Check(T, new Date(1))
const R2 = Value.Check(T, new Date(2))
Assert.IsFalse(R1)
Assert.IsTrue(R2)
})
})

View File

@@ -0,0 +1,31 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Enum', () => {
enum Foo {
A = 1,
B = 2,
}
const T = Type.Enum(Foo)
it('Should pass enum option A', () => {
const value = Foo.A
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass enum option B', () => {
const value = Foo.A
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail unknown value', () => {
const value = 'unknown'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,28 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Function', () => {
it('Should validate function 1', () => {
const T = Type.Function([Type.Number()], Type.Number())
Assert.IsTrue(Value.Check(T, function () {}))
})
it('Should validate function 2', () => {
const T = Type.Function([Type.Number()], Type.Number())
// note: validation only checks typeof 'function'
Assert.IsTrue(Value.Check(T, function (a: string, b: string, c: string, d: string) {}))
})
it('Should validate function 3', () => {
const T = Type.Function([Type.Number()], Type.Number())
// note: validation only checks typeof 'function'
Assert.IsTrue(
Value.Check(T, function () {
return 'not-a-number'
}),
)
})
it('Should not validate function', () => {
const T = Type.Function([Type.Number()], Type.Number())
Assert.IsFalse(Value.Check(T, 1))
})
})

View File

@@ -0,0 +1,37 @@
import './any'
import './argument'
import './array'
import './async-iterator'
import './bigint'
import './boolean'
import './composite'
import './const'
import './constructor'
import './date'
import './enum'
import './function'
import './integer'
import './intersect'
import './iterator'
import './keyof'
import './kind'
import './literal'
import './module'
import './never'
import './not'
import './null'
import './number'
import './object'
import './recursive'
import './ref'
import './record'
import './regexp'
import './string'
import './symbol'
import './template-literal'
import './tuple'
import './uint8array'
import './undefined'
import './union'
import './unknown'
import './void'

View File

@@ -0,0 +1,37 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Integer', () => {
const T = Type.Integer()
it('Should not validate NaN', () => {
const T = Type.Integer()
const result = Value.Check(T, NaN)
Assert.IsEqual(result, false)
})
it('Should not validate +Infinity', () => {
const T = Type.Integer()
const result = Value.Check(T, Infinity)
Assert.IsEqual(result, false)
})
it('Should not validate -Infinity', () => {
const T = Type.Integer()
const result = Value.Check(T, -Infinity)
Assert.IsEqual(result, false)
})
it('Should pass integer', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail integer', () => {
const value = 3.14
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,219 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Intersect', () => {
it('Should intersect number and number', () => {
const A = Type.Number()
const B = Type.Number()
const T = Type.Intersect([A, B], {})
Assert.IsEqual(Value.Check(T, 1), true)
})
it('Should not intersect string and number', () => {
const A = Type.String()
const B = Type.Number()
const T = Type.Intersect([A, B], {})
Assert.IsEqual(Value.Check(T, 1), false)
Assert.IsEqual(Value.Check(T, '1'), false)
})
it('Should intersect two objects', () => {
const A = Type.Object({ x: Type.Number() })
const B = Type.Object({ y: Type.Number() })
const T = Type.Intersect([A, B], {})
Assert.IsEqual(Value.Check(T, { x: 1, y: 1 }), true)
})
it('Should not intersect two objects with internal additionalProperties false', () => {
const A = Type.Object({ x: Type.Number() }, { additionalProperties: false })
const B = Type.Object({ y: Type.Number() }, { additionalProperties: false })
const T = Type.Intersect([A, B], {})
Assert.IsEqual(Value.Check(T, { x: 1, y: 1 }), false)
})
it('Should intersect two objects and mandate required properties', () => {
const A = Type.Object({ x: Type.Number() })
const B = Type.Object({ y: Type.Number() })
const T = Type.Intersect([A, B], {})
Assert.IsEqual(Value.Check(T, { x: 1, y: 1 }), true)
Assert.IsEqual(Value.Check(T, { x: 1 }), false)
Assert.IsEqual(Value.Check(T, { x: 1 }), false)
})
it('Should intersect two objects with unevaluated properties', () => {
const A = Type.Object({ x: Type.Number() })
const B = Type.Object({ y: Type.Number() })
const T = Type.Intersect([A, B], {})
Assert.IsEqual(Value.Check(T, { x: 1, y: 1, z: 1 }), true)
})
it('Should intersect two objects and restrict unevaluated properties', () => {
const A = Type.Object({ x: Type.Number() })
const B = Type.Object({ y: Type.Number() })
const T = Type.Intersect([A, B], { unevaluatedProperties: false })
Assert.IsEqual(Value.Check(T, { x: 1, y: 1, z: 1 }), false)
})
it('Should intersect two objects and allow unevaluated properties of number', () => {
const A = Type.Object({ x: Type.Number() })
const B = Type.Object({ y: Type.Number() })
const T = Type.Intersect([A, B], { unevaluatedProperties: Type.Number() })
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, z: 3 }), true)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, z: '1' }), false)
})
it('Should intersect two union objects with overlapping properties of the same type', () => {
const A = Type.Union([Type.Object({ x: Type.Number() })])
const B = Type.Union([Type.Object({ x: Type.Number() })])
const T = Type.Intersect([A, B])
Assert.IsEqual(Value.Check(T, { x: 1 }), true)
Assert.IsEqual(Value.Check(T, { x: '1' }), false)
})
it('Should not intersect two union objects with overlapping properties of varying types', () => {
const A = Type.Union([Type.Object({ x: Type.Number() })])
const B = Type.Union([Type.Object({ x: Type.String() })])
const T = Type.Intersect([A, B])
Assert.IsEqual(Value.Check(T, { x: 1 }), false)
Assert.IsEqual(Value.Check(T, { x: '1' }), false)
})
it('Should intersect two union objects with non-overlapping properties', () => {
const A = Type.Union([Type.Object({ x: Type.Number() })])
const B = Type.Union([Type.Object({ y: Type.Number() })])
const T = Type.Intersect([A, B])
Assert.IsEqual(Value.Check(T, { x: 1, y: 1 }), true)
})
it('Should not intersect two union objects with non-overlapping properties for additionalProperties false', () => {
const A = Type.Union([Type.Object({ x: Type.Number() }, { additionalProperties: false })])
const B = Type.Union([Type.Object({ y: Type.Number() }, { additionalProperties: false })])
const T = Type.Intersect([A, B])
Assert.IsEqual(Value.Check(T, { x: 1, y: 1 }), false)
})
it('unevaluatedProperties with Record 1', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: false,
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2 }), true)
})
it('unevaluatedProperties with Record 2', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: false,
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, 0: 'hello' }), true)
})
it('unevaluatedProperties with Record 3', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: false,
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, 0: 1 }), false)
})
it('unevaluatedProperties with Record 4', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: Type.Boolean(),
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2 }), true)
})
it('unevaluatedProperties with Record 5', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: Type.Boolean(),
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, z: true }), true)
})
it('unevaluatedProperties with Record 6', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: Type.Boolean(),
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, z: 1 }), false)
})
it('unevaluatedProperties with Record 7', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: Type.Boolean(),
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, 0: '' }), true)
})
it('unevaluatedProperties with Record 8', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: Type.Boolean(),
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, 0: '', z: true }), true)
})
it('unevaluatedProperties with Record 9', () => {
const T = Type.Intersect(
[
Type.Record(Type.Number(), Type.String()),
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
],
{
unevaluatedProperties: Type.Boolean(),
},
)
Assert.IsEqual(Value.Check(T, { x: 1, y: 2, 0: '', z: 1 }), false)
})
})

View File

@@ -0,0 +1,24 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Iterator', () => {
it('Should pass iterator 1', () => {
function* f() {}
const T = Type.Iterator(Type.Any())
const result = Value.Check(T, f())
Assert.IsEqual(result, true)
})
it('Should pass iterator 2', () => {
const T = Type.Iterator(Type.Any())
const result = Value.Check(T, {
[Symbol.iterator]: () => {},
})
Assert.IsEqual(result, true)
})
it('Should pass iterator', () => {
const T = Type.Iterator(Type.Any())
const result = Value.Check(T, {})
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,33 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/KeyOf', () => {
const T = Type.KeyOf(
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
it('Should pass keyof', () => {
const value = 'x'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail keyof', () => {
const value = 'w'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail keyof with undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail keyof with null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,107 @@
import { Value } from '@sinclair/typebox/value'
import { TypeRegistry, Type, Kind, TSchema } from '@sinclair/typebox'
import { Assert } from '../../assert'
describe('value/check/Kind', () => {
// ------------------------------------------------------------
// Fixtures
// ------------------------------------------------------------
beforeEach(() => TypeRegistry.Set('PI', (_, value) => value === Math.PI))
afterEach(() => TypeRegistry.Delete('PI'))
// ------------------------------------------------------------
// Tests
// ------------------------------------------------------------
it('Should validate', () => {
const T = Type.Unsafe({ [Kind]: 'PI' })
Assert.IsTrue(Value.Check(T, Math.PI))
})
it('Should not validate', () => {
const T = Type.Unsafe({ [Kind]: 'PI' })
Assert.IsFalse(Value.Check(T, Math.PI * 2))
})
it('Should validate in object', () => {
const T = Type.Object({
x: Type.Unsafe({ [Kind]: 'PI' }),
})
Assert.IsTrue(Value.Check(T, { x: Math.PI }))
})
it('Should not validate in object', () => {
const T = Type.Object({
x: Type.Unsafe({ [Kind]: 'PI' }),
})
Assert.IsFalse(Value.Check(T, { x: Math.PI * 2 }))
})
it('Should validate in array', () => {
const T = Type.Array(Type.Unsafe({ [Kind]: 'PI' }))
Assert.IsTrue(Value.Check(T, [Math.PI]))
})
it('Should not validate in array', () => {
const T = Type.Array(Type.Unsafe({ [Kind]: 'PI' }))
Assert.IsFalse(Value.Check(T, [Math.PI * 2]))
})
it('Should validate in tuple', () => {
const T = Type.Tuple([Type.Unsafe({ [Kind]: 'PI' })])
Assert.IsTrue(Value.Check(T, [Math.PI]))
})
it('Should not validate in tuple', () => {
const T = Type.Tuple([Type.Unsafe({ [Kind]: 'PI' })])
Assert.IsFalse(Value.Check(T, [Math.PI * 2]))
})
// ------------------------------------------------------------
// Instances
// ------------------------------------------------------------
it('Should receive kind instance on registry callback', () => {
const stack: string[] = []
TypeRegistry.Set('Kind', (schema: unknown) => {
// prettier-ignore
return (typeof schema === 'object' && schema !== null && Kind in schema && schema[Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string')
? (() => { stack.push(schema.$id); return true })()
: false
})
const A = { [Kind]: 'Kind', $id: 'A' } as TSchema
const B = { [Kind]: 'Kind', $id: 'B' } as TSchema
const T = Type.Object({ a: A, b: B })
const R = Value.Check(T, { a: null, b: null })
Assert.IsTrue(R)
Assert.IsEqual(stack[0], 'A')
Assert.IsEqual(stack[1], 'B')
TypeRegistry.Delete('Kind')
})
it('Should retain kind instances on subsequent check', () => {
let stack: string[] = []
TypeRegistry.Set('Kind', (schema: unknown) => {
// prettier-ignore
return (typeof schema === 'object' && schema !== null && Kind in schema && schema[Kind] === 'Kind' && '$id' in schema && typeof schema.$id === 'string')
? (() => { stack.push(schema.$id); return true })()
: false
})
const A = { [Kind]: 'Kind', $id: 'A' } as TSchema
const B = { [Kind]: 'Kind', $id: 'B' } as TSchema
const C = { [Kind]: 'Kind', $id: 'C' } as TSchema
const D = { [Kind]: 'Kind', $id: 'D' } as TSchema
const T1 = Type.Object({ a: A, b: B })
const T2 = Type.Object({ a: C, b: D })
// run T1 check
const R2 = Value.Check(T1, { a: null, b: null })
Assert.IsTrue(R2)
Assert.IsEqual(stack.length, 2)
Assert.IsEqual(stack[0], 'A')
Assert.IsEqual(stack[1], 'B')
stack = []
// run T2 check
const R3 = Value.Check(T2, { a: null, b: null })
Assert.IsTrue(R3)
Assert.IsEqual(stack.length, 2)
Assert.IsEqual(stack[0], 'C')
Assert.IsEqual(stack[1], 'D')
stack = []
// run T1 check
const R4 = Value.Check(T1, { a: null, b: null })
Assert.IsTrue(R4)
Assert.IsEqual(stack.length, 2)
Assert.IsEqual(stack[0], 'A')
Assert.IsEqual(stack[1], 'B')
stack = []
TypeRegistry.Delete('Kind')
})
})

View File

@@ -0,0 +1,27 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Literal', () => {
const T = Type.Literal('hello')
it('Should pass literal', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail literal', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail literal with undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail literal with null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,146 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert'
describe('value/check/Module', () => {
it('Should validate string', () => {
const Module = Type.Module({
A: Type.String(),
})
const T = Module.Import('A')
Assert.IsTrue(Value.Check(T, 'hello'))
Assert.IsFalse(Value.Check(T, true))
})
it('Should validate referenced string', () => {
const Module = Type.Module({
A: Type.String(),
B: Type.Ref('A'),
})
const T = Module.Import('B')
Assert.IsTrue(Value.Check(T, 'hello'))
Assert.IsFalse(Value.Check(T, true))
})
it('Should validate self referential', () => {
const Module = Type.Module({
A: Type.Object({
nodes: Type.Array(Type.Ref('A')),
}),
})
const T = Module.Import('A')
Assert.IsTrue(Value.Check(T, { nodes: [{ nodes: [{ nodes: [] }, { nodes: [] }] }] }))
Assert.IsFalse(Value.Check(T, { nodes: [{ nodes: [{ nodes: [] }, { nodes: false }] }] }))
Assert.IsFalse(Value.Check(T, true))
})
it('Should validate mutual recursive', () => {
const Module = Type.Module({
A: Type.Object({
b: Type.Ref('B'),
}),
B: Type.Object({
a: Type.Union([Type.Ref('A'), Type.Null()]),
}),
})
const T = Module.Import('A')
Assert.IsTrue(Value.Check(T, { b: { a: null } }))
Assert.IsTrue(Value.Check(T, { b: { a: { b: { a: null } } } }))
Assert.IsFalse(Value.Check(T, { b: { a: 1 } }))
Assert.IsFalse(Value.Check(T, { b: { a: { b: { a: 1 } } } }))
Assert.IsFalse(Value.Check(T, true))
})
it('Should validate mutual recursive (Array)', () => {
const Module = Type.Module({
A: Type.Object({
b: Type.Ref('B'),
}),
B: Type.Object({
a: Type.Array(Type.Ref('A')),
}),
})
const T = Module.Import('A')
Assert.IsTrue(Value.Check(T, { b: { a: [{ b: { a: [] } }] } }))
Assert.IsFalse(Value.Check(T, { b: { a: [{ b: { a: [null] } }] } }))
Assert.IsFalse(Value.Check(T, true))
})
it('Should validate deep referential', () => {
const Module = Type.Module({
A: Type.Ref('B'),
B: Type.Ref('C'),
C: Type.Ref('D'),
D: Type.Ref('E'),
E: Type.Ref('F'),
F: Type.Ref('G'),
G: Type.Ref('H'),
H: Type.Literal('hello'),
})
const T = Module.Import('A')
Assert.IsTrue(Value.Check(T, 'hello'))
Assert.IsFalse(Value.Check(T, 'world'))
})
// ----------------------------------------------------------------
// Modifiers
// ----------------------------------------------------------------
it('Should validate objects with property modifiers 1', () => {
const Module = Type.Module({
T: Type.Object({
x: Type.ReadonlyOptional(Type.Null()),
y: Type.Readonly(Type.Null()),
z: Type.Optional(Type.Null()),
w: Type.Null(),
}),
})
const T = Module.Import('T')
Assert.IsTrue(Value.Check(T, { x: null, y: null, w: null }))
Assert.IsTrue(Value.Check(T, { y: null, w: null }))
Assert.IsFalse(Value.Check(T, { x: 1, y: null, w: null }))
})
it('Should validate objects with property modifiers 2', () => {
const Module = Type.Module({
T: Type.Object({
x: Type.ReadonlyOptional(Type.Array(Type.Null())),
y: Type.Readonly(Type.Array(Type.Null())),
z: Type.Optional(Type.Array(Type.Null())),
w: Type.Array(Type.Null()),
}),
})
const T = Module.Import('T')
Assert.IsTrue(Value.Check(T, { x: [null], y: [null], w: [null] }))
Assert.IsTrue(Value.Check(T, { y: [null], w: [null] }))
Assert.IsFalse(Value.Check(T, { x: [1], y: [null], w: [null] }))
})
// ----------------------------------------------------------------
// https://github.com/sinclairzx81/typebox/issues/1109
// ----------------------------------------------------------------
it('Should validate deep referential 1', () => {
const Module = Type.Module({
A: Type.Union([Type.Literal('Foo'), Type.Literal('Bar')]),
B: Type.Ref('A'),
C: Type.Object({ ref: Type.Ref('B') }),
D: Type.Union([Type.Ref('B'), Type.Ref('C')]),
})
Assert.IsTrue(Value.Check(Module.Import('A') as never, 'Foo'))
Assert.IsTrue(Value.Check(Module.Import('A') as never, 'Bar'))
Assert.IsTrue(Value.Check(Module.Import('B') as never, 'Foo'))
Assert.IsTrue(Value.Check(Module.Import('B') as never, 'Bar'))
Assert.IsTrue(Value.Check(Module.Import('C') as never, { ref: 'Foo' }))
Assert.IsTrue(Value.Check(Module.Import('C') as never, { ref: 'Bar' }))
Assert.IsTrue(Value.Check(Module.Import('D') as never, 'Foo'))
Assert.IsTrue(Value.Check(Module.Import('D') as never, 'Bar'))
Assert.IsTrue(Value.Check(Module.Import('D') as never, { ref: 'Foo' }))
Assert.IsTrue(Value.Check(Module.Import('D') as never, { ref: 'Bar' }))
})
it('Should validate deep referential 2', () => {
const Module = Type.Module({
A: Type.Literal('Foo'),
B: Type.Ref('A'),
C: Type.Ref('B'),
D: Type.Ref('C'),
E: Type.Ref('D'),
})
Assert.IsTrue(Value.Check(Module.Import('A'), 'Foo'))
Assert.IsTrue(Value.Check(Module.Import('B'), 'Foo'))
Assert.IsTrue(Value.Check(Module.Import('C'), 'Foo'))
Assert.IsTrue(Value.Check(Module.Import('D'), 'Foo'))
Assert.IsTrue(Value.Check(Module.Import('E'), 'Foo'))
})
})

View File

@@ -0,0 +1,42 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Never', () => {
const T = Type.Never()
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,30 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Not', () => {
it('Should validate with not number', () => {
const T = Type.Not(Type.Number())
Assert.IsEqual(Value.Check(T, 1), false)
Assert.IsEqual(Value.Check(T, 'A'), true)
})
it('Should validate with union left', () => {
// prettier-ignore
const T = Type.Not(Type.Union([
Type.Literal('A'),
Type.Literal('B'),
Type.Literal('C')
]))
Assert.IsEqual(Value.Check(T, 'A'), false)
Assert.IsEqual(Value.Check(T, 'B'), false)
Assert.IsEqual(Value.Check(T, 'C'), false)
Assert.IsEqual(Value.Check(T, 'D'), true)
})
it('Should validate with union right', () => {
// prettier-ignore
const T = Type.Not(Type.Number())
Assert.IsEqual(Value.Check(T, 1), false)
Assert.IsEqual(Value.Check(T, 'A'), true)
Assert.IsEqual(Value.Check(T, true), true)
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Null', () => {
const T = Type.Null()
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,67 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Number', () => {
const T = Type.Number()
it('Should not validate NaN', () => {
const T = Type.Number()
const result = Value.Check(T, NaN)
Assert.IsEqual(result, false)
})
it('Should not validate +Infinity', () => {
const T = Type.Number()
const result = Value.Check(T, Infinity)
Assert.IsEqual(result, false)
})
it('Should not validate -Infinity', () => {
const T = Type.Number()
const result = Value.Check(T, -Infinity)
Assert.IsEqual(result, false)
})
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail NaN', () => {
const result = Value.Check(Type.Number(), NaN)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,212 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Object', () => {
const T = Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
a: Type.String(),
b: Type.String(),
c: Type.String(),
})
it('Should pass object', () => {
const value = {
x: 1,
y: 1,
z: 1,
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail object with additional properties', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
},
{ additionalProperties: false },
)
const value = {
x: 1,
y: 1,
z: 1,
a: 1,
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object with invalid property', () => {
const value = {
x: true,
y: 1,
z: 1,
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object with missing property', () => {
const value = {
y: 1,
z: 1,
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass object with optional properties', () => {
const T = Type.Object({
x: Type.Optional(Type.Number()),
y: Type.Optional(Type.Number()),
z: Type.Optional(Type.Number()),
a: Type.String(),
b: Type.String(),
c: Type.String(),
})
const value = {
a: '1',
b: '1',
c: '1',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail object with null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object with undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should validate schema additional properties of string', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
Assert.IsEqual(
Value.Check(T, {
x: 1,
y: 2,
z: 'hello',
}),
true,
)
Assert.IsEqual(
Value.Check(T, {
x: 1,
y: 2,
z: 3,
}),
false,
)
})
it('Should validate schema additional properties of array', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.Array(Type.Number()),
},
)
Assert.IsEqual(
Value.Check(T, {
x: 1,
y: 2,
z: [0, 1, 2],
}),
true,
)
Assert.IsEqual(
Value.Check(T, {
x: 1,
y: 2,
z: 3,
}),
false,
)
})
it('Should validate schema additional properties of object', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.Object({
z: Type.Number(),
}),
},
)
Assert.IsEqual(
Value.Check(T, {
x: 1,
y: 2,
z: { z: 1 },
}),
true,
)
Assert.IsEqual(
Value.Check(T, {
x: 1,
y: 2,
z: 3,
}),
false,
)
})
it('Should check for property key if property type is undefined', () => {
const T = Type.Object({ x: Type.Undefined() })
Assert.IsEqual(Value.Check(T, { x: undefined }), true)
Assert.IsEqual(Value.Check(T, {}), false)
})
it('Should check for property key if property type extends undefined', () => {
const T = Type.Object({ x: Type.Union([Type.Number(), Type.Undefined()]) })
Assert.IsEqual(Value.Check(T, { x: 1 }), true)
Assert.IsEqual(Value.Check(T, { x: undefined }), true)
Assert.IsEqual(Value.Check(T, {}), false)
})
it('Should not check for property key if property type is undefined and optional', () => {
const T = Type.Object({ x: Type.Optional(Type.Undefined()) })
Assert.IsEqual(Value.Check(T, { x: undefined }), true)
Assert.IsEqual(Value.Check(T, {}), true)
})
it('Should not check for property key if property type extends undefined and optional', () => {
const T = Type.Object({ x: Type.Optional(Type.Union([Type.Number(), Type.Undefined()])) })
Assert.IsEqual(Value.Check(T, { x: 1 }), true)
Assert.IsEqual(Value.Check(T, { x: undefined }), true)
Assert.IsEqual(Value.Check(T, {}), true)
})
it('Should check undefined for optional property of number', () => {
const T = Type.Object({ x: Type.Optional(Type.Number()) })
Assert.IsEqual(Value.Check(T, { x: 1 }), true)
Assert.IsEqual(Value.Check(T, { x: undefined }), true) // allowed by default
Assert.IsEqual(Value.Check(T, {}), true)
})
it('Should check undefined for optional property of undefined', () => {
const T = Type.Object({ x: Type.Optional(Type.Undefined()) })
Assert.IsEqual(Value.Check(T, { x: 1 }), false)
Assert.IsEqual(Value.Check(T, {}), true)
Assert.IsEqual(Value.Check(T, { x: undefined }), true)
})
})

View File

@@ -0,0 +1,297 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Record', () => {
it('Should pass record', () => {
const T = Type.Record(
Type.String(),
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
const value = {
position: {
x: 1,
y: 2,
z: 3,
},
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail when below minProperties', () => {
const T = Type.Record(Type.String(), Type.Number(), { minProperties: 4 })
Assert.IsEqual(Value.Check(T, { a: 1, b: 2, c: 3, d: 4 }), true)
Assert.IsEqual(Value.Check(T, { a: 1, b: 2, c: 3 }), false)
})
it('Should fail when above maxProperties', () => {
const T = Type.Record(Type.String(), Type.Number(), { maxProperties: 4 })
Assert.IsEqual(Value.Check(T, { a: 1, b: 2, c: 3, d: 4 }), true)
Assert.IsEqual(Value.Check(T, { a: 1, b: 2, c: 3, d: 4, e: 5 }), false)
})
it('Should fail with illogical minProperties | maxProperties', () => {
const T = Type.Record(Type.String(), Type.Number(), { minProperties: 5, maxProperties: 4 })
Assert.IsEqual(Value.Check(T, { a: 1, b: 2, c: 3 }), false)
Assert.IsEqual(Value.Check(T, { a: 1, b: 2, c: 3, d: 4 }), false)
Assert.IsEqual(Value.Check(T, { a: 1, b: 2, c: 3, d: 4, e: 5 }), false)
})
it('Should fail record with Date', () => {
const T = Type.Record(Type.String(), Type.String())
const result = Value.Check(T, new Date())
Assert.IsEqual(result, false)
})
it('Should fail record with Uint8Array', () => {
const T = Type.Record(Type.String(), Type.String())
const result = Value.Check(T, new Uint8Array())
Assert.IsEqual(result, false)
})
it('Should fail record with missing property', () => {
const T = Type.Record(
Type.String(),
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
const value = {
position: {
x: 1,
y: 2,
},
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail record with invalid property', () => {
const T = Type.Record(
Type.String(),
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
}),
)
const value = {
position: {
x: 1,
y: 2,
z: '3',
},
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass record with optional property', () => {
const T = Type.Record(
Type.String(),
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Optional(Type.Number()),
}),
)
const value = {
position: {
x: 1,
y: 2,
},
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass record with optional property', () => {
const T = Type.Record(
Type.String(),
Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Optional(Type.Number()),
}),
)
const value = {
position: {
x: 1,
y: 2,
},
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should validate when specifying regular expressions', () => {
const K = Type.RegExp(/^op_.*$/)
const T = Type.Record(K, Type.Number())
const R = Value.Check(T, {
op_a: 1,
op_b: 2,
op_c: 3,
})
Assert.IsTrue(R)
})
it('Should not validate when specifying regular expressions and passing invalid property', () => {
const K = Type.RegExp(/^op_.*$/)
const T = Type.Record(K, Type.Number(), { additionalProperties: false })
const R = Value.Check(T, {
op_a: 1,
op_b: 2,
aop_c: 3,
})
Assert.IsFalse(R)
})
it('Should validate with quoted string pattern', () => {
const K = Type.String({ pattern: "'(a|b|c)" })
const T = Type.Record(K, Type.Number())
const R = Value.Check(T, {
"'a": 1,
"'b": 2,
"'c": 3,
})
Assert.IsTrue(R)
})
it('Should validate with forward-slash pattern', () => {
const K = Type.String({ pattern: '/(a|b|c)' })
const T = Type.Record(K, Type.Number())
const R = Value.Check(T, {
'/a': 1,
'/b': 2,
'/c': 3,
})
Assert.IsTrue(R)
})
// -------------------------------------------------
// Number Key
// -------------------------------------------------
it('Should pass record with number key', () => {
const T = Type.Record(Type.Number(), Type.String())
const value = {
0: 'a',
1: 'a',
2: 'a',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should not pass record with invalid number key', () => {
const T = Type.Record(Type.Number(), Type.String(), { additionalProperties: false })
const value = {
a: 'a',
1: 'a',
2: 'a',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
// -------------------------------------------------
// Integer Key
// -------------------------------------------------
it('Should pass record with integer key', () => {
const T = Type.Record(Type.Integer(), Type.String())
const value = {
0: 'a',
1: 'a',
2: 'a',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should not pass record with invalid integer key', () => {
const T = Type.Record(Type.Integer(), Type.String(), { additionalProperties: false })
const value = {
a: 'a',
1: 'a',
2: 'a',
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
// ------------------------------------------------------------
// AdditionalProperties
// ------------------------------------------------------------
it('AdditionalProperties 1', () => {
const T = Type.Record(Type.Number(), Type.String(), { additionalProperties: true })
const R = Value.Check(T, { 1: '', 2: '', x: 1, y: 2, z: 3 })
Assert.IsEqual(R, true)
})
it('AdditionalProperties 2', () => {
const T = Type.Record(Type.Number(), Type.String(), { additionalProperties: false })
const R = Value.Check(T, { 1: '', 2: '', 3: '' })
Assert.IsEqual(R, true)
})
it('AdditionalProperties 3', () => {
const T = Type.Record(Type.Number(), Type.String(), { additionalProperties: false })
const R = Value.Check(T, { 1: '', 2: '', x: '' })
Assert.IsEqual(R, false)
})
it('AdditionalProperties 4', () => {
const T = Type.Record(Type.Number(), Type.String(), { additionalProperties: Type.Boolean() })
const R = Value.Check(T, { 1: '', 2: '', x: '' })
Assert.IsEqual(R, false)
})
it('AdditionalProperties 5', () => {
const T = Type.Record(Type.Number(), Type.String(), { additionalProperties: Type.Boolean() })
const R = Value.Check(T, { 1: '', 2: '', x: true })
Assert.IsEqual(R, true)
})
// ----------------------------------------------------------------
// https://github.com/sinclairzx81/typebox/issues/916
// ----------------------------------------------------------------
it('Should validate for string keys', () => {
const T = Type.Record(Type.String(), Type.Null(), {
additionalProperties: false,
})
const R = Value.Check(T, {
a: null,
b: null,
0: null,
1: null,
})
Assert.IsEqual(R, true)
})
it('Should validate for number keys', () => {
const T = Type.Record(Type.Number(), Type.Null(), {
additionalProperties: false,
})
const R1 = Value.Check(T, {
a: null,
b: null,
0: null,
1: null,
})
const R2 = Value.Check(T, {
0: null,
1: null,
})
Assert.IsEqual(R1, false)
Assert.IsEqual(R2, true)
})
it('Should validate for any keys', () => {
const T = Type.Record(Type.Any(), Type.Null(), {
additionalProperties: false,
})
const R = Value.Check(T, {
a: null,
b: null,
0: null,
1: null,
})
Assert.IsEqual(R, true)
})
it('Should validate for never keys', () => {
const T = Type.Record(Type.Never(), Type.Null(), {
additionalProperties: false,
})
const R1 = Value.Check(T, {})
const R2 = Value.Check(T, {
a: null,
b: null,
0: null,
1: null,
})
Assert.IsEqual(R1, true)
Assert.IsEqual(R2, false)
})
})

View File

@@ -0,0 +1,69 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Recursive', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
it('Should pass recursive', () => {
const value = {
id: 'A',
nodes: [
{ id: 'B', nodes: [] },
{ id: 'C', nodes: [] },
{ id: 'D', nodes: [] },
],
}
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail recursive with invalid id', () => {
const value = {
id: 'A',
nodes: [
{ id: 1, nodes: [] },
{ id: 'C', nodes: [] },
{ id: 'D', nodes: [] },
],
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail rec with invalid nodes', () => {
const value = {
id: 'A',
nodes: [
{ id: 'B', nodes: 1 },
{ id: 'C', nodes: [] },
{ id: 'D', nodes: [] },
],
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail recursive with missing id', () => {
const value = {
id: 'A',
nodes: [{ nodes: [] }, { id: 'C', nodes: [] }, { id: 'D', nodes: [] }],
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail rec with missing nodes', () => {
const value = {
id: 'A',
nodes: [{ id: 'B' }, { id: 'C', nodes: [] }, { id: 'D', nodes: [] }],
}
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,95 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Ref', () => {
// ----------------------------------------------------------------
// Deprecated
// ----------------------------------------------------------------
it('Should validate for Ref(Schema)', () => {
const T = Type.Number({ $id: 'T' })
const R = Type.Ref(T)
Assert.IsTrue(Value.Check(T, [T], 1234))
Assert.IsFalse(Value.Check(T, [T], 'hello'))
})
// ----------------------------------------------------------------
// Standard
// ----------------------------------------------------------------
it('Should should validate when referencing a type', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
},
{ $id: Assert.NextId() },
)
const R = Type.Ref(T.$id!)
Assert.IsEqual(
Value.Check(R, [T], {
x: 1,
y: 2,
z: 3,
}),
true,
)
})
it('Should not validate when passing invalid data', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
},
{ $id: Assert.NextId() },
)
const R = Type.Ref(T.$id!)
Assert.IsEqual(
Value.Check(R, [T], {
x: 1,
y: 2,
}),
false,
)
})
it('Should de-reference object property schema', () => {
const T = Type.Object(
{
name: Type.String(),
},
{ $id: 'R' },
)
const R = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
r: Type.Optional(Type.Ref(T.$id!)),
},
{ $id: 'T' },
)
Assert.IsEqual(Value.Check(R, [T], { x: 1, y: 2, z: 3 }), true)
Assert.IsEqual(Value.Check(R, [T], { x: 1, y: 2, z: 3, r: { name: 'hello' } }), true)
Assert.IsEqual(Value.Check(R, [T], { x: 1, y: 2, z: 3, r: { name: 1 } }), false)
Assert.IsEqual(Value.Check(R, [T], { x: 1, y: 2, z: 3, r: {} }), false)
// Ok(R, { x: 1, y: 2, z: 3 }, [T])
// Ok(R, , [T])
// Fail(R, , [T])
// Fail(R, , [T])
})
it('Should reference recursive schema', () => {
const T = Type.Recursive((Node) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(Node),
}),
)
const R = Type.Ref(T.$id!)
Assert.IsEqual(Value.Check(R, [T], { id: '', nodes: [{ id: '', nodes: [] }] }), true)
Assert.IsEqual(Value.Check(R, [T], { id: '', nodes: [{ id: 1, nodes: [] }] }), false)
})
})

View File

@@ -0,0 +1,50 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/RegExp', () => {
// -------------------------------------------------
// Regular Expression
// -------------------------------------------------
it('Should pass regular expression 1', () => {
const T = Type.RegExp(/foo/)
const value = 'foo'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass regular expression 2', () => {
const T = Type.RegExp(/foo/)
const value = 'bar'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
// -------------------------------------------------
// Pattern
// -------------------------------------------------
it('Should pass pattern 1', () => {
const T = Type.RegExp('foo')
const value = 'foo'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass pattern 2', () => {
const T = Type.RegExp('foo')
const value = 'bar'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should validate with minLength constraint', () => {
const T = Type.RegExp(/(.*)/, {
minLength: 3,
})
Assert.IsTrue(Value.Check(T, 'xxx'))
Assert.IsFalse(Value.Check(T, 'xx'))
})
it('Should validate with maxLength constraint', () => {
const T = Type.RegExp(/(.*)/, {
maxLength: 3,
})
Assert.IsTrue(Value.Check(T, 'xxx'))
Assert.IsFalse(Value.Check(T, 'xxxx'))
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/String', () => {
const T = Type.String()
it('Should pass string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,52 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Symbol', () => {
const T = Type.Symbol()
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass symbol', () => {
const value = Symbol(1)
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
})

View File

@@ -0,0 +1,187 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/TemplateLiteral', () => {
// --------------------------------------------------------
// Finite
// --------------------------------------------------------
it('Should validate finite pattern 1', () => {
// prettier-ignore
const T = Type.TemplateLiteral([])
Assert.IsEqual(Value.Check(T, ''), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate finite pattern 1', () => {
// prettier-ignore
const T = Type.TemplateLiteral([Type.Boolean()])
Assert.IsEqual(Value.Check(T, 'true'), true)
Assert.IsEqual(Value.Check(T, 'false'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate finite pattern 2', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A')
])
Assert.IsEqual(Value.Check(T, 'A'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate finite pattern 3', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A'),
Type.Literal('B')
])
Assert.IsEqual(Value.Check(T, 'AB'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate finite pattern 4', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A'),
Type.Union([
Type.Literal('B'),
Type.Literal('C')
]),
])
Assert.IsEqual(Value.Check(T, 'AB'), true)
Assert.IsEqual(Value.Check(T, 'AC'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate finite pattern 5', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A'),
Type.Union([
Type.Literal('B'),
Type.Literal('C')
]),
Type.Literal('D'),
])
Assert.IsEqual(Value.Check(T, 'ABD'), true)
Assert.IsEqual(Value.Check(T, 'ACD'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate finite pattern 6', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Union([
Type.Literal('0'),
Type.Literal('1')
]),
Type.Union([
Type.Literal('0'),
Type.Literal('1')
]),
])
Assert.IsEqual(Value.Check(T, '00'), true)
Assert.IsEqual(Value.Check(T, '01'), true)
Assert.IsEqual(Value.Check(T, '10'), true)
Assert.IsEqual(Value.Check(T, '11'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
// --------------------------------------------------------
// Infinite
// --------------------------------------------------------
it('Should validate infinite pattern 1', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Number()
])
Assert.IsEqual(Value.Check(T, '1'), true)
Assert.IsEqual(Value.Check(T, '22'), true)
Assert.IsEqual(Value.Check(T, '333'), true)
Assert.IsEqual(Value.Check(T, '4444'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate infinite pattern 2', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Integer()
])
Assert.IsEqual(Value.Check(T, '1'), true)
Assert.IsEqual(Value.Check(T, '22'), true)
Assert.IsEqual(Value.Check(T, '333'), true)
Assert.IsEqual(Value.Check(T, '4444'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate infinite pattern 3', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.BigInt()
])
Assert.IsEqual(Value.Check(T, '1'), true)
Assert.IsEqual(Value.Check(T, '22'), true)
Assert.IsEqual(Value.Check(T, '333'), true)
Assert.IsEqual(Value.Check(T, '4444'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate infinite pattern 4', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.String()
])
Assert.IsEqual(Value.Check(T, '1'), true)
Assert.IsEqual(Value.Check(T, '22'), true)
Assert.IsEqual(Value.Check(T, '333'), true)
Assert.IsEqual(Value.Check(T, '4444'), true)
Assert.IsEqual(Value.Check(T, 'a'), true)
Assert.IsEqual(Value.Check(T, 'bb'), true)
Assert.IsEqual(Value.Check(T, 'ccc'), true)
Assert.IsEqual(Value.Check(T, 'dddd'), true)
})
it('Should validate infinite pattern 5', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A'),
Type.Number()
])
Assert.IsEqual(Value.Check(T, 'A1'), true)
Assert.IsEqual(Value.Check(T, 'A22'), true)
Assert.IsEqual(Value.Check(T, 'A333'), true)
Assert.IsEqual(Value.Check(T, 'A4444'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate infinite pattern 6', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A'),
Type.Integer()
])
Assert.IsEqual(Value.Check(T, 'A1'), true)
Assert.IsEqual(Value.Check(T, 'A22'), true)
Assert.IsEqual(Value.Check(T, 'A333'), true)
Assert.IsEqual(Value.Check(T, 'A4444'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate infinite pattern 7', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A'),
Type.BigInt()
])
Assert.IsEqual(Value.Check(T, 'A1'), true)
Assert.IsEqual(Value.Check(T, 'A22'), true)
Assert.IsEqual(Value.Check(T, 'A333'), true)
Assert.IsEqual(Value.Check(T, 'A4444'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
it('Should validate infinite pattern 8', () => {
// prettier-ignore
const T = Type.TemplateLiteral([
Type.Literal('A'),
Type.String()
])
Assert.IsEqual(Value.Check(T, 'A1'), true)
Assert.IsEqual(Value.Check(T, 'A22'), true)
Assert.IsEqual(Value.Check(T, 'A333'), true)
Assert.IsEqual(Value.Check(T, 'A4444'), true)
Assert.IsEqual(Value.Check(T, 'Aa'), true)
Assert.IsEqual(Value.Check(T, 'Abb'), true)
Assert.IsEqual(Value.Check(T, 'Accc'), true)
Assert.IsEqual(Value.Check(T, 'Adddd'), true)
Assert.IsEqual(Value.Check(T, 'X'), false)
})
})

View File

@@ -0,0 +1,40 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Tuple', () => {
it('Should pass tuple', () => {
const T = Type.Tuple([Type.Number(), Type.Number()])
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail when tuple is less than length', () => {
const T = Type.Tuple([Type.Number(), Type.Number()])
const value = [1]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail when tuple is greater than length', () => {
const T = Type.Tuple([Type.Number(), Type.Number()])
const value = [1, 1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass empty tuple', () => {
const T = Type.Tuple([])
const value = [] as any[]
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail empty tuple', () => {
const T = Type.Tuple([])
const value = [1]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,33 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Uint8Array', () => {
it('Should pass Uint8Array', () => {
const T = Type.Uint8Array()
const value = new Uint8Array(4)
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail Uint8Array', () => {
const T = Type.Uint8Array()
const value = [0, 1, 2, 3]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Uint8Array with undefined', () => {
const T = Type.Uint8Array()
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Uint8Array with null', () => {
const T = Type.Uint8Array()
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Undefined', () => {
const T = Type.Undefined()
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,77 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Union', () => {
const A = Type.Object({
type: Type.Literal('A'),
x: Type.Number(),
y: Type.Number(),
})
const B = Type.Object({
type: Type.Literal('B'),
x: Type.Boolean(),
y: Type.Boolean(),
})
const T = Type.Union([A, B])
it('Should pass union A', () => {
const value = { type: 'A', x: 1, y: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass union B', () => {
const value = { type: 'B', x: true, y: false }
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail union A', () => {
const value = { type: 'A', x: true, y: false }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail union B', () => {
const value = { type: 'B', x: 1, y: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass union A with optional properties', () => {
const A = Type.Object({
type: Type.Literal('A'),
x: Type.Optional(Type.Number()),
y: Type.Optional(Type.Number()),
})
const B = Type.Object({
type: Type.Literal('B'),
x: Type.Boolean(),
y: Type.Boolean(),
})
const T = Type.Union([A, B])
const value = { type: 'A' }
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail union A with invalid optional properties', () => {
const A = Type.Object({
type: Type.Literal('A'),
x: Type.Optional(Type.Number()),
y: Type.Optional(Type.Number()),
})
const B = Type.Object({
type: Type.Literal('B'),
x: Type.Boolean(),
y: Type.Boolean(),
})
const T = Type.Union([A, B])
const value = { type: 'A', x: true, y: false }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Unknown', () => {
const T = Type.Any()
it('Should pass string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should pass Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
})

View File

@@ -0,0 +1,47 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/check/Void', () => {
const T = Type.Void()
it('Should fail string', () => {
const value = 'hello'
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail number', () => {
const value = 1
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail boolean', () => {
const value = true
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass null', () => {
const value = null
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should pass undefined', () => {
const value = undefined
const result = Value.Check(T, value)
Assert.IsEqual(result, true)
})
it('Should fail object', () => {
const value = { a: 1 }
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail array', () => {
const value = [1, 2]
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
it('Should fail Date', () => {
const value = new Date()
const result = Value.Check(T, value)
Assert.IsEqual(result, false)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Any', () => {
it('Should clean 1', () => {
const T = Type.Any()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,21 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Array', () => {
it('Should clean 1', () => {
const T = Type.Any()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean 2', () => {
const T = Type.Array(
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
)
const R = Value.Clean(T, [undefined, null, { x: 1 }, { x: 1, y: 2 }, { x: 1, y: 2, z: 3 }])
Assert.IsEqual(R, [undefined, null, { x: 1 }, { x: 1, y: 2 }, { x: 1, y: 2 }])
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/AsyncIterator', () => {
it('Should clean 1', () => {
const T = Type.AsyncIterator(Type.Number())
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/BigInt', () => {
it('Should clean 1', () => {
const T = Type.BigInt()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Boolean', () => {
it('Should clean 1', () => {
const T = Type.Boolean()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Composite', () => {
it('Should clean 1', () => {
const T = Type.Composite([Type.Object({ x: Type.Number() }), Type.Object({ y: Type.Number() })])
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Constructor', () => {
it('Should clean 1', () => {
const T = Type.Constructor([Type.Object({ x: Type.Number() }), Type.Object({ y: Type.Number() })], Type.Object({ z: Type.Number() }))
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Date', () => {
it('Should clean 1', () => {
const T = Type.Date()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Enum', () => {
it('Should clean 1', () => {
const T = Type.Enum({ x: 1, y: 2 })
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Function', () => {
it('Should clean 1', () => {
const T = Type.Function([Type.Object({ x: Type.Number() }), Type.Object({ y: Type.Number() })], Type.Object({ z: Type.Number() }))
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,203 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Import', () => {
// ----------------------------------------------------------------
// Clean
// ----------------------------------------------------------------
it('Should clean 1', () => {
const T = Type.Module({ A: Type.Object({ x: Type.Number() }) }).Import('A')
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean 2', () => {
const T = Type.Module({ A: Type.Object({ x: Type.Number() }) }).Import('A')
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean 3', () => {
const T = Type.Module({ A: Type.Object({ x: Type.Number() }) }).Import('A')
const R = Value.Clean(T, { x: 1 })
Assert.IsEqual(R, { x: 1 })
})
it('Should clean 4', () => {
const T = Type.Module({ A: Type.Object({ x: Type.Number() }) }).Import('A')
const R = Value.Clean(T, { x: null })
Assert.IsEqual(R, { x: null })
})
// ----------------------------------------------------------------
// Nested
// ----------------------------------------------------------------
it('Should clean nested 1', () => {
const T = Type.Module({
A: Type.Object({
x: Type.Object({
y: Type.Number(),
}),
}),
}).Import('A')
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean nested 2', () => {
const T = Type.Module({
A: Type.Object({
x: Type.Object({
y: Type.Number(),
}),
}),
}).Import('A')
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean nested 3', () => {
const T = Type.Module({
A: Type.Object({
x: Type.Object({
y: Type.Number(),
}),
}),
}).Import('A')
const R = Value.Clean(T, { x: null })
Assert.IsEqual(R, { x: null })
})
it('Should clean nested 4', () => {
const T = Type.Module({
A: Type.Object({
x: Type.Object({
y: Type.Number(),
}),
}),
}).Import('A')
const R = Value.Clean(T, { x: { y: null } })
Assert.IsEqual(R, { x: { y: null } })
})
// ----------------------------------------------------------------
// Additional Properties
// ----------------------------------------------------------------
it('Should clean additional properties 1', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean additional properties 2', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean additional properties 3', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, { x: 1 })
Assert.IsEqual(R, { x: 1 })
})
it('Should clean additional properties 4', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, { x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
// ----------------------------------------------------------------
// Additional Properties Discard
// ----------------------------------------------------------------
it('Should clean additional properties discard 1', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean additional properties discard 2', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, { k: '', d: null })
Assert.IsEqual(R, { k: '' })
})
it('Should clean additional properties discard 3', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, { k: '', d: null, x: 1 })
Assert.IsEqual(R, { k: '', x: 1 })
})
it('Should clean additional properties discard 4', () => {
const T = Type.Module({
A: Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
),
}).Import('A')
const R = Value.Clean(T, { k: '', d: null, x: 1, y: 2 })
Assert.IsEqual(R, { k: '', x: 1, y: 2 })
})
})

View File

@@ -0,0 +1,35 @@
import './any'
import './array'
import './async-iterator'
import './bigint'
import './boolean'
import './composite'
import './constructor'
import './date'
import './enum'
import './function'
import './import'
import './integer'
import './intersect'
import './iterator'
import './keyof'
import './kind'
import './literal'
import './never'
import './not'
import './null'
import './object'
import './promise'
import './record'
import './recursive'
import './ref'
import './regexp'
import './string'
import './symbol'
import './template-literal'
import './tuple'
import './uint8array'
import './undefined'
import './union'
import './unknown'
import './void'

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Integer', () => {
it('Should clean 1', () => {
const T = Type.Integer()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,346 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
// prettier-ignore
describe('value/clean/Intersect', () => {
// ----------------------------------------------------------------
// Intersect
// ----------------------------------------------------------------
it('Should clean 1', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean 2', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean 3', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, { x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
it('Should clean 4', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, { x: 1, y: 2, z: 3 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
// ----------------------------------------------------------------
// Intersect Discard
// ----------------------------------------------------------------
it('Should clean discard 1', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean discard 2', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, { u: null })
Assert.IsEqual(R, {})
})
it('Should clean discard 3', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, { u: null, x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
it('Should clean discard 4', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
])
const R = Value.Clean(T, { u: null, x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
// ----------------------------------------------------------------
// Intersect Deep
// ----------------------------------------------------------------
it('Should clear intersect deep 1', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clear intersect deep 2', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clear intersect deep 3', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { x: 1 })
Assert.IsEqual(R, { x: 1 })
})
it('Should clear intersect deep 4', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
it('Should clear intersect deep 5', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { x: 1, y: 2, z: 3 })
Assert.IsEqual(R, { x: 1, y: 2, z: 3 })
})
it('Should clear intersect deep 6', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { x: 1, y: 2, z: 3, w: 3 })
Assert.IsEqual(R, { x: 1, y: 2, z: 3, w: 3 })
})
it('Should clear intersect deep 7', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { x: 1, y: 2, z: 3, w: 3 })
Assert.IsEqual(R, { x: 1, y: 2, z: 3, w: 3 })
})
// ----------------------------------------------------------------
// Intersect Deep Discard
// ----------------------------------------------------------------
it('Should clear intersect discard deep 1', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clear intersect discard deep 2', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { u: null })
Assert.IsEqual(R, {})
})
it('Should clear intersect discard deep 3', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { u: null, x: 1 })
Assert.IsEqual(R, { x: 1 })
})
it('Should clear intersect discard deep 4', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { u: null, x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
it('Should clear intersect discard deep 5', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { u: null, x: 1, y: 2, z: 3 })
Assert.IsEqual(R, { x: 1, y: 2, z: 3 })
})
it('Should clear intersect discard deep 6', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { u: null, x: 1, y: 2, z: 3, w: 3 })
Assert.IsEqual(R, { x: 1, y: 2, z: 3, w: 3 })
})
it('Should clear intersect discard deep 7', () => {
const T = Type.Intersect([
Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.Number() })
]),
Type.Intersect([
Type.Object({ z: Type.Number() }),
Type.Object({ w: Type.Number() })
])
])
const R = Value.Clean(T, { u: null, x: 1, y: 2, z: 3, w: 3, a: 1 })
Assert.IsEqual(R, { x: 1, y: 2, z: 3, w: 3 })
})
// ----------------------------------------------------------------
// Intersect Invalid
// ----------------------------------------------------------------
it('Should clean intersect invalid 1', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.String() })
])
const R = Value.Clean(T, { x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 }) // types are ignored
})
// ----------------------------------------------------------------
// Intersect Unevaluted Properties
// ----------------------------------------------------------------
it('Should clean intersect unevaluated properties 1', () => {
const T = Type.Intersect([
Type.Object({ x: Type.Number() }),
Type.Object({ y: Type.String() })
], {
unevaluatedProperties: Type.String()
})
const R = Value.Clean(T, { x: 1, y: 2, a: 1, b: '' })
Assert.IsEqual(R, { x: 1, y: 2, b: '' })
})
// ----------------------------------------------------------------
// Intersect Illogical
// ----------------------------------------------------------------
it('Should clean illogical 1', () => {
const T = Type.Intersect([
Type.Number(),
Type.Object({ x: Type.Number() })
])
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean illogical 2', () => {
const T = Type.Intersect([
Type.Number(),
Type.Object({ x: Type.Number() })
])
const R = Value.Clean(T, 1)
Assert.IsEqual(R, 1)
})
it('Should clean illogical 3', () => {
const T = Type.Intersect([
Type.Number(),
Type.Object({ x: Type.Number() })
])
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean illogical 4', () => {
const T = Type.Intersect([
Type.Number(),
Type.Object({ x: Type.Number() })
])
const R = Value.Clean(T, { x: 1 })
Assert.IsEqual(R, { x: 1 })
})
it('Should clean illogical 5', () => {
const T = Type.Intersect([
Type.Number(),
Type.Object({ x: Type.Number() }),
])
const R = Value.Clean(T, { u: null, x: 1 })
Assert.IsEqual(R, { u: null, x: 1 }) // u retained from Number
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Iterator', () => {
it('Should clean 1', () => {
const T = Type.Iterator(Type.String())
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/KeyOf', () => {
it('Should clean 1', () => {
const T = Type.KeyOf(Type.Object({ x: Type.Number(), y: Type.Number() }))
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type, Kind } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Kind', () => {
it('Should clean 1', () => {
const T = Type.Unsafe({ [Kind]: 'Unknown' })
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Literal', () => {
it('Should clean 1', () => {
const T = Type.Literal(1)
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Never', () => {
it('Should clean 1', () => {
const T = Type.Never()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Not', () => {
it('Should clean 1', () => {
const T = Type.Not(Type.Any())
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Null', () => {
it('Should clean 1', () => {
const T = Type.Null()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Number', () => {
it('Should clean 1', () => {
const T = Type.Number()
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,178 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Object', () => {
// ----------------------------------------------------------------
// Clean
// ----------------------------------------------------------------
it('Should clean 1', () => {
const T = Type.Object({ x: Type.Number() })
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean 2', () => {
const T = Type.Object({ x: Type.Number() })
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean 3', () => {
const T = Type.Object({ x: Type.Number() })
const R = Value.Clean(T, { x: 1 })
Assert.IsEqual(R, { x: 1 })
})
it('Should clean 4', () => {
const T = Type.Object({ x: Type.Number() })
const R = Value.Clean(T, { x: null })
Assert.IsEqual(R, { x: null })
})
// ----------------------------------------------------------------
// Nested
// ----------------------------------------------------------------
it('Should clean nested 1', () => {
const T = Type.Object({
x: Type.Object({
y: Type.Number(),
}),
})
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean nested 2', () => {
const T = Type.Object({
x: Type.Object({
y: Type.Number(),
}),
})
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean nested 3', () => {
const T = Type.Object({
x: Type.Object({
y: Type.Number(),
}),
})
const R = Value.Clean(T, { x: null })
Assert.IsEqual(R, { x: null })
})
it('Should clean nested 4', () => {
const T = Type.Object({
x: Type.Object({
y: Type.Number(),
}),
})
const R = Value.Clean(T, { x: { y: null } })
Assert.IsEqual(R, { x: { y: null } })
})
// ----------------------------------------------------------------
// Additional Properties
// ----------------------------------------------------------------
it('Should clean additional properties 1', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean additional properties 2', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean additional properties 3', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, { x: 1 })
Assert.IsEqual(R, { x: 1 })
})
it('Should clean additional properties 4', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, { x: 1, y: 2 })
Assert.IsEqual(R, { x: 1, y: 2 })
})
// ----------------------------------------------------------------
// Additional Properties Discard
// ----------------------------------------------------------------
it('Should clean additional properties discard 1', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean additional properties discard 2', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, { k: '', d: null })
Assert.IsEqual(R, { k: '' })
})
it('Should clean additional properties discard 3', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, { k: '', d: null, x: 1 })
Assert.IsEqual(R, { k: '', x: 1 })
})
it('Should clean additional properties discard 4', () => {
const T = Type.Object(
{
x: Type.Number(),
y: Type.Number(),
},
{
additionalProperties: Type.String(),
},
)
const R = Value.Clean(T, { k: '', d: null, x: 1, y: 2 })
Assert.IsEqual(R, { k: '', x: 1, y: 2 })
})
})

View File

@@ -0,0 +1,11 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Promise', () => {
it('Should clean 1', () => {
const T = Type.Promise(Type.Any())
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
})

View File

@@ -0,0 +1,114 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Record', () => {
// ----------------------------------------------------------------
// Clean
// ----------------------------------------------------------------
it('Should clean 1', () => {
const T = Type.Record(Type.Number(), Type.String())
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean 2', () => {
const T = Type.Record(Type.Number(), Type.String())
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean 3', () => {
const T = Type.Record(Type.Number(), Type.String())
const R = Value.Clean(T, { 0: null })
Assert.IsEqual(R, { 0: null })
})
// ----------------------------------------------------------------
// Clean Discard
// ----------------------------------------------------------------
it('Should clean discard 1', () => {
const T = Type.Record(Type.Number(), Type.String())
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean discard 2', () => {
const T = Type.Record(Type.Number(), Type.String())
const R = Value.Clean(T, { a: 1 })
Assert.IsEqual(R, {})
})
it('Should clean discard 3', () => {
const T = Type.Record(Type.Number(), Type.String())
const R = Value.Clean(T, { a: 1, 0: null })
Assert.IsEqual(R, { 0: null })
})
// ----------------------------------------------------------------
// Additional Properties
// ----------------------------------------------------------------
it('Should clean additional properties 1', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean additional properties 2', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, {})
Assert.IsEqual(R, {})
})
it('Should clean additional properties 3', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, { 0: null })
Assert.IsEqual(R, { 0: null })
})
// ----------------------------------------------------------------
// Additional Properties Discard
// ----------------------------------------------------------------
it('Should clean additional properties discard 1', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean additional properties discard 2', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, { a: null })
Assert.IsEqual(R, {})
})
it('Should clean additional properties discard 3', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, { a: null, 0: null })
Assert.IsEqual(R, { 0: null })
})
// ----------------------------------------------------------------
// Additional Properties Keep
// ----------------------------------------------------------------
it('Should clean additional properties keep 1', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean additional properties keep 2', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, { a: true })
Assert.IsEqual(R, { a: true })
})
it('Should clean additional properties keep 3', () => {
const T = Type.Record(Type.Number(), Type.String(), {
additionalProperties: Type.Boolean(),
})
const R = Value.Clean(T, { a: true, 0: null })
Assert.IsEqual(R, { a: true, 0: null })
})
})

View File

@@ -0,0 +1,112 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Recursive', () => {
// ----------------------------------------------------------------
// Clean
// ----------------------------------------------------------------
it('Should clean 1', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean 2', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { id: null })
Assert.IsEqual(R, { id: null })
})
it('Should clean 3', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { id: null, nodes: null })
Assert.IsEqual(R, { id: null, nodes: null })
})
it('Should clean 4', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { id: null, nodes: [] })
Assert.IsEqual(R, { id: null, nodes: [] })
})
it('Should clean 5', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { id: null, nodes: [{ id: null }] })
Assert.IsEqual(R, { id: null, nodes: [{ id: null }] })
})
// ----------------------------------------------------------------
// Clean Discard
// ----------------------------------------------------------------
it('Should clean discard 1', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, null)
Assert.IsEqual(R, null)
})
it('Should clean discard 2', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { u: null, id: null })
Assert.IsEqual(R, { id: null })
})
it('Should clean discard 3', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { u: null, id: null, nodes: null })
Assert.IsEqual(R, { id: null, nodes: null })
})
it('Should clean discard 4', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { u: null, id: null, nodes: [] })
Assert.IsEqual(R, { id: null, nodes: [] })
})
it('Should clean discard 5', () => {
const T = Type.Recursive((This) =>
Type.Object({
id: Type.String(),
nodes: Type.Array(This),
}),
)
const R = Value.Clean(T, { u: null, id: null, nodes: [{ u: null, id: null }] })
Assert.IsEqual(R, { id: null, nodes: [{ id: null }] })
})
})

View File

@@ -0,0 +1,78 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'
describe('value/clean/Ref', () => {
// ----------------------------------------------------------------
// Clean
// ----------------------------------------------------------------
it('Should clean 1', () => {
const A = Type.Object(
{
x: Type.Number(),
},
{ $id: 'A' },
)
const T = Type.Ref('A')
const R = Value.Clean(T, [A], null)
Assert.IsEqual(R, null)
})
it('Should clean 2', () => {
const A = Type.Object(
{
x: Type.Number(),
},
{ $id: 'A' },
)
const T = Type.Ref('A')
const R = Value.Clean(T, [A], {})
Assert.IsEqual(R, {})
})
it('Should clean 3', () => {
const A = Type.Object(
{
x: Type.Number(),
},
{ $id: 'A' },
)
const T = Type.Ref('A')
const R = Value.Clean(T, [A], { x: null })
Assert.IsEqual(R, { x: null })
})
// ----------------------------------------------------------------
// Clean Discard
// ----------------------------------------------------------------
it('Should clean discard 1', () => {
const A = Type.Object(
{
x: Type.Number(),
},
{ $id: 'A' },
)
const T = Type.Ref('A')
const R = Value.Clean(T, [A], null)
Assert.IsEqual(R, null)
})
it('Should clean discard 2', () => {
const A = Type.Object(
{
x: Type.Number(),
},
{ $id: 'A' },
)
const T = Type.Ref('A')
const R = Value.Clean(T, [A], { a: null })
Assert.IsEqual(R, {})
})
it('Should clean discard 3', () => {
const A = Type.Object(
{
x: Type.Number(),
},
{ $id: 'A' },
)
const T = Type.Ref('A')
const R = Value.Clean(T, [A], { a: null, x: null })
Assert.IsEqual(R, { x: null })
})
})

Some files were not shown because too many files have changed in this diff Show More