diff --git a/package.json b/package.json index ccd4b86..c9a2ab8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/typebox", - "version": "0.26.5", + "version": "0.26.6", "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript", "keywords": [ "typescript", diff --git a/src/value/convert.ts b/src/value/convert.ts index 987ef03..b40ab96 100644 --- a/src/value/convert.ts +++ b/src/value/convert.ts @@ -28,6 +28,7 @@ THE SOFTWARE. import * as Types from '../typebox' import { ValueClone } from './clone' +import { ValueCheck } from './check' // ---------------------------------------------------------------------------------------------- // Errors @@ -129,7 +130,6 @@ export namespace ValueConvert { function TryConvertBigInt(value: unknown) { return IsStringNumeric(value) ? globalThis.BigInt(parseInt(value)) : IsNumber(value) ? globalThis.BigInt(value | 0) : IsValueFalse(value) ? 0 : IsValueTrue(value) ? 1 : value } - function TryConvertString(value: unknown) { return IsValueToString(value) ? value.toString() : IsSymbol(value) && value.description !== undefined ? value.description.toString() : value } @@ -229,7 +229,13 @@ export namespace ValueConvert { return value } function Record(schema: Types.TRecord, references: Types.TSchema[], value: any): unknown { - return value + const propertyKey = globalThis.Object.getOwnPropertyNames(schema.patternProperties)[0] + const property = schema.patternProperties[propertyKey] + const result = {} as Record + for (const [propKey, propValue] of globalThis.Object.entries(value)) { + result[propKey] = Visit(property, references, propValue) + } + return result } function Ref(schema: Types.TRef, references: Types.TSchema[], value: any): unknown { const index = references.findIndex((foreign) => foreign.$id === schema.$ref) @@ -261,6 +267,12 @@ export namespace ValueConvert { return TryConvertUndefined(value) } function Union(schema: Types.TUnion, references: Types.TSchema[], value: any): unknown { + for (const subschema of schema.anyOf) { + const converted = Visit(subschema, references, value) + if (ValueCheck.Check(subschema, references, converted)) { + return converted + } + } return value } function Uint8Array(schema: Types.TUint8Array, references: Types.TSchema[], value: any): unknown { diff --git a/test/runtime/value/convert/record.ts b/test/runtime/value/convert/record.ts index bfeb712..641476f 100644 --- a/test/runtime/value/convert/record.ts +++ b/test/runtime/value/convert/record.ts @@ -3,5 +3,9 @@ import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('value/convert/Record', () => { - it('Should convert', () => {}) + it('Should convert record value to numeric', () => { + const T = Type.Record(Type.String(), Type.Number()) + const V = Value.Convert(T, { x: '42', y: '24', z: 'hello' }) + Assert.deepEqual(V, { x: 42, y: '24', z: 'hello' }) + }) }) diff --git a/test/runtime/value/convert/union.ts b/test/runtime/value/convert/union.ts index 5b1f2f3..7fd75a1 100644 --- a/test/runtime/value/convert/union.ts +++ b/test/runtime/value/convert/union.ts @@ -3,5 +3,22 @@ import { Type } from '@sinclair/typebox' import { Assert } from '../../assert/index' describe('value/convert/Union', () => { - it('Should convert', () => {}) + it('Should convert union variant', () => { + const T = Type.Object({ + x: Type.Union([Type.Number(), Type.Null()]), + }) + const V1 = Value.Convert(T, { x: '42' }) + const V2 = Value.Convert(T, { x: 'null' }) + const V3 = Value.Convert(T, { x: 'hello' }) + Assert.deepEqual(V1, { x: 42 }) + Assert.deepEqual(V2, { x: null }) + Assert.deepEqual(V3, { x: 'hello' }) + }) + it('Should convert first variant in ambiguous conversion', () => { + const T = Type.Object({ + x: Type.Union([Type.Boolean(), Type.Number()]), + }) + const V1 = Value.Convert(T, { x: '1' }) + Assert.deepEqual(V1, { x: true }) + }) })