Skip to content

Commit

Permalink
Revision 0.33.7 (#964)
Browse files Browse the repository at this point in the history
* Additional Improvements to Object Default

* Version
  • Loading branch information
sinclairzx81 authored Aug 15, 2024
1 parent 6da8b3f commit 8b503f6
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 17 deletions.
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.6",
"version": "0.33.7",
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",
Expand Down
10 changes: 6 additions & 4 deletions src/value/default/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,17 @@ import type { TUnion } from '../../type/union/index'
// ------------------------------------------------------------------
// ValueGuard
// ------------------------------------------------------------------
import { IsString, IsObject, IsArray, IsUndefined } from '../guard/index'
import { IsString, IsObject, IsArray, IsUndefined, HasPropertyKey } from '../guard/index'
// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsKind } from '../../type/guard/kind'
// ------------------------------------------------------------------
// ValueOrDefault
// ------------------------------------------------------------------
function ValueOrDefault(schema: TSchema, value: unknown) {
return value === undefined && 'default' in schema ? Clone(schema.default) : value
function ValueOrDefault(schema: TSchema, value: unknown): unknown {
const clone = HasPropertyKey(schema, 'default') ? Clone(schema.default) : undefined
return IsUndefined(value) ? clone : IsObject(value) && IsObject(clone) ? Object.assign(clone, value) : value
}
// ------------------------------------------------------------------
// HasDefaultProperty
Expand Down Expand Up @@ -81,6 +82,7 @@ function FromIntersect(schema: TIntersect, references: TSchema[], value: unknown
}
function FromObject(schema: TObject, references: TSchema[], value: unknown): any {
const defaulted = ValueOrDefault(schema, value)
// return defaulted
if (!IsObject(defaulted)) return defaulted
const knownPropertyKeys = Object.getOwnPropertyNames(schema.properties)
// properties
Expand All @@ -90,7 +92,7 @@ function FromObject(schema: TObject, references: TSchema[], value: unknown): any
// a non assignable property and continue.
const propertyValue = Visit(schema.properties[key], references, defaulted[key])
if (IsUndefined(propertyValue)) continue
defaulted[key] = propertyValue
defaulted[key] = Visit(schema.properties[key], references, defaulted[key])
}
// return if not additional properties
if (!HasDefaultProperty(schema.additionalProperties)) return defaulted
Expand Down
48 changes: 38 additions & 10 deletions test/runtime/value/default/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,19 +213,47 @@ describe('value/default/Object', () => {
// Traveral: https://github.com/sinclairzx81/typebox/issues/962
// ----------------------------------------------------------------
it('Should traverse into an object 1 (initialize)', () => {
const Child = Type.Object({ a: Type.String({ default: 'x' }) })
const Parent = Type.Object({ child: Child })
Assert.IsEqual(Value.Default(Child, {}), { a: 'x' })
Assert.IsEqual(Value.Default(Parent, { child: {} }), { child: { a: 'x' } })
const Y = Type.Object({ y: Type.String({ default: 'y' }) })
const X = Type.Object({ x: Y })
Assert.IsEqual(Value.Default(Y, {}), { y: 'y' })
Assert.IsEqual(Value.Default(X, { x: {} }), { x: { y: 'y' } })
})
it('Should traverse into an object 2 (retain)', () => {
const Child = Type.Object({ a: Type.String({ default: 'x' }) })
const Parent = Type.Object({ child: Child })
Assert.IsEqual(Value.Default(Parent, { child: { a: 1 } }), { child: { a: 1 } })
const Y = Type.Object({ y: Type.String({ default: 'y' }) })
const X = Type.Object({ x: Y })
Assert.IsEqual(Value.Default(X, { x: { y: 1 } }), { x: { y: 1 } })
})
it('Should traverse into an object 3 (ignore on undefined)', () => {
const Child = Type.Object({ a: Type.String({ default: 'x' }) })
const Parent = Type.Object({ child: Child })
Assert.IsEqual(Value.Default(Parent, { child: undefined }), { child: undefined })
const Y = Type.Object({ y: Type.String({ default: 'y' }) })
const X = Type.Object({ x: Y })
Assert.IsEqual(Value.Default(X, { x: undefined }), { x: undefined })
})
// ----------------------------------------------------------------
// Exterior Object Defaults
// ----------------------------------------------------------------
it('Should default exterior into an object 1', () => {
const X = Type.Object({ x: Type.String({ default: 1 }) }, { default: {} })
const R = Value.Default(X, undefined)
Assert.IsEqual(R, { x: 1 })
})
it('Should default exterior into an object 2', () => {
const X = Type.Object({ x: Type.String({ default: 1 }) }, { default: {} })
const R = Value.Default(X, {})
Assert.IsEqual(R, { x: 1 })
})
it('Should default exterior into an object 3', () => {
const X = Type.Object({ x: Type.String({ default: 1 }) }, { default: {} })
const R = Value.Default(X, { y: 3 })
Assert.IsEqual(R, { y: 3, x: 1 })
})
it('Should default exterior into an object 4', () => {
const X = Type.Object({ x: Type.String({ default: 1 }) }, { default: {} })
const R = Value.Default(X, { y: 3, x: 7 })
Assert.IsEqual(R, { y: 3, x: 7 })
})
it('Should default exterior into an object 5', () => {
const X = Type.Object({ x: Type.String({ default: 1 }) }, { default: {} })
const R = Value.Default(X, { x: 2 })
Assert.IsEqual(R, { x: 2 })
})
})

0 comments on commit 8b503f6

Please sign in to comment.