From b05c59c13bc95679a5ec1c202e7007e2aa127f1a Mon Sep 17 00:00:00 2001 From: Haydn Paterson Date: Thu, 21 Nov 2024 13:53:20 +0900 Subject: [PATCH] Revision 0.34.7 (#1093) * Revert Ref(Schema) Signature with Deprecation Notice * ChangeLog * Version --- changelog/0.34.0.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- readme.md | 10 +--------- src/type/ref/ref.ts | 28 +++++++++++++++++++++++++++- src/type/type/json.ts | 27 +++++++++++++++++++++++---- test/runtime/compiler-ajv/ref.ts | 12 ++++++++++++ test/runtime/compiler/ref.ts | 12 ++++++++++++ test/runtime/type/guard/kind/ref.ts | 21 +++++++++++++++++++++ test/runtime/type/guard/type/ref.ts | 21 +++++++++++++++++++++ test/runtime/value/check/ref.ts | 12 ++++++++++++ 11 files changed, 134 insertions(+), 17 deletions(-) diff --git a/changelog/0.34.0.md b/changelog/0.34.0.md index 77f5d0146..6a2ea89e7 100644 --- a/changelog/0.34.0.md +++ b/changelog/0.34.0.md @@ -1,4 +1,6 @@ ### 0.34.0 +- [Revision 0.34.7](https://github.com/sinclairzx81/typebox/pull/1093) + - Revert Ref(Schema) Signature with Deprecation Notice - [Revision 0.34.6](https://github.com/sinclairzx81/typebox/pull/1090) - Add Computed To Type and Kind Guards (IsSchema) - [Revision 0.34.5](https://github.com/sinclairzx81/typebox/pull/1088) diff --git a/package-lock.json b/package-lock.json index 4b4175ebb..a3eedbdaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@sinclair/typebox", - "version": "0.34.6", + "version": "0.34.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@sinclair/typebox", - "version": "0.34.6", + "version": "0.34.7", "license": "MIT", "devDependencies": { "@arethetypeswrong/cli": "^0.13.2", diff --git a/package.json b/package.json index 7ccb40d08..e630cd735 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/typebox", - "version": "0.34.6", + "version": "0.34.7", "description": "Json Schema Type Builder with Static Type Resolution for TypeScript", "keywords": [ "typescript", diff --git a/readme.md b/readme.md index 740e7c3e9..c6438cb85 100644 --- a/readme.md +++ b/readme.md @@ -534,15 +534,7 @@ The following table lists the supported Json types. These types are fully compat │ │ │ } │ │ │ │ │ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ -│ const T = Type.Object({ │ type T = { │ const R = { │ -│ x: Type.Number(), │ x: number, │ $ref: 'T' │ -│ y: Type.Number() │ y: number │ } │ -│ }, { $id: 'T' }) | } │ │ -│ │ │ │ -│ const R = Type.Ref(T) │ type R = T │ │ -│ │ │ │ -│ │ │ │ -│ │ │ │ +│ const R = Type.Ref('T') │ type R = unknown │ const R = { $ref: 'T' } │ │ │ │ │ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘ ``` diff --git a/src/type/ref/ref.ts b/src/type/ref/ref.ts index f61f04fac..f50f6a7ed 100644 --- a/src/type/ref/ref.ts +++ b/src/type/ref/ref.ts @@ -27,8 +27,11 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import type { TSchema, SchemaOptions } from '../schema/index' +import { TypeBoxError } from '../error/index' import { CreateType } from '../create/type' import { Kind } from '../symbols/index' +import { TUnsafe } from '../unsafe/index' +import { Static } from '../static/index' // ------------------------------------------------------------------ // TRef @@ -38,7 +41,30 @@ export interface TRef extends TSchema { static: unknown $ref: Ref } + +export type TRefUnsafe = TUnsafe> + +/** `[Json]` Creates a Ref type.*/ +export function Ref($ref: Ref, options?: SchemaOptions): TRef +/** + * @deprecated `[Json]` Creates a Ref type. The referenced type MUST contain a $id. The Ref(TSchema) signature was + * deprecated on 0.34.0 in support of a new type referencing model (Module). Existing implementations using Ref(TSchema) + * can migrate using the following. The Ref(TSchema) validation behavior of Ref will be preserved how the construction + * of legacy Ref(TSchema) will require wrapping in TUnsafe (where TUnsafe is used for inference only) + * + * ```typescript + * const R = Type.Ref(T) + * ``` + * to + * + * ```typescript + * const R = Type.Unsafe>(T.$id) + * ``` + */ +export function Ref(type: Type, options?: SchemaOptions): TRefUnsafe /** `[Json]` Creates a Ref type. The referenced type must contain a $id */ -export function Ref($ref: Ref, options?: SchemaOptions): TRef { +export function Ref(...args: any[]): unknown { + const [$ref, options] = typeof args[0] === 'string' ? [args[0], args[1]] : [args[0].$id, args[1]] + if (typeof $ref !== 'string') throw new TypeBoxError('Ref: $ref must be a string') return CreateType({ [Kind]: 'Ref', $ref }, options) as never } diff --git a/src/type/type/json.ts b/src/type/type/json.ts index acc91ce1f..f7efb99c4 100644 --- a/src/type/type/json.ts +++ b/src/type/type/json.ts @@ -57,7 +57,7 @@ import { Readonly, type TReadonlyWithFlag, type TReadonlyFromMappedResult } from import { ReadonlyOptional, type TReadonlyOptional } from '../readonly-optional/index' import { Record, type TRecordOrObject } from '../record/index' import { Recursive, type TRecursive, type TThis } from '../recursive/index' -import { Ref, type TRef } from '../ref/index' +import { Ref, type TRef, type TRefUnsafe } from '../ref/index' import { Required, type TRequired, type TRequiredFromMappedResult } from '../required/index' import { Rest, type TRest } from '../rest/index' import { type TSchema, type SchemaOptions } from '../schema/index' @@ -259,9 +259,28 @@ export class JsonTypeBuilder { public Recursive(callback: (thisType: TThis) => T, options?: SchemaOptions): TRecursive { return Recursive(callback, options) } - /** `[Json]` Creates a Ref type. */ - public Ref($ref: Ref, options?: SchemaOptions): TRef { - return Ref($ref, options) + + /** `[Json]` Creates a Ref type.*/ + public Ref($ref: Ref, options?: SchemaOptions): TRef + /** + * @deprecated `[Json]` Creates a Ref type. The referenced type MUST contain a $id. The Ref(TSchema) signature was + * deprecated on 0.34.0 in support of a new type referencing model (Module). Existing implementations using Ref(TSchema) + * can migrate using the following. The Ref(TSchema) validation behavior of Ref will be preserved how the construction + * of legacy Ref(TSchema) will require wrapping in TUnsafe (where TUnsafe is used for inference only) + * + * ```typescript + * const R = Type.Ref(T) + * ``` + * to + * + * ```typescript + * const R = Type.Unsafe>(T.$id) + * ``` + */ + public Ref(type: Type, options?: SchemaOptions): TRefUnsafe + /** `[Json]` Creates a Ref type. The referenced type must contain a $id */ + public Ref(...args: any[]): unknown { + return Ref(args[0] as string, args[1]) } /** `[Json]` Constructs a type where all properties are required */ public Required(type: MappedResult, options?: SchemaOptions): TRequiredFromMappedResult diff --git a/test/runtime/compiler-ajv/ref.ts b/test/runtime/compiler-ajv/ref.ts index 564dbc197..ac0815b13 100644 --- a/test/runtime/compiler-ajv/ref.ts +++ b/test/runtime/compiler-ajv/ref.ts @@ -2,6 +2,18 @@ import { Type } from '@sinclair/typebox' import { Ok, Fail } from './validate' describe('compiler-ajv/Ref', () => { + // ---------------------------------------------------------------- + // Deprecated + // ---------------------------------------------------------------- + it('Should validate for Ref(Schema)', () => { + const T = Type.Number({ $id: 'T' }) + const R = Type.Ref(T) + Ok(R, 1234, [T]) + Fail(R, 'hello', [T]) + }) + // ---------------------------------------------------------------- + // Standard + // ---------------------------------------------------------------- it('Should should validate when referencing a type', () => { const T = Type.Object( { diff --git a/test/runtime/compiler/ref.ts b/test/runtime/compiler/ref.ts index 1cd002f80..75470f8e5 100644 --- a/test/runtime/compiler/ref.ts +++ b/test/runtime/compiler/ref.ts @@ -3,6 +3,18 @@ import { Ok, Fail } from './validate' import { Assert } from '../assert/index' describe('compiler/Ref', () => { + // ---------------------------------------------------------------- + // Deprecated + // ---------------------------------------------------------------- + it('Should validate for Ref(Schema)', () => { + const T = Type.Number({ $id: 'T' }) + const R = Type.Ref(T) + Ok(R, 1234, [T]) + Fail(R, 'hello', [T]) + }) + // ---------------------------------------------------------------- + // Standard + // ---------------------------------------------------------------- it('Should should validate when referencing a type', () => { const T = Type.Object( { diff --git a/test/runtime/type/guard/kind/ref.ts b/test/runtime/type/guard/kind/ref.ts index 441d412cd..60d674634 100644 --- a/test/runtime/type/guard/kind/ref.ts +++ b/test/runtime/type/guard/kind/ref.ts @@ -3,6 +3,27 @@ import { Type } from '@sinclair/typebox' import { Assert } from '../../../assert/index' describe('guard/kind/TRef', () => { + // ---------------------------------------------------------------- + // Deprecated + // ---------------------------------------------------------------- + it('Should guard for Ref(Schema) 1', () => { + const T = Type.Number({ $id: 'T' }) + const R = Type.Ref(T) + Assert.IsTrue(KindGuard.IsRef(R)) + Assert.IsTrue(typeof R['$ref'] === 'string') + }) + it('Should guard for Ref(Schema) 2', () => { + const T = Type.Number() + Assert.Throws(() => Type.Ref(T)) + }) + it('Should guard for Ref(Schema) 3', () => { + // @ts-ignore + const T = Type.Number({ $id: null }) + Assert.Throws(() => Type.Ref(T)) + }) + // ---------------------------------------------------------------- + // Standard + // ---------------------------------------------------------------- it('Should guard for TRef', () => { const T = Type.Number({ $id: 'T' }) const R = KindGuard.IsRef(Type.Ref(T)) diff --git a/test/runtime/type/guard/type/ref.ts b/test/runtime/type/guard/type/ref.ts index c11b1a39c..0228f01af 100644 --- a/test/runtime/type/guard/type/ref.ts +++ b/test/runtime/type/guard/type/ref.ts @@ -3,6 +3,27 @@ import { Type, CloneType } from '@sinclair/typebox' import { Assert } from '../../../assert/index' describe('guard/type/TRef', () => { + // ---------------------------------------------------------------- + // Deprecated + // ---------------------------------------------------------------- + it('Should guard for Ref(Schema) 1', () => { + const T = Type.Number({ $id: 'T' }) + const R = Type.Ref(T) + Assert.IsTrue(TypeGuard.IsRef(R)) + Assert.IsTrue(typeof R['$ref'] === 'string') + }) + it('Should guard for Ref(Schema) 2', () => { + const T = Type.Number() + Assert.Throws(() => Type.Ref(T)) + }) + it('Should guard for Ref(Schema) 3', () => { + // @ts-ignore + const T = Type.Number({ $id: null }) + Assert.Throws(() => Type.Ref(T)) + }) + // ---------------------------------------------------------------- + // Standard + // ---------------------------------------------------------------- it('Should guard for TRef', () => { const T = Type.Number({ $id: 'T' }) const R = TypeGuard.IsRef(Type.Ref('T')) diff --git a/test/runtime/value/check/ref.ts b/test/runtime/value/check/ref.ts index 20156eb8d..aa7d76f03 100644 --- a/test/runtime/value/check/ref.ts +++ b/test/runtime/value/check/ref.ts @@ -3,6 +3,18 @@ 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( {