Skip to content

Commit

Permalink
Revision 0.33.13 (#1011)
Browse files Browse the repository at this point in the history
* Correctly Deref Union Variant in Default

* Version

* ChangeLog
  • Loading branch information
sinclairzx81 authored Oct 2, 2024
1 parent 0ed2071 commit e5d5ec0
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 47 deletions.
2 changes: 2 additions & 0 deletions changelog/0.33.0.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
### 0.33.0
- [Revision 0.33.13](https://github.com/sinclairzx81/typebox/pull/1011)
- [1010](https://github.com/sinclairzx81/typebox/pull/1011) Fixes Value.Parse fails with recursive types
- [Revision 0.33.12](https://github.com/sinclairzx81/typebox/pull/999)
- [998](https://github.com/sinclairzx81/typebox/issues/998) Avoid losing precision when converting to bigints
- [Revision 0.33.11](https://github.com/sinclairzx81/typebox/pull/994)
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sinclair/typebox",
"version": "0.33.12",
"version": "0.33.13",
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",
Expand Down
8 changes: 2 additions & 6 deletions src/value/convert/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ THE SOFTWARE.

import { Clone } from '../clone/index'
import { Check } from '../check/index'
import { Deref } from '../deref/index'
import { Deref, Pushref } from '../deref/index'
import { Kind } from '../../type/symbols/index'

import type { TSchema } from '../../type/schema/index'
Expand Down Expand Up @@ -249,12 +249,8 @@ function FromUnion(schema: TUnion, references: TSchema[], value: any): unknown {
}
return value
}
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
references.push(schema)
return references
}
function Visit(schema: TSchema, references: TSchema[], value: any): unknown {
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
const references_ = Pushref(schema, references)
const schema_ = schema as any
switch (schema[Kind]) {
case 'Array':
Expand Down
10 changes: 3 additions & 7 deletions src/value/create/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { HasPropertyKey, IsString } from '../guard/index'
import { HasPropertyKey } from '../guard/index'
import { Check } from '../check/index'
import { Clone } from '../clone/index'
import { Deref } from '../deref/index'
import { Deref, Pushref } from '../deref/index'
import { TemplateLiteralGenerate, IsTemplateLiteralFinite } from '../../type/template-literal/index'
import { PatternStringExact, PatternNumberExact } from '../../type/patterns/index'
import { TypeRegistry } from '../../type/registry/index'
Expand Down Expand Up @@ -391,12 +391,8 @@ function FromKind(schema: TSchema, references: TSchema[]): any {
throw new Error('User defined types must specify a default value')
}
}
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
references.push(schema)
return references
}
function Visit(schema: TSchema, references: TSchema[]): unknown {
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
const references_ = Pushref(schema, references)
const schema_ = schema as any
switch (schema_[Kind]) {
case 'Any':
Expand Down
12 changes: 4 additions & 8 deletions src/value/default/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ THE SOFTWARE.

import { Check } from '../check/index'
import { Clone } from '../clone/index'
import { Deref } from '../deref/index'
import { Deref, Pushref } from '../deref/index'
import { Kind } from '../../type/symbols/index'

import type { TSchema } from '../../type/schema/index'
Expand All @@ -44,7 +44,7 @@ import type { TUnion } from '../../type/union/index'
// ------------------------------------------------------------------
// ValueGuard
// ------------------------------------------------------------------
import { IsString, IsFunction, IsObject, IsArray, IsUndefined, HasPropertyKey } from '../guard/index'
import { IsFunction, IsObject, IsArray, IsUndefined, HasPropertyKey } from '../guard/index'
// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
Expand Down Expand Up @@ -143,18 +143,14 @@ function FromUnion(schema: TUnion, references: TSchema[], value: unknown): any {
const defaulted = ValueOrDefault(schema, value)
for (const inner of schema.anyOf) {
const result = Visit(inner, references, Clone(defaulted))
if (Check(inner, result)) {
if (Check(inner, references, result)) {
return result
}
}
return defaulted
}
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
references.push(schema)
return references
}
function Visit(schema: TSchema, references: TSchema[], value: unknown): any {
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
const references_ = Pushref(schema, references)
const schema_ = schema as any
switch (schema_[Kind]) {
case 'Array':
Expand Down
14 changes: 11 additions & 3 deletions src/value/deref/deref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,26 @@ import type { TRef } from '../../type/ref/index'
import type { TThis } from '../../type/recursive/index'
import { TypeBoxError } from '../../type/error/index'
import { Kind } from '../../type/symbols/index'

import { IsString } from '../guard/guard'
export class TypeDereferenceError extends TypeBoxError {
constructor(public readonly schema: TRef | TThis) {
super(`Unable to dereference schema with $id '${schema.$id}'`)
super(`Unable to dereference schema with $id '${schema.$ref}'`)
}
}
function Resolve(schema: TThis | TRef, references: TSchema[]): TSchema {
const target = references.find((target) => target.$id === schema.$ref)
if (target === undefined) throw new TypeDereferenceError(schema)
return Deref(target, references)
}
/** Dereferences a schema from the references array or throws if not found */

/** `[Internal]` Pushes a schema onto references if the schema has an $id and does not exist on references */
export function Pushref(schema: TSchema, references: TSchema[]): TSchema[] {
if (!IsString(schema.$id) || references.some((target) => target.$id === schema.$id)) return references
references.push(schema)
return references
}

/** `[Internal]` Dereferences a schema from the references array or throws if not found */
export function Deref(schema: TSchema, references: TSchema[]): TSchema {
// prettier-ignore
return (schema[Kind] === 'This' || schema[Kind] === 'Ref')
Expand Down
8 changes: 2 additions & 6 deletions src/value/transform/decode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { Kind, TransformKind } from '../../type/symbols/index'
import { TypeBoxError } from '../../type/error/index'
import { ValueError } from '../../errors/index'
import { KeyOfPropertyKeys, KeyOfPropertyEntries } from '../../type/keyof/index'
import { Deref } from '../deref/index'
import { Deref, Pushref } from '../deref/index'
import { Check } from '../check/index'

import type { TSchema } from '../../type/schema/index'
Expand Down Expand Up @@ -192,13 +192,9 @@ function FromUnion(schema: TUnion, references: TSchema[], path: string, value: a
}
return Default(schema, path, value)
}
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
references.push(schema)
return references
}
// prettier-ignore
function Visit(schema: TSchema, references: TSchema[], path: string, value: any): any {
const references_ = typeof schema.$id === 'string' ? AddReference(references, schema) : references
const references_ = Pushref(schema, references)
const schema_ = schema as any
switch (schema[Kind]) {
case 'Array':
Expand Down
8 changes: 2 additions & 6 deletions src/value/transform/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { Kind, TransformKind } from '../../type/symbols/index'
import { TypeBoxError } from '../../type/error/index'
import { ValueError } from '../../errors/index'
import { KeyOfPropertyKeys, KeyOfPropertyEntries } from '../../type/keyof/index'
import { Deref } from '../deref/index'
import { Deref, Pushref } from '../deref/index'
import { Check } from '../check/index'

import type { TSchema } from '../../type/schema/index'
Expand Down Expand Up @@ -203,13 +203,9 @@ function FromUnion(schema: TUnion, references: TSchema[], path: string, value: a
}
return Default(schema, path, value)
}
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
references.push(schema)
return references
}
// prettier-ignore
function Visit(schema: TSchema, references: TSchema[], path: string, value: any): any {
const references_ = typeof schema.$id === 'string' ? AddReference(references, schema) : references
const references_ = Pushref(schema, references)
const schema_ = schema as any
switch (schema[Kind]) {
case 'Array':
Expand Down
10 changes: 3 additions & 7 deletions src/value/transform/has.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { Deref } from '../deref/index'
import { Deref, Pushref } from '../deref/index'
import { Kind } from '../../type/symbols/index'

import type { TSchema } from '../../type/schema/index'
Expand All @@ -52,7 +52,7 @@ import { IsTransform, IsSchema } from '../../type/guard/type'
// ------------------------------------------------------------------
// ValueGuard
// ------------------------------------------------------------------
import { IsString, IsUndefined } from '../guard/index'
import { IsUndefined } from '../guard/index'

// prettier-ignore
function FromArray(schema: TArray, references: TSchema[]): boolean {
Expand Down Expand Up @@ -120,13 +120,9 @@ function FromTuple(schema: TTuple, references: TSchema[]) {
function FromUnion(schema: TUnion, references: TSchema[]) {
return IsTransform(schema) || schema.anyOf.some((schema) => Visit(schema, references))
}
function AddReference(references: TSchema[], schema: TSchema): TSchema[] {
references.push(schema)
return references
}
// prettier-ignore
function Visit(schema: TSchema, references: TSchema[]): boolean {
const references_ = IsString(schema.$id) ? AddReference(references, schema) : references
const references_ = Pushref(schema, references)
const schema_ = schema as any
if (schema.$id && visited.has(schema.$id)) return false
if (schema.$id) visited.add(schema.$id)
Expand Down
37 changes: 36 additions & 1 deletion test/runtime/value/default/recursive.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Value } from '@sinclair/typebox/value'
import { Type } from '@sinclair/typebox'
import { TSchema, Type } from '@sinclair/typebox'
import { Assert } from '../../assert/index'

// prettier-ignore
Expand Down Expand Up @@ -55,4 +55,39 @@ describe('value/default/Recursive', () => {
id: 1
})
})
// ----------------------------------------------------------------
// https://github.com/sinclairzx81/typebox/issues/1010
// ----------------------------------------------------------------
it('Should default Recursive Union', () => {
const Binary = <Node extends TSchema>(node: Node) => Type.Object({
type: Type.Literal('Binary'),
left: node,
right: node
})
const Node = Type.Object({
type: Type.Literal('Node'),
value: Type.String({ default: 'X' })
})
const Expr = Type.Recursive(This => Type.Union([Binary(This), Node]))
const R = Value.Default(Expr, {
type: 'Binary',
left: {
type: 'Node'
},
right: {
type: 'Node'
}
})
Assert.IsEqual(R, {
type: 'Binary',
left: {
type: 'Node',
value: 'X'
},
right: {
type: 'Node',
value: 'X'
}
})
})
})

0 comments on commit e5d5ec0

Please sign in to comment.