diff --git a/example/index.ts b/example/index.ts index 0ef2a7acc..6e81f491c 100644 --- a/example/index.ts +++ b/example/index.ts @@ -1,7 +1,7 @@ import { TypeSystem } from '@sinclair/typebox/system' import { TypeCompiler } from '@sinclair/typebox/compiler' import { Value, ValuePointer } from '@sinclair/typebox/value' -import { Type, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox' +import { Type, TypeGuard, Kind, Static, TSchema, Optional } from '@sinclair/typebox' // Modifiers // - Deprecate Modifier Symbol diff --git a/src/value/cast.ts b/src/value/cast.ts index 7112b1eed..1dba9f7f2 100644 --- a/src/value/cast.ts +++ b/src/value/cast.ts @@ -156,7 +156,7 @@ function Integer(schema: Types.TInteger, references: Types.TSchema[], value: any } function Intersect(schema: Types.TIntersect, references: Types.TSchema[], value: any): any { const created = ValueCreate.Create(schema, references) - const mapped = ValueGuard.IsNonNominalObject(created) && ValueGuard.IsNonNominalObject(value) ? { ...(created as any), ...value } : value + const mapped = ValueGuard.IsPlainObject(created) && ValueGuard.IsPlainObject(value) ? { ...(created as any), ...value } : value return ValueCheck.Check(schema, references, mapped) ? mapped : ValueCreate.Create(schema, references) } function Iterator(schema: Types.TIterator, references: Types.TSchema[], value: any): any { diff --git a/src/value/clone.ts b/src/value/clone.ts index 7d1cededd..f369a5a85 100644 --- a/src/value/clone.ts +++ b/src/value/clone.ts @@ -70,7 +70,7 @@ export function Clone(value: T): T { if (ValueGuard.IsIterator(value)) return Iterator(value) if (ValueGuard.IsPromise(value)) return Promise(value) if (ValueGuard.IsDate(value)) return Date(value) - if (ValueGuard.IsNonNominalObject(value)) return Object(value) + if (ValueGuard.IsPlainObject(value)) return Object(value) if (ValueGuard.IsTypedArray(value)) return TypedArray(value) if (ValueGuard.IsValueType(value)) return Value(value) throw new Error('ValueClone: Unable to clone value') diff --git a/src/value/delta.ts b/src/value/delta.ts index 86306a8a8..16bd339c8 100644 --- a/src/value/delta.ts +++ b/src/value/delta.ts @@ -82,7 +82,7 @@ function CreateDelete(path: string): Edit { // Diffing Generators // -------------------------------------------------------------------------- function* Object(path: string, current: ValueGuard.ObjectType, next: unknown): IterableIterator { - if (!ValueGuard.IsNonNominalObject(next)) return yield CreateUpdate(path, next) + if (!ValueGuard.IsPlainObject(next)) return yield CreateUpdate(path, next) const currentKeys = [...globalThis.Object.keys(current), ...globalThis.Object.getOwnPropertySymbols(current)] const nextKeys = [...globalThis.Object.keys(next), ...globalThis.Object.getOwnPropertySymbols(next)] for (const key of currentKeys) { @@ -128,7 +128,7 @@ function* ValueType(path: string, current: ValueGuard.ValueType, next: unknown): yield CreateUpdate(path, next) } function* Visit(path: string, current: unknown, next: unknown): IterableIterator { - if (ValueGuard.IsNonNominalObject(current)) return yield* Object(path, current, next) + if (ValueGuard.IsPlainObject(current)) return yield* Object(path, current, next) if (ValueGuard.IsArray(current)) return yield* Array(path, current, next) if (ValueGuard.IsTypedArray(current)) return yield* TypedArray(path, current, next) if (ValueGuard.IsValueType(current)) return yield* ValueType(path, current, next) diff --git a/src/value/equal.ts b/src/value/equal.ts index 6f6506111..5146781c5 100644 --- a/src/value/equal.ts +++ b/src/value/equal.ts @@ -32,7 +32,7 @@ import * as ValueGuard from './guard' // Equality Checks // -------------------------------------------------------------------------- function Object(left: ValueGuard.ObjectType, right: unknown): boolean { - if (!ValueGuard.IsNonNominalObject(right)) return false + if (!ValueGuard.IsPlainObject(right)) return false const leftKeys = [...globalThis.Object.keys(left), ...globalThis.Object.getOwnPropertySymbols(left)] const rightKeys = [...globalThis.Object.keys(right), ...globalThis.Object.getOwnPropertySymbols(right)] if (leftKeys.length !== rightKeys.length) return false @@ -54,7 +54,7 @@ function ValueType(left: ValueGuard.ValueType, right: unknown): any { } /** Returns true if the left value deep-equals the right */ export function Equal(left: T, right: unknown): right is T { - if (ValueGuard.IsNonNominalObject(left)) return Object(left, right) + if (ValueGuard.IsPlainObject(left)) return Object(left, right) if (ValueGuard.IsDate(left)) return Date(left, right) if (ValueGuard.IsTypedArray(left)) return TypedArray(left, right) if (ValueGuard.IsArray(left)) return Array(left, right) diff --git a/src/value/guard.ts b/src/value/guard.ts index 58c4a4441..c10735fc3 100644 --- a/src/value/guard.ts +++ b/src/value/guard.ts @@ -50,11 +50,11 @@ export type TypedArrayType = // -------------------------------------------------------------------------- /** Returns true if this value is an async iterator */ export function IsAsyncIterator(value: unknown): value is AsyncIterableIterator { - return IsNonNominalObject(value) && Symbol.asyncIterator in value + return IsPlainObject(value) && Symbol.asyncIterator in value } /** Returns true if this value is an iterator */ export function IsIterator(value: unknown): value is IterableIterator { - return IsNonNominalObject(value) && Symbol.iterator in value + return IsPlainObject(value) && Symbol.iterator in value } // -------------------------------------------------------------------------- // Nominal @@ -78,20 +78,20 @@ export function IsDate(value: unknown): value is Date { // -------------------------------------------------------------------------- // Standard // -------------------------------------------------------------------------- +/** Returns true if this value has this property key */ +export function HasPropertyKey(value: Record, key: K): value is ObjectType & Record { + return key in value +} /** Returns true of this value is an object type, non-inclusive of arrays, typed-arrays, promises and dates */ -export function IsNonNominalObject(value: unknown): value is ObjectType { +export function IsPlainObject(value: unknown): value is ObjectType { // prettier-ignore return IsObject(value) && ( - !IsTypedArray(value) && !IsArray(value) && - !IsPromise(value) && - !IsDate(value) + !IsDate(value) && + !IsTypedArray(value) && + !IsPromise(value) ) } -/** Returns true if this value has this property key */ -export function HasPropertyKey(value: Record, key: K): value is ObjectType & Record { - return key in value -} /** Returns true of this value is an object type */ export function IsObject(value: unknown): value is ObjectType { return value !== null && typeof value === 'object' @@ -140,42 +140,12 @@ export function IsSymbol(value: unknown): value is symbol { export function IsValueType(value: unknown): value is ValueType { // prettier-ignore return ( + IsBigInt(value) || + IsBoolean(value) || IsNull(value) || - IsUndefined(value) || IsNumber(value) || - IsBoolean(value) || IsString(value) || - IsBigInt(value) || - IsSymbol(value) + IsSymbol(value) || + IsUndefined(value) ) } -// -------------------------------------------------------------------------- -// Conversions -// -------------------------------------------------------------------------- -export function IsStringNumeric(value: unknown): value is string { - return IsString(value) && !isNaN(value as any) && !isNaN(parseFloat(value)) -} -export function IsValueToString(value: unknown): value is { toString: () => string } { - return IsBigInt(value) || IsBoolean(value) || IsNumber(value) -} -export function IsValueTrue(value: unknown): value is true { - return value === true || (IsNumber(value) && value === 1) || (IsBigInt(value) && value === globalThis.BigInt('1')) || (IsString(value) && (value.toLowerCase() === 'true' || value === '1')) -} -export function IsValueFalse(value: unknown): value is false { - return value === false || (IsNumber(value) && value === 0) || (IsBigInt(value) && value === globalThis.BigInt('0')) || (IsString(value) && (value.toLowerCase() === 'false' || value === '0')) -} -export function IsTimeStringWithTimeZone(value: unknown): value is string { - return IsString(value) && /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i.test(value) -} -export function IsTimeStringWithoutTimeZone(value: unknown): value is string { - return IsString(value) && /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)?$/i.test(value) -} -export function IsDateTimeStringWithTimeZone(value: unknown): value is string { - return IsString(value) && /^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i.test(value) -} -export function IsDateTimeStringWithoutTimeZone(value: unknown): value is string { - return IsString(value) && /^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)?$/i.test(value) -} -export function IsDateString(value: unknown): value is string { - return IsString(value) && /^\d\d\d\d-[0-1]\d-[0-3]\d$/i.test(value) -} diff --git a/src/value/hash.ts b/src/value/hash.ts index 3f99ba12e..5a48b7265 100644 --- a/src/value/hash.ts +++ b/src/value/hash.ts @@ -128,7 +128,7 @@ function Visit(value: any) { if (ValueGuard.IsDate(value)) return Date(value) if (ValueGuard.IsNull(value)) return Null(value) if (ValueGuard.IsNumber(value)) return Number(value) - if (ValueGuard.IsNonNominalObject(value)) return Object(value) + if (ValueGuard.IsPlainObject(value)) return Object(value) if (ValueGuard.IsString(value)) return String(value) if (ValueGuard.IsSymbol(value)) return Symbol(value) if (ValueGuard.IsUint8Array(value)) return Uint8Array(value) diff --git a/src/value/mutate.ts b/src/value/mutate.ts index 7f0681d7f..c71e9c2d5 100644 --- a/src/value/mutate.ts +++ b/src/value/mutate.ts @@ -48,7 +48,7 @@ export class ValueMutateInvalidRootMutationError extends Error { // -------------------------------------------------------------------------- export type Mutable = { [key: string]: unknown } | unknown[] function Object(root: Mutable, path: string, current: unknown, next: Record) { - if (!ValueGuard.IsNonNominalObject(current)) { + if (!ValueGuard.IsPlainObject(current)) { ValuePointer.Set(root, path, ValueClone.Clone(next)) } else { const currentKeys = globalThis.Object.keys(current) @@ -94,7 +94,7 @@ function Value(root: Mutable, path: string, current: unknown, next: unknown) { function Visit(root: Mutable, path: string, current: unknown, next: unknown) { if (ValueGuard.IsArray(next)) return Array(root, path, current, next) if (ValueGuard.IsTypedArray(next)) return TypedArray(root, path, current, next) - if (ValueGuard.IsNonNominalObject(next)) return Object(root, path, current, next) + if (ValueGuard.IsPlainObject(next)) return Object(root, path, current, next) if (ValueGuard.IsValueType(next)) return Value(root, path, current, next) } // -------------------------------------------------------------------------- @@ -106,8 +106,8 @@ function IsNonMutableValue(value: unknown): value is Mutable { function IsMismatchedValue(current: unknown, next: unknown) { // prettier-ignore return ( - (ValueGuard.IsNonNominalObject(current) && ValueGuard.IsArray(next)) || - (ValueGuard.IsArray(current) && ValueGuard.IsNonNominalObject(next)) + (ValueGuard.IsPlainObject(current) && ValueGuard.IsArray(next)) || + (ValueGuard.IsArray(current) && ValueGuard.IsPlainObject(next)) ) } /** Performs a deep mutable value assignment while retaining internal references. */