Skip to content

Commit 16f6551

Browse files
authored
TypeBox 0.25.0 (#271)
1 parent d0faeab commit 16f6551

116 files changed

Lines changed: 1834 additions & 373 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1+
## [0.25.0](https://www.npmjs.com/package/@sinclair/typebox/v/0.25.0)
2+
3+
Updates:
4+
5+
- [271](https://github.com/sinclairzx81/typebox/pull/271) Adds a new non-standard `Type.Date()` type. This type joins the existing `Type.UInt8Array()` as a promoted extended type used to represent core JavaScript primitives. It's inclusion was prompted by end user requirements to validate Date objects prior to writing them to Date supported API's and where serialization of the Date object is handled internally by the API.
6+
7+
- [271](https://github.com/sinclairzx81/typebox/pull/271) Redesign of Extended Type representations. Extended types been updated to provide external validators (such as Ajv) additional standard proporties to use when defining the custom schema. These properties are `instanceOf` (used for validating a class `object` instances), and `typeOf` (when validating `value` types). Information on configuring Ajv for these properties can be found in the Ajv section of the TypeBox readme.
8+
19
## [0.24.49](https://www.npmjs.com/package/@sinclair/typebox/v/0.24.49)
210

311
Updates:
12+
413
- [264](https://github.com/sinclairzx81/typebox/pull/264) TypeBox now provides preliminary support for non-boolean `additionalProperties`. This allows existing `TObject` schemas to be augmented with additional properties of a known type.
514

615
Additional:

example/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Conditional } from '@sinclair/typebox/conditional'
44
import { TypeGuard } from '@sinclair/typebox/guard'
55
import { Format } from '@sinclair/typebox/format'
66
import { Value, ValuePointer } from '@sinclair/typebox/value'
7-
import { Type, Static } from '@sinclair/typebox'
7+
import { Type, Static, TSchema } from '@sinclair/typebox'
88

99
const T = Type.Object({
1010
x: Type.Number(),

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sinclair/typebox",
3-
"version": "0.24.51",
3+
"version": "0.25.0",
44
"description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
55
"keywords": [
66
"typescript",

readme.md

Lines changed: 245 additions & 161 deletions
Large diffs are not rendered by default.

src/compiler/compiler.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class TypeCheck<T extends Types.TSchema> {
5454
return ValueErrors.Errors(this.schema, this.references, value)
5555
}
5656

57-
/** Returns true if the value matches the given type. */
57+
/** Returns true if the value matches the compiled type. */
5858
public Check(value: unknown): value is Types.Static<T> {
5959
return this.checkFunc(value)
6060
}
@@ -132,11 +132,19 @@ export namespace TypeCompiler {
132132
yield* Visit(schema.returns, `${value}.prototype`)
133133
}
134134

135+
function* Date(schema: Types.TDate, value: string): IterableIterator<string> {
136+
yield `(${value} instanceof Date)`
137+
if (schema.exclusiveMinimumTimestamp !== undefined) yield `(${value}.getTime() > ${schema.exclusiveMinimumTimestamp})`
138+
if (schema.exclusiveMaximumTimestamp !== undefined) yield `(${value}.getTime() < ${schema.exclusiveMaximumTimestamp})`
139+
if (schema.minimumTimestamp !== undefined) yield `(${value}.getTime() >= ${schema.minimumTimestamp})`
140+
if (schema.maximumTimestamp !== undefined) yield `(${value}.getTime() <= ${schema.maximumTimestamp})`
141+
}
142+
135143
function* Function(schema: Types.TFunction, value: string): IterableIterator<string> {
136144
yield `(typeof ${value} === 'function')`
137145
}
138146

139-
function* Integer(schema: Types.TNumeric, value: string): IterableIterator<string> {
147+
function* Integer(schema: Types.TInteger, value: string): IterableIterator<string> {
140148
yield `(typeof ${value} === 'number' && Number.isInteger(${value}))`
141149
if (schema.multipleOf !== undefined) yield `(${value} % ${schema.multipleOf} === 0)`
142150
if (schema.exclusiveMinimum !== undefined) yield `(${value} > ${schema.exclusiveMinimum})`
@@ -161,7 +169,7 @@ export namespace TypeCompiler {
161169
yield `(${value} === null)`
162170
}
163171

164-
function* Number(schema: Types.TNumeric, value: string): IterableIterator<string> {
172+
function* Number(schema: Types.TNumber, value: string): IterableIterator<string> {
165173
yield `(typeof ${value} === 'number')`
166174
if (schema.multipleOf !== undefined) yield `(${value} % ${schema.multipleOf} === 0)`
167175
if (schema.exclusiveMinimum !== undefined) yield `(${value} > ${schema.exclusiveMinimum})`
@@ -209,7 +217,7 @@ export namespace TypeCompiler {
209217
}
210218

211219
function* Record(schema: Types.TRecord<any, any>, value: string): IterableIterator<string> {
212-
yield `(typeof ${value} === 'object' && ${value} !== null && !Array.isArray(${value}))`
220+
yield `(typeof ${value} === 'object' && ${value} !== null && !Array.isArray(${value}) && !(${value} instanceof Date))`
213221
const [keyPattern, valueSchema] = globalThis.Object.entries(schema.patternProperties)[0]
214222
const local = PushLocal(`new RegExp(/${keyPattern}/)`)
215223
yield `(Object.keys(${value}).every(key => ${local}.test(key)))`
@@ -304,6 +312,8 @@ export namespace TypeCompiler {
304312
return yield* Boolean(anySchema, value)
305313
case 'Constructor':
306314
return yield* Constructor(anySchema, value)
315+
case 'Date':
316+
return yield* Date(anySchema, value)
307317
case 'Function':
308318
return yield* Function(anySchema, value)
309319
case 'Integer':

src/conditional/structural.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,22 @@ export namespace Structural {
197197
}
198198
}
199199

200+
function Date(left: Types.TDate, right: Types.TSchema): StructuralResult {
201+
if (AnyOrUnknownRule(right)) {
202+
return StructuralResult.True
203+
} else if (TypeGuard.TObject(right) && ObjectRightRule(left, right)) {
204+
return StructuralResult.True
205+
} else if (TypeGuard.TRecord(right)) {
206+
return StructuralResult.False
207+
} else if (TypeGuard.TDate(right)) {
208+
return StructuralResult.True
209+
} else if (TypeGuard.TUnion(right)) {
210+
return UnionRightRule(left, right)
211+
} else {
212+
return StructuralResult.False
213+
}
214+
}
215+
200216
function Function(left: Types.TFunction, right: Types.TSchema): StructuralResult {
201217
if (AnyOrUnknownRule(right)) {
202218
return StructuralResult.True
@@ -510,6 +526,8 @@ export namespace Structural {
510526
return Boolean(left, resolvedRight)
511527
} else if (TypeGuard.TConstructor(left)) {
512528
return Constructor(left, resolvedRight)
529+
} else if (TypeGuard.TDate(left)) {
530+
return Date(left, resolvedRight)
513531
} else if (TypeGuard.TFunction(left)) {
514532
return Function(left, resolvedRight)
515533
} else if (TypeGuard.TInteger(left)) {

src/errors/errors.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ export enum ValueErrorType {
3939
ArrayMaxItems,
4040
ArrayUniqueItems,
4141
Boolean,
42+
Date,
43+
DateExclusiveMinimum,
44+
DateExclusiveMaximum,
45+
DateMinimum,
46+
DateMaximum,
4247
Function,
4348
Integer,
4449
IntegerMultipleOf,
@@ -132,6 +137,24 @@ export namespace ValueErrors {
132137
yield* Visit(schema.returns, references, path, value.prototype)
133138
}
134139

140+
function* Date(schema: Types.TNumeric, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
141+
if (!(value instanceof globalThis.Date)) {
142+
return yield { type: ValueErrorType.Date, schema, path, value, message: `Expected Date object` }
143+
}
144+
if (schema.exclusiveMinimumTimestamp && !(value.getTime() > schema.exclusiveMinimumTimestamp)) {
145+
yield { type: ValueErrorType.DateExclusiveMinimum, schema, path, value, message: `Expected Date timestamp to be greater than ${schema.exclusiveMinimum}` }
146+
}
147+
if (schema.exclusiveMaximumTimestamp && !(value.getTime() < schema.exclusiveMaximumTimestamp)) {
148+
yield { type: ValueErrorType.DateExclusiveMaximum, schema, path, value, message: `Expected Date timestamp to be less than ${schema.exclusiveMaximum}` }
149+
}
150+
if (schema.minimumTimestamp && !(value.getTime() >= schema.minimumTimestamp)) {
151+
yield { type: ValueErrorType.DateMinimum, schema, path, value, message: `Expected Date timestamp to be greater or equal to ${schema.minimum}` }
152+
}
153+
if (schema.maximumTimestamp && !(value.getTime() <= schema.maximumTimestamp)) {
154+
yield { type: ValueErrorType.DateMaximum, schema, path, value, message: `Expected Date timestamp to be less or equal to ${schema.maximum}` }
155+
}
156+
}
157+
135158
function* Function(schema: Types.TFunction, references: Types.TSchema[], path: string, value: any): IterableIterator<ValueError> {
136159
if (!(typeof value === 'function')) {
137160
return yield { type: ValueErrorType.Function, schema, path, value, message: `Expected function` }
@@ -379,6 +402,8 @@ export namespace ValueErrors {
379402
return yield* Boolean(anySchema, anyReferences, path, value)
380403
case 'Constructor':
381404
return yield* Constructor(anySchema, anyReferences, path, value)
405+
case 'Date':
406+
return yield* Date(anySchema, anyReferences, path, value)
382407
case 'Function':
383408
return yield* Function(anySchema, anyReferences, path, value)
384409
case 'Integer':

0 commit comments

Comments
 (0)