diff --git a/hammer.mjs b/hammer.mjs index c99da14f9..76e8ea38e 100644 --- a/hammer.mjs +++ b/hammer.mjs @@ -36,7 +36,7 @@ export async function benchmark() { // Test // ------------------------------------------------------------------------------- export async function test_typescript() { - for (const version of ['4.9.5', '5.0.4', '5.1.3', '5.1.6', 'next', 'latest']) { + for (const version of ['4.9.5', '5.0.4', '5.1.3', '5.1.6', '5.2.2', 'next', 'latest']) { await shell(`npm install typescript@${version} --no-save`) await test_static() } diff --git a/package-lock.json b/package-lock.json index 2b0ccba85..283e9a681 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@sinclair/typebox", - "version": "0.31.2", + "version": "0.31.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@sinclair/typebox", - "version": "0.31.2", + "version": "0.31.3", "license": "MIT", "devDependencies": { "@sinclair/hammer": "^0.17.1", @@ -16,7 +16,7 @@ "ajv-formats": "^2.1.1", "mocha": "^9.2.2", "prettier": "^2.7.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } }, "node_modules/@esbuild/android-arm": { @@ -1334,9 +1334,9 @@ } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -2304,9 +2304,9 @@ } }, "typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true }, "uri-js": { diff --git a/package.json b/package.json index 7b85f51eb..7ceb60964 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/typebox", - "version": "0.31.2", + "version": "0.31.3", "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript", "keywords": [ "typescript", @@ -59,6 +59,6 @@ "ajv-formats": "^2.1.1", "mocha": "^9.2.2", "prettier": "^2.7.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/readme.md b/readme.md index 582456434..05345fec0 100644 --- a/readme.md +++ b/readme.md @@ -60,7 +60,7 @@ type T = Static // type T = { TypeBox is a runtime type builder that creates Json Schema objects that infer as TypeScript types. The schemas produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox offers a unified type that can be statically checked by TypeScript or runtime checked using standard Json Schema validation. -TypeBox is built upon industry standard specifications. It offers reflectable, serializable and publishable types as standard, a fully extensible type system capable of supporting multiple schema specifications, includes a high performance validation compiler, offers various tools for working with dynamic data and provides detailed structured error reporting. +TypeBox types are designed to express industry standard schematics as TypeScript types. All types are runtime reflectable, serializable and publishable by default. It includes an extensible type system able to represent type safe schematics for multiple schema specifications. It also provides a high performance validation compiler, various tools for working with dynamic data and offers detailed structured error reporting. TypeBox can be used as a simple tool to build up complex schemas or integrated into applications to enable high performance runtime validation for data received over the wire. @@ -949,7 +949,7 @@ const U = Type.Union(R) // const U = { ### Transform Types -TypeBox supports bi-directional decode and encode with Transform types. These types are designed to operate with the Value and TypeCompiler Encode and Decode functions. Transform types are useful to convert Json encoded values into constructs more natural to JavaScript. The following creates a Transform type to convert between Date and number using the Value module. +TypeBox supports value decoding and encoding with Transform types. These types work in tandem with the Encode and Decode functions available on the Value and TypeCompiler modules. Transform types can be used to convert Json encoded values into constructs more natural to JavaScript. The following creates a Transform type to decode numbers into Dates using the Value module. ```typescript import { Value } from '@sinclair/typebox/value' @@ -1604,13 +1604,16 @@ The following is a list of community packages that offer general tooling, extend | Package | Description | | ------------- | ------------- | +| [drizzle-typebox](https://www.npmjs.com/package/drizzle-typebox) | Generates TypeBox types from Drizzle ORM schemas | | [elysia](https://github.com/elysiajs/elysia) | Fast and friendly Bun web framework | | [fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox) | Fastify TypeBox integration with the Fastify Type Provider | | [feathersjs](https://github.com/feathersjs/feathers) | The API and real-time application framework | | [fetch-typebox](https://github.com/erfanium/fetch-typebox) | Drop-in replacement for fetch that brings easy integration with TypeBox | +| [h3-typebox](https://github.com/kevinmarrec/h3-typebox) | Schema validation utilities for h3 using TypeBox & Ajv | | [schema2typebox](https://github.com/xddq/schema2typebox) | Creating TypeBox code from Json Schemas | | [ts2typebox](https://github.com/xddq/ts2typebox) | Creating TypeBox code from Typescript types | | [typebox-client](https://github.com/flodlc/typebox-client) | Type safe http client library for Fastify | +| [typebox-form-parser](https://github.com/jtlapp/typebox-form-parser) | Parses form and query data based on TypeBox schemas | | [typebox-validators](https://github.com/jtlapp/typebox-validators) | Advanced validators supporting discriminated and heterogeneous unions | diff --git a/test/runtime/compiler/record.ts b/test/runtime/compiler/record.ts index cd9322b08..89368d724 100644 --- a/test/runtime/compiler/record.ts +++ b/test/runtime/compiler/record.ts @@ -85,7 +85,7 @@ describe('compiler/Record', () => { const R = Type.Record(Type.KeyOf(T), Type.Number(), { additionalProperties: false }) Fail(R, { a: 1, b: 2, c: 3, d: 4 }) }) - it('Should should validate when specifying regular expressions', () => { + it('Should validate when specifying regular expressions', () => { const K = Type.RegExp(/^op_.*$/) const T = Type.Record(K, Type.Number()) Ok(T, { @@ -94,7 +94,7 @@ describe('compiler/Record', () => { op_c: 3, }) }) - it('Should should not validate when specifying regular expressions and passing invalid property', () => { + 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 }) Fail(T, { @@ -103,6 +103,24 @@ describe('compiler/Record', () => { aop_c: 3, }) }) + it('Should validate with quoted string pattern', () => { + const K = Type.String({ pattern: "'(a|b|c)" }) + const T = Type.Record(K, Type.Number()) + Ok(T, { + "'a": 1, + "'b": 2, + "'c": 3, + }) + }) + it('Should validate with forward-slash pattern', () => { + const K = Type.String({ pattern: '/(a|b|c)' }) + const T = Type.Record(K, Type.Number()) + Ok(T, { + '/a': 1, + '/b': 2, + '/c': 3, + }) + }) // ------------------------------------------------------------ // Integer Keys // ------------------------------------------------------------ diff --git a/test/runtime/index.ts b/test/runtime/index.ts index 5a8bca7ab..8f53de837 100644 --- a/test/runtime/index.ts +++ b/test/runtime/index.ts @@ -1,6 +1,6 @@ import './compiler/index' -import './errors/index' import './schema/index' +import './errors/index' import './system/index' import './type/index' import './value/index' diff --git a/test/runtime/schema/any.ts b/test/runtime/schema/any.ts index 3e857c831..695113f09 100644 --- a/test/runtime/schema/any.ts +++ b/test/runtime/schema/any.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok } from './validate' -describe('type/schema/Any', () => { +describe('compiler-ajv/Any', () => { it('Should validate number', () => { const T = Type.Any() Ok(T, 1) diff --git a/test/runtime/schema/array.ts b/test/runtime/schema/array.ts index d20e504c4..dd9feaea4 100644 --- a/test/runtime/schema/array.ts +++ b/test/runtime/schema/array.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Array', () => { +describe('compiler-ajv/Array', () => { it('Should validate an array of any', () => { const T = Type.Array(Type.Any()) Ok(T, [0, true, 'hello', {}]) diff --git a/test/runtime/schema/boolean.ts b/test/runtime/schema/boolean.ts index f8f75a55e..6ff4f7861 100644 --- a/test/runtime/schema/boolean.ts +++ b/test/runtime/schema/boolean.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Boolean', () => { +describe('compiler-ajv/Boolean', () => { it('Should validate a boolean', () => { const T = Type.Boolean() Ok(T, true) diff --git a/test/runtime/schema/composite.ts b/test/runtime/schema/composite.ts index 23e5d1055..41e8a8ac9 100644 --- a/test/runtime/schema/composite.ts +++ b/test/runtime/schema/composite.ts @@ -2,7 +2,7 @@ import { Type } from '@sinclair/typebox' import { Assert } from '../assert' import { Ok, Fail } from './validate' -describe('type/schema/Composite', () => { +describe('compiler-ajv/Composite', () => { it('Should compose two objects', () => { const A = Type.Object({ a: Type.String() }) const B = Type.Object({ b: Type.Number() }) diff --git a/test/runtime/schema/date.ts b/test/runtime/schema/date.ts index 659c704b9..f5f8e12fc 100644 --- a/test/runtime/schema/date.ts +++ b/test/runtime/schema/date.ts @@ -10,7 +10,7 @@ // which are configured to use Value.Check() // ---------------------------------------------------- -// describe('type/schema/Date', () => { +// describe('compiler-ajv/Date', () => { // it('Should not validate number', () => { // const T = Type.Date() // Fail(T, 1) diff --git a/test/runtime/schema/enum.ts b/test/runtime/schema/enum.ts index 910e16e27..c4599be98 100644 --- a/test/runtime/schema/enum.ts +++ b/test/runtime/schema/enum.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Enum', () => { +describe('compiler-ajv/Enum', () => { it('Should validate when emum uses default numeric values', () => { enum Kind { Foo, // = 0 diff --git a/test/runtime/schema/integer.ts b/test/runtime/schema/integer.ts index 5d984691f..664eacf7b 100644 --- a/test/runtime/schema/integer.ts +++ b/test/runtime/schema/integer.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Integer', () => { +describe('compiler-ajv/Integer', () => { it('Should not validate number', () => { const T = Type.Integer() Fail(T, 3.14) diff --git a/test/runtime/schema/intersect.ts b/test/runtime/schema/intersect.ts index 5e4b64a4f..00fe0ac1a 100644 --- a/test/runtime/schema/intersect.ts +++ b/test/runtime/schema/intersect.ts @@ -1,7 +1,7 @@ import { Type, Static } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Intersect', () => { +describe('compiler-ajv/Intersect', () => { it('Should intersect number and number', () => { const A = Type.Number() const B = Type.Number() diff --git a/test/runtime/schema/keyof.ts b/test/runtime/schema/keyof.ts index 17b36914f..0734a2f93 100644 --- a/test/runtime/schema/keyof.ts +++ b/test/runtime/schema/keyof.ts @@ -1,8 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -import { strictEqual } from 'assert' -describe('type/schema/KeyOf', () => { +describe('compiler-ajv/KeyOf', () => { it('Should validate with all object keys as a kind of union', () => { const T = Type.KeyOf( Type.Object({ diff --git a/test/runtime/schema/literal.ts b/test/runtime/schema/literal.ts index d14d5b784..a41d69044 100644 --- a/test/runtime/schema/literal.ts +++ b/test/runtime/schema/literal.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Literal', () => { +describe('compiler-ajv/Literal', () => { it('Should validate literal number', () => { const T = Type.Literal(42) Ok(T, 42) diff --git a/test/runtime/schema/never.ts b/test/runtime/schema/never.ts index 8a3f6e386..49904f4eb 100644 --- a/test/runtime/schema/never.ts +++ b/test/runtime/schema/never.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Fail } from './validate' -describe('type/schema/Never', () => { +describe('compiler-ajv/Never', () => { it('Should not validate number', () => { const T = Type.Never() Fail(T, 1) diff --git a/test/runtime/schema/not.ts b/test/runtime/schema/not.ts index 491de05b4..013cf28a5 100644 --- a/test/runtime/schema/not.ts +++ b/test/runtime/schema/not.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Not', () => { +describe('compiler-ajv/Not', () => { it('Should validate not number', () => { const T = Type.Not(Type.Number()) Fail(T, 1) diff --git a/test/runtime/schema/null.ts b/test/runtime/schema/null.ts index b338d78eb..4947b0cf9 100644 --- a/test/runtime/schema/null.ts +++ b/test/runtime/schema/null.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Null', () => { +describe('compiler-ajv/Null', () => { it('Should not validate number', () => { const T = Type.Null() Fail(T, 1) diff --git a/test/runtime/schema/number.ts b/test/runtime/schema/number.ts index 880a85e4a..30dd7fb8a 100644 --- a/test/runtime/schema/number.ts +++ b/test/runtime/schema/number.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Number', () => { +describe('compiler-ajv/Number', () => { it('Should validate number', () => { const T = Type.Number() Ok(T, 3.14) diff --git a/test/runtime/schema/object.ts b/test/runtime/schema/object.ts index cabe95979..c096bc546 100644 --- a/test/runtime/schema/object.ts +++ b/test/runtime/schema/object.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Object', () => { +describe('compiler-ajv/Object', () => { it('Should not validate a number', () => { const T = Type.Object({}) Fail(T, 42) diff --git a/test/runtime/schema/omit.ts b/test/runtime/schema/omit.ts index 7a1d6e108..0053c6808 100644 --- a/test/runtime/schema/omit.ts +++ b/test/runtime/schema/omit.ts @@ -2,7 +2,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' import { strictEqual } from 'assert' -describe('type/schema/Omit', () => { +describe('compiler-ajv/Omit', () => { it('Should omit properties on the source schema', () => { const A = Type.Object( { diff --git a/test/runtime/schema/optional.ts b/test/runtime/schema/optional.ts index 298550f73..a5d39dd6f 100644 --- a/test/runtime/schema/optional.ts +++ b/test/runtime/schema/optional.ts @@ -2,7 +2,7 @@ import { strictEqual } from 'assert' import { Type } from '@sinclair/typebox' import { Ok } from './validate' -describe('type/schema/Optional', () => { +describe('compiler-ajv/Optional', () => { it('Should validate object with optional', () => { const T = Type.Object( { diff --git a/test/runtime/schema/partial.ts b/test/runtime/schema/partial.ts index c28f1368e..5e56d704a 100644 --- a/test/runtime/schema/partial.ts +++ b/test/runtime/schema/partial.ts @@ -1,8 +1,8 @@ import { Type, Readonly, Optional } from '@sinclair/typebox' -import { Ok, Fail } from './validate' -import { strictEqual } from 'assert' +import { Ok } from './validate' +import { Assert } from '../assert' -describe('type/schema/Partial', () => { +describe('compiler-ajv/Partial', () => { it('Should convert a required object into a partial.', () => { const A = Type.Object( { @@ -29,12 +29,12 @@ describe('type/schema/Partial', () => { { additionalProperties: false }, ) const T = Type.Partial(A) - strictEqual(T.properties.x[Readonly], 'Readonly') - strictEqual(T.properties.x[Optional], 'Optional') - strictEqual(T.properties.y[Readonly], 'Readonly') - strictEqual(T.properties.y[Optional], 'Optional') - strictEqual(T.properties.z[Optional], 'Optional') - strictEqual(T.properties.w[Optional], 'Optional') + Assert.IsEqual(T.properties.x[Readonly], 'Readonly') + Assert.IsEqual(T.properties.x[Optional], 'Optional') + Assert.IsEqual(T.properties.y[Readonly], 'Readonly') + Assert.IsEqual(T.properties.y[Optional], 'Optional') + Assert.IsEqual(T.properties.z[Optional], 'Optional') + Assert.IsEqual(T.properties.w[Optional], 'Optional') }) it('Should inherit options from the source object', () => { const A = Type.Object( @@ -46,7 +46,7 @@ describe('type/schema/Partial', () => { { additionalProperties: false }, ) const T = Type.Partial(A) - strictEqual(A.additionalProperties, false) - strictEqual(T.additionalProperties, false) + Assert.IsEqual(A.additionalProperties, false) + Assert.IsEqual(T.additionalProperties, false) }) }) diff --git a/test/runtime/schema/pick.ts b/test/runtime/schema/pick.ts index 39dde3a06..e9c09c700 100644 --- a/test/runtime/schema/pick.ts +++ b/test/runtime/schema/pick.ts @@ -1,8 +1,8 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -import { strictEqual } from 'assert' +import { Assert } from '../assert' -describe('type/schema/Pick', () => { +describe('compiler-ajv/Pick', () => { it('Should pick properties from the source schema', () => { const Vector3 = Type.Object( { @@ -25,7 +25,7 @@ describe('type/schema/Pick', () => { { additionalProperties: false }, ) const T = Type.Pick(A, ['x', 'y']) - strictEqual(T.required!.includes('z'), false) + Assert.IsEqual(T.required!.includes('z'), false) }) it('Should delete the required property if no required properties remain', () => { const A = Type.Object( @@ -37,7 +37,7 @@ describe('type/schema/Pick', () => { { additionalProperties: false }, ) const T = Type.Pick(A, ['x', 'y']) - strictEqual(T.required, undefined) + Assert.IsEqual(T.required, undefined) }) it('Should inherit options from the source object', () => { const A = Type.Object( @@ -49,8 +49,8 @@ describe('type/schema/Pick', () => { { additionalProperties: false }, ) const T = Type.Pick(A, ['x', 'y']) - strictEqual(A.additionalProperties, false) - strictEqual(T.additionalProperties, false) + Assert.IsEqual(A.additionalProperties, false) + Assert.IsEqual(T.additionalProperties, false) }) it('Should pick with keyof object', () => { const A = Type.Object({ diff --git a/test/runtime/schema/readonly-optional.ts b/test/runtime/schema/readonly-optional.ts index 6025c3cf1..cbdd883ff 100644 --- a/test/runtime/schema/readonly-optional.ts +++ b/test/runtime/schema/readonly-optional.ts @@ -1,8 +1,8 @@ import { Type } from '@sinclair/typebox' -import { Ok, Fail } from './validate' -import { strictEqual } from 'assert' +import { Ok } from './validate' +import { Assert } from '../assert' -describe('type/schema/ReadonlyOptional', () => { +describe('compiler-ajv/ReadonlyOptional', () => { it('Should validate object with optional', () => { const T = Type.Object( { @@ -22,6 +22,6 @@ describe('type/schema/ReadonlyOptional', () => { }, { additionalProperties: false }, ) - strictEqual(T.required!.includes('a'), false) + Assert.IsEqual(T.required!.includes('a'), false) }) }) diff --git a/test/runtime/schema/readonly.ts b/test/runtime/schema/readonly.ts index a651d3af3..c26dd62f6 100644 --- a/test/runtime/schema/readonly.ts +++ b/test/runtime/schema/readonly.ts @@ -1,8 +1,8 @@ -import { deepStrictEqual, strictEqual } from 'assert' import { Type } from '@sinclair/typebox' -import { Ok, Fail } from './validate' +import { Ok } from './validate' +import { Assert } from '../assert' -describe('type/schema/Readonly', () => { +describe('compiler-ajv/Readonly', () => { it('Should validate object with readonly', () => { const T = Type.Object( { @@ -21,7 +21,7 @@ describe('type/schema/Readonly', () => { }, { additionalProperties: false }, ) - strictEqual(T.required!.includes('a'), true) - strictEqual(T.required!.includes('b'), true) + Assert.IsEqual(T.required!.includes('a'), true) + Assert.IsEqual(T.required!.includes('b'), true) }) }) diff --git a/test/runtime/schema/record.ts b/test/runtime/schema/record.ts index 6a6ba818c..082a58fb2 100644 --- a/test/runtime/schema/record.ts +++ b/test/runtime/schema/record.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Record', () => { +describe('compiler-ajv/Record', () => { it('Should validate when all property values are numbers', () => { const T = Type.Record(Type.String(), Type.Number()) Ok(T, { a: 1, b: 2, c: 3 }) @@ -54,7 +54,7 @@ describe('type/schema/Record', () => { const R = Type.Record(Type.KeyOf(T), Type.Number(), { additionalProperties: false }) Fail(R, { a: 1, b: 2, c: 3, d: 4 }) }) - it('Should should validate when specifying regular expressions', () => { + it('Should validate when specifying regular expressions', () => { const K = Type.RegExp(/^op_.*$/) const T = Type.Record(K, Type.Number()) Ok(T, { @@ -63,7 +63,7 @@ describe('type/schema/Record', () => { op_c: 3, }) }) - it('Should should not validate when specifying regular expressions and passing invalid property', () => { + 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 }) Fail(T, { @@ -72,6 +72,24 @@ describe('type/schema/Record', () => { aop_c: 3, }) }) + it('Should validate with quoted string pattern', () => { + const K = Type.String({ pattern: "'(a|b|c)" }) + const T = Type.Record(K, Type.Number()) + Ok(T, { + "'a": 1, + "'b": 2, + "'c": 3, + }) + }) + it('Should validate with forward-slash pattern', () => { + const K = Type.String({ pattern: '/(a|b|c)' }) + const T = Type.Record(K, Type.Number()) + Ok(T, { + '/a': 1, + '/b': 2, + '/c': 3, + }) + }) // ------------------------------------------------------------ // Integer Keys // ------------------------------------------------------------ diff --git a/test/runtime/schema/recursive.ts b/test/runtime/schema/recursive.ts index b2f90d756..0a04dc313 100644 --- a/test/runtime/schema/recursive.ts +++ b/test/runtime/schema/recursive.ts @@ -1,8 +1,8 @@ import { Type } from '@sinclair/typebox' -import { Assert } from '../assert/index' import { Ok, Fail } from './validate' +import { Assert } from '../assert/index' -describe('type/schema/Recursive', () => { +describe('compiler-ajv/Recursive', () => { it('Should generate default ordinal $id if not specified', () => { const Node = Type.Recursive((Node) => Type.Object({ @@ -10,7 +10,7 @@ describe('type/schema/Recursive', () => { nodes: Type.Array(Node), }), ) - Assert.IsEqual(Node.$id === undefined, false) + Assert.IsFalse(Node.$id === undefined) }) it('Should override default ordinal $id if specified', () => { const Node = Type.Recursive( diff --git a/test/runtime/schema/ref.ts b/test/runtime/schema/ref.ts index a3d522f89..d9bf5c954 100644 --- a/test/runtime/schema/ref.ts +++ b/test/runtime/schema/ref.ts @@ -1,8 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -import { Assert } from '../assert/index' -describe('type/schema/Ref', () => { +describe('compiler-ajv/Ref', () => { it('Should should validate when referencing a type', () => { const T = Type.Object( { diff --git a/test/runtime/schema/regexp.ts b/test/runtime/schema/regexp.ts index 643b43b81..dcfae6e8d 100644 --- a/test/runtime/schema/regexp.ts +++ b/test/runtime/schema/regexp.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/RegExp', () => { +describe('compiler-ajv/RegExp', () => { //----------------------------------------------------- // Regular Expression //----------------------------------------------------- diff --git a/test/runtime/schema/required.ts b/test/runtime/schema/required.ts index 19ab20f5c..7df4b1875 100644 --- a/test/runtime/schema/required.ts +++ b/test/runtime/schema/required.ts @@ -1,8 +1,8 @@ import { Type, Readonly, Optional } from '@sinclair/typebox' import { Ok, Fail } from './validate' -import { strictEqual } from 'assert' +import { Assert } from '../assert' -describe('type/schema/Required', () => { +describe('compiler-ajv/Required', () => { it('Should convert a partial object into a required object', () => { const A = Type.Object( { @@ -26,10 +26,10 @@ describe('type/schema/Required', () => { w: Type.Number(), }) const T = Type.Required(A) - strictEqual(T.properties.x[Readonly], 'Readonly') - strictEqual(T.properties.y[Readonly], 'Readonly') - strictEqual(T.properties.z[Optional], undefined) - strictEqual(T.properties.w[Optional], undefined) + Assert.IsEqual(T.properties.x[Readonly], 'Readonly') + Assert.IsEqual(T.properties.y[Readonly], 'Readonly') + Assert.IsEqual(T.properties.z[Optional], undefined) + Assert.IsEqual(T.properties.w[Optional], undefined) }) it('Should inherit options from the source object', () => { const A = Type.Object( @@ -41,8 +41,8 @@ describe('type/schema/Required', () => { { additionalPropeties: false }, ) const T = Type.Required(A) - strictEqual(A.additionalPropeties, false) - strictEqual(T.additionalPropeties, false) + Assert.IsEqual(A.additionalPropeties, false) + Assert.IsEqual(T.additionalPropeties, false) }) // it('Should construct new object when targetting reference', () => { // const T = Type.Object({ a: Type.String(), b: Type.String() }, { $id: 'T' }) diff --git a/test/runtime/schema/string.ts b/test/runtime/schema/string.ts index 73b62efa2..33729175e 100644 --- a/test/runtime/schema/string.ts +++ b/test/runtime/schema/string.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/String', () => { +describe('compiler-ajv/String', () => { it('Should not validate number', () => { const T = Type.String() Fail(T, 1) diff --git a/test/runtime/schema/template-literal.ts b/test/runtime/schema/template-literal.ts index 80c862b58..ad083a50b 100644 --- a/test/runtime/schema/template-literal.ts +++ b/test/runtime/schema/template-literal.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/TemplateLiteral', () => { +describe('compiler-ajv/TemplateLiteral', () => { // -------------------------------------------------------- // Finite // -------------------------------------------------------- diff --git a/test/runtime/schema/tuple.ts b/test/runtime/schema/tuple.ts index 22f9999dc..96dfc1aa3 100644 --- a/test/runtime/schema/tuple.ts +++ b/test/runtime/schema/tuple.ts @@ -1,8 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -import { Assert } from '../assert' -describe('type/schema/Tuple', () => { +describe('compiler-ajv/Tuple', () => { it('Should validate tuple of [string, number]', () => { const A = Type.String() const B = Type.Number() diff --git a/test/runtime/schema/uint8array.ts b/test/runtime/schema/uint8array.ts index 96e2dd39c..b50979504 100644 --- a/test/runtime/schema/uint8array.ts +++ b/test/runtime/schema/uint8array.ts @@ -3,7 +3,7 @@ // --------------------------------------------------- // import { Type } from '@sinclair/typebox' // import { Ok, Fail } from './validate' -// describe('type/schema/Uint8Array', () => { +// describe('compiler-ajv/Uint8Array', () => { // it('Should not validate number', () => { // const T = Type.Uint8Array() // Fail(T, 1) diff --git a/test/runtime/schema/union.ts b/test/runtime/schema/union.ts index fc6493c91..ab18c1e18 100644 --- a/test/runtime/schema/union.ts +++ b/test/runtime/schema/union.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Union', () => { +describe('compiler-ajv/Union', () => { it('Should validate union of string, number and boolean', () => { const A = Type.String() const B = Type.Number() diff --git a/test/runtime/schema/unknown.ts b/test/runtime/schema/unknown.ts index 2bc681767..8ad7cfacf 100644 --- a/test/runtime/schema/unknown.ts +++ b/test/runtime/schema/unknown.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' -import { Ok, Fail } from './validate' +import { Ok } from './validate' -describe('type/schema/Unknown', () => { +describe('compiler-ajv/Unknown', () => { it('Should validate number', () => { const T = Type.Any() Ok(T, 1) diff --git a/test/runtime/schema/unsafe.ts b/test/runtime/schema/unsafe.ts index 509d2d4fb..6a53eea0a 100644 --- a/test/runtime/schema/unsafe.ts +++ b/test/runtime/schema/unsafe.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Unsafe', () => { +describe('compiler-ajv/Unsafe', () => { it('Should validate an unsafe type', () => { const T = Type.Unsafe({ type: 'object', diff --git a/test/runtime/schema/void.ts b/test/runtime/schema/void.ts index 1aab66be4..547ead1ae 100644 --- a/test/runtime/schema/void.ts +++ b/test/runtime/schema/void.ts @@ -1,7 +1,7 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' -describe('type/schema/Void', () => { +describe('compiler-ajv/Void', () => { it('Should not validate number', () => { const T = Type.Void() Fail(T, 1) diff --git a/test/runtime/value/check/record.ts b/test/runtime/value/check/record.ts index c6e04ce8d..2e4bd7362 100644 --- a/test/runtime/value/check/record.ts +++ b/test/runtime/value/check/record.ts @@ -121,6 +121,46 @@ describe('value/check/Record', () => { 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 // ------------------------------------------------- diff --git a/test/static/transform.ts b/test/static/transform.ts index 99e7e067a..3e02df125 100644 --- a/test/static/transform.ts +++ b/test/static/transform.ts @@ -182,3 +182,35 @@ import { Expect } from './assert' // z: number; // } // lol } +{ + // ensure decode as optional + // prettier-ignore + const T = Type.Object({ + x: Type.Optional(Type.Number()), + y: Type.Optional(Type.Number()) + }) + Expect(T).ToStaticDecode<{ x: undefined; y: undefined }>() + Expect(T).ToStaticDecode<{ x: 1; y: 1 }>() +} +{ + // ensure decode as readonly + // prettier-ignore + const T = Type.Object({ + x: Type.Readonly(Type.Number()), + y: Type.Readonly(Type.Number()) + }) + Expect(T).ToStaticDecode<{ readonly x: 1; readonly y: 1 }>() +} +{ + // ensure decode as optional union + // prettier-ignore + const T = Type.Object({ + x: Type.Optional(Type.Union([ + Type.String(), + Type.Number() + ])) + }) + Expect(T).ToStaticDecode<{ x: 1 }>() + Expect(T).ToStaticDecode<{ x: '1' }>() + Expect(T).ToStaticDecode<{ x: undefined }>() +}