From b2960fe9137186e6d7e3e1a1ef7c47abf305382f Mon Sep 17 00:00:00 2001 From: sinclair Date: Tue, 26 Nov 2024 18:54:50 +0900 Subject: [PATCH] Tests --- example/index.ts | 50 +++++++++++++++++++++++++----- readme.md | 9 +++--- src/compiler/compiler.ts | 8 +++++ src/value/parse/parse.ts | 9 +++--- test/runtime/compiler/__members.ts | 20 ++++++++++++ test/runtime/compiler/index.ts | 1 + test/runtime/value/parse/parse.ts | 39 +++++++++++++++++++++-- 7 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 test/runtime/compiler/__members.ts diff --git a/example/index.ts b/example/index.ts index b8c498d02..9d228684a 100644 --- a/example/index.ts +++ b/example/index.ts @@ -1,13 +1,49 @@ import { TypeSystem } from '@sinclair/typebox/system' import { TypeCompiler } from '@sinclair/typebox/compiler' -import { Value, ValuePointer, ParseRegistry } from '@sinclair/typebox/value' +import { Value, ValuePointer } from '@sinclair/typebox/value' import { Parse, StaticParseAsType } from '@sinclair/typebox/syntax' import { Type, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox' -ParseRegistry.Set('Foo', (a, b, c) => c) +// ----------------------------------------------------------- +// Create: Type +// ----------------------------------------------------------- -console.time() -for (let i = 0; i < 1_000_000; i += 1) { - Value.Parse(['Convert', 'Assert', 'Clone'], Type.String(), 1) -} -console.timeEnd() +const T = Type.Object({ + x: Type.Number(), + y: Type.Number(), + z: Type.Number(), +}) + +type T = Static + +console.log(T) + +// ----------------------------------------------------------- +// Parse: Type +// ----------------------------------------------------------- + +const S = Parse({ T }, `{ x: T, y: T, z: T }`) + +type S = Static + +// ----------------------------------------------------------- +// Create: Value +// ----------------------------------------------------------- + +const V = Value.Create(T) + +console.log(V) + +// ----------------------------------------------------------- +// Compile: Type +// ----------------------------------------------------------- + +const C = TypeCompiler.Compile(T) + +console.log(C.Code()) + +// ----------------------------------------------------------- +// Check: Value +// ----------------------------------------------------------- + +console.log(C.Check(V)) diff --git a/readme.md b/readme.md index a6a9448d3..2145c00ef 100644 --- a/readme.md +++ b/readme.md @@ -1325,7 +1325,7 @@ const B = Value.Encode(Type.String(), 42) // throw ### Parse -Use the Parse function to parse a value. The Parse function will internally call a sequence of Value operations in order to parse the value. +Use the Parse function to process a value. The Parse function will call a specific sequence of Value functions (operations) to process the value. ```typescript const R = Value.Parse(Type.String(), 'hello') // const R: string = "hello" @@ -1333,17 +1333,18 @@ const R = Value.Parse(Type.String(), 'hello') // const R: string = "hello" const E = Value.Parse(Type.String(), undefined) // throws AssertError ``` -The default sequence of Value operations is `Clone` `Clean`, `Default`, `Convert`, `Assert` and `Decode`. You can override this sequence in the following way. +The specific sequence of Value operations is `Clone` `Clean`, `Default`, `Convert`, `Assert` and `Decode`. You can specify user defined sequences in the following way. ```typescript -// Will only Assert the value a String +// Same as calling the Assert() function const E = Value.Parse(['Assert'], Type.String(), 12345) -// Will Convert first, then Assert. +// Same as calling the Convert() then Assert() functions. const S = Value.Parse(['Convert', 'Assert'], Type.String(), 12345) ``` +When specifying user defined sequences, the return type of Parse will be unknown. diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index 6e438702b..7450c8aab 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -97,6 +97,14 @@ export class TypeCheck { public Code(): string { return this.code } + /** Returns the schema type used to validate */ + public Schema(): T { + return this.schema + } + /** Returns reference types used to validate */ + public References(): TSchema[] { + return this.references + } /** Returns an iterator for each error in this value. */ public Errors(value: unknown): ValueErrorIterator { return Errors(this.schema, this.references, value) diff --git a/src/value/parse/parse.ts b/src/value/parse/parse.ts index d54e5d1d3..8fa83e48d 100644 --- a/src/value/parse/parse.ts +++ b/src/value/parse/parse.ts @@ -99,14 +99,15 @@ function ParseValue = St // ------------------------------------------------------------------ // Parse // ------------------------------------------------------------------ -/** Parses a value using the specified operations. */ -export function Parse, Result extends Output = Output>(operations: TParseOperation[], schema: Type, references: TSchema[], value: unknown): Result -/** Parses a value using the specified operations. */ -export function Parse, Result extends Output = Output>(operations: TParseOperation[], schema: Type, value: unknown): Result + /** Parses a value using the default parse pipeline. Will throws an `AssertError` if invalid. */ export function Parse, Result extends Output = Output>(schema: Type, references: TSchema[], value: unknown): Result /** Parses a value using the default parse pipeline. Will throws an `AssertError` if invalid. */ export function Parse, Result extends Output = Output>(schema: Type, value: unknown): Result +/** Parses a value using the specified operations. */ +export function Parse(operations: TParseOperation[], schema: Type, references: TSchema[], value: unknown): unknown +/** Parses a value using the specified operations. */ +export function Parse(operations: TParseOperation[], schema: Type, value: unknown): unknown /** Parses a value */ export function Parse(...args: any[]): unknown { // prettier-ignore diff --git a/test/runtime/compiler/__members.ts b/test/runtime/compiler/__members.ts new file mode 100644 index 000000000..6ade7f40b --- /dev/null +++ b/test/runtime/compiler/__members.ts @@ -0,0 +1,20 @@ +import { TypeCompiler } from '@sinclair/typebox/compiler' +import { Type, TypeGuard, ValueGuard } from '@sinclair/typebox' +import { Assert } from '../assert/index' + +describe('compiler/TypeCheckMembers', () => { + it('Should return Schema', () => { + const A = TypeCompiler.Compile(Type.Number(), [Type.String(), Type.Boolean()]) + Assert.IsTrue(TypeGuard.IsNumber(A.Schema())) + }) + it('Should return References', () => { + const A = TypeCompiler.Compile(Type.Number(), [Type.String(), Type.Boolean()]) + Assert.IsTrue(TypeGuard.IsNumber(A.Schema())) + Assert.IsTrue(TypeGuard.IsString(A.References()[0])) + Assert.IsTrue(TypeGuard.IsBoolean(A.References()[1])) + }) + it('Should return Code', () => { + const A = TypeCompiler.Compile(Type.Number(), [Type.String(), Type.Boolean()]) + Assert.IsTrue(ValueGuard.IsString(A.Code())) + }) +}) diff --git a/test/runtime/compiler/index.ts b/test/runtime/compiler/index.ts index 21decd7fa..a39e51760 100644 --- a/test/runtime/compiler/index.ts +++ b/test/runtime/compiler/index.ts @@ -1,3 +1,4 @@ +import './__members' import './any' import './array' import './async-iterator' diff --git a/test/runtime/value/parse/parse.ts b/test/runtime/value/parse/parse.ts index 5c8be9dd7..2bf7106de 100644 --- a/test/runtime/value/parse/parse.ts +++ b/test/runtime/value/parse/parse.ts @@ -1,5 +1,5 @@ -import { Value, AssertError } from '@sinclair/typebox/value' -import { Type } from '@sinclair/typebox' +import { Value, AssertError, ParseRegistry } from '@sinclair/typebox/value' +import { Type, TypeGuard } from '@sinclair/typebox' import { Assert } from '../../assert/index' // prettier-ignore @@ -87,4 +87,39 @@ describe('value/Parse', () => { const X = Value.Parse(T, 'world') Assert.IsEqual(X, 'hello') }) + // ---------------------------------------------------------------- + // Operations + // ---------------------------------------------------------------- + it('Should run operations 1', () => { + const A = Type.Object({ x: Type.Number() }) + const I = { x: 1 } + const O = Value.Parse([], A, I) + Assert.IsTrue(I === O) + }) + it('Should run operations 2', () => { + const A = Type.Object({ x: Type.Number() }) + const I = { x: 1 } + const O = Value.Parse(['Clone'], A, I) + Assert.IsTrue(I !== O) + }) + it('Should run operations 3', () => { + ParseRegistry.Set('Intercept', ( schema, references, value) => { throw 1 }) + const A = Type.Object({ x: Type.Number() }) + Assert.Throws(() => Value.Parse(['Intercept'], A, null)) + ParseRegistry.Delete('Intercept') + const F = ParseRegistry.Get('Intercept') + Assert.IsEqual(F, undefined) + }) + it('Should run operations 4', () => { + ParseRegistry.Set('Intercept', ( schema, references, value) => { + Assert.IsEqual(value, 12345) + Assert.IsTrue(TypeGuard.IsNumber(schema)) + Assert.IsTrue(TypeGuard.IsString(references[0])) + }) + Value.Parse(['Intercept'], Type.Number(), [Type.String()], 12345) + ParseRegistry.Delete('Intercept') + }) + it('Should run operations 5', () => { + Assert.Throws(() => Value.Parse(['Intercept'], Type.String(), null)) + }) })