From 9c885def4ecd432eee53c1b6ebd69d18e8bd1131 Mon Sep 17 00:00:00 2001 From: sinclair Date: Fri, 24 Nov 2023 14:00:38 +0900 Subject: [PATCH] Reimplement Index Types --- examples/index.ts | 175 ++++++++++++++++---- examples/next/indexer.ts | 2 +- examples/prototypes/evaluate.ts | 4 +- src/compiler/compiler.ts | 4 +- src/errors/errors.ts | 4 +- src/typebox.ts | 275 +++++++++++++++++++++++++++----- src/value/check.ts | 4 +- src/value/transform.ts | 8 +- 8 files changed, 387 insertions(+), 89 deletions(-) diff --git a/examples/index.ts b/examples/index.ts index 9f2e52892..0111b7a01 100644 --- a/examples/index.ts +++ b/examples/index.ts @@ -45,6 +45,7 @@ import { AccessResolver, IndexResolver, Assert, + UnionToIntersect, } from '@sinclair/typebox' // prettier-ignore @@ -57,7 +58,7 @@ export namespace KeyResolver { ? [...Resolve, ...Intersect] : [] ) - export function Intersect(T: T): Intersect { + export function Intersect(T: [...T]): Intersect { const [L, ...R] = T return ( T.length > 0 @@ -66,32 +67,87 @@ export namespace KeyResolver { ) as Intersect } // ---------------------------------------------------------------- - // Union + // UnionKeyIn // ---------------------------------------------------------------- - export type Union = [] - export function Union(T: TSchema[]): string[] { - return globalThis.Object.getOwnPropertyNames(T) + export type UnionKeyIn = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? S extends L + ? true + : UnionKeyIn + : false + ) + export function UnionKeyIn(T: [...T], S: S) { + return ( + T.includes(S) + ) as UnionKeyIn } // ---------------------------------------------------------------- - // Array + // UnionKeysIn // ---------------------------------------------------------------- - export type Properties = ( - UnionToTuple + export type UnionKeysIn = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? UnionKeyIn extends true + ? [L, ...UnionKeysIn] + : [...UnionKeysIn] + : [] ) - export function Properties(T: T): Properties { + export function UnionKeysIn(T: [...T], S: [...S]): UnionKeysIn { + const [L, ...R] = T return ( - globalThis.Object.getOwnPropertyNames(T) - ) as Properties + T.length > 0 + ? UnionKeyIn(S, L) === true + ? [L, ...UnionKeysIn(R, S)] + : [...UnionKeysIn(R, S)] + : [] + ) as UnionKeysIn } // ---------------------------------------------------------------- - // Array + // UnionKeys // ---------------------------------------------------------------- - export type Array<_ extends TSchema> = ( - ['number'] + export type UnionKeys = ( + T extends [infer L extends PropertyKey[]] + ? L + : T extends [infer L extends PropertyKey[], ...infer R extends PropertyKey[][]] + ? UnionKeysIn> + : [] + ) + export function UnionKeys(T: [...T]): UnionKeys { + return ( + T.length === 1 + ? T[0] + : Into(() => { + const [L, ...R] = T + return L.length > 0 + ? UnionKeysIn(L, UnionKeys(R)) + : [] + }) + ) as UnionKeys + } + // ---------------------------------------------------------------- + // UnionCollect + // ---------------------------------------------------------------- + export type UnionCollect = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [Resolve, ...UnionCollect] + : [] ) - export function Array<_ extends TSchema>(_: _): Array<_> { + export function UnionCollect(T: [...T]): UnionCollect { + const [L, ...R] = T return ( - ['number'] + T.length > 0 + ? [Resolve(L), ...UnionCollect(R)] + : [] + ) as UnionCollect + } + // ---------------------------------------------------------------- + // Union + // ---------------------------------------------------------------- + export type Union> = ( + UnionKeys + ) + export function Union(T: [...T], C = UnionCollect(T)): Union { + return ( + UnionKeys(C as PropertyKey[][]) as Union ) } // ---------------------------------------------------------------- @@ -107,49 +163,102 @@ export namespace KeyResolver { ? Tuple, ...I]> : I ) - export function Tuple(T: T): Tuple { + export function Tuple(T: [...T]): Tuple { return ( T.map((_, index) => index.toString()) ) as Tuple } // ---------------------------------------------------------------- + // Array + // ---------------------------------------------------------------- + export type Array<_ extends TSchema> = ( + ['number'] + ) + export function Array<_ extends TSchema>(_: _): Array<_> { + return ( + ['number'] + ) + } + // ---------------------------------------------------------------- + // Properties + // ---------------------------------------------------------------- + export type Properties = ( + UnionToTuple + ) + export function Properties(T: T): Properties { + return ( + globalThis.Object.getOwnPropertyNames(T) + ) as Properties + } + // ---------------------------------------------------------------- + // Pattern + // ---------------------------------------------------------------- + function PatternProperties(patternProperties: Record): string[] { + if(!includePatternProperties) return [] + const patternPropertyKeys = globalThis.Object.getOwnPropertyNames(patternProperties) + return patternPropertyKeys.map(key => { + return (key[0] === '^' && key[key.length - 1] === '$') + ? key.slice(1, key.length - 1) + : key + }) + } + // ---------------------------------------------------------------- // Resolve // ---------------------------------------------------------------- export type Resolve = ( + T extends TRecursive ? Resolve : T extends TIntersect ? Intersect : T extends TUnion ? Union : - T extends TObject ? Properties : - T extends TArray ? Array : T extends TTuple ? Tuple : + T extends TArray ? Array : + T extends TObject ? Properties : [] ) + /** Resolves finite keys from this type */ export function Resolve(T: T): Resolve { return ( TypeGuard.TIntersect(T) ? Intersect(T.allOf) : TypeGuard.TUnion(T) ? Union(T.anyOf) : - TypeGuard.TObject(T) ? Object(T.properties) : - TypeGuard.TArray(T) ? Array(T.items) : TypeGuard.TTuple(T) ? Tuple(T.items ?? []) : + TypeGuard.TArray(T) ? Array(T.items) : + TypeGuard.TObject(T) ? Properties(T.properties) : + TypeGuard.TRecord(T) ? PatternProperties(T.patternProperties) : [] - ) + ) as Resolve + } + // ---------------------------------------------------------------- + // ResolvePattern + // ---------------------------------------------------------------- + let includePatternProperties = false + /** Resolves keys as a regular expression, including pattern property keys */ + export function ResolvePattern(schema: TSchema): string { + includePatternProperties = true + const keys = Resolve(schema) + includePatternProperties = false + const pattern = keys.map((key) => `(${key})`) + return `^(${pattern.join('|')})$` } } -const K = KeyResolver.Resolve(Type.Object({ - x: Type.Number() -})) +const A = KeyResolver.ResolvePattern(Type.Intersect([ + Type.Record(Type.Number(), Type.Number()), + Type.Object({ + x: Type.Number(), + y: Type.Number(), + z: Type.Number() + }) +])) + +const B = KeyResolver.Union([ + Type.Object({ x: Type.Number(), y: Type.Number() }), + Type.Object({ x: Type.Number(), y: Type.Number() }) +]) + +console.log(A) -const I = IndexResolver.Resolve(Type.TemplateLiteral('a${1|2|3}')) -const X = AccessResolver.Union([Type.Object({ - a1: Type.String() -}), Type.Object({ - a2: Type.Number() -})] , 'a1') -type A = { x: number } | { x: number } -type K = keyof A diff --git a/examples/next/indexer.ts b/examples/next/indexer.ts index e5d3649fa..6fc5bfa81 100644 --- a/examples/next/indexer.ts +++ b/examples/next/indexer.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, AccessResolver, TemplateLiteralParser, TemplateLiteralFinite, TemplateLiteralResolver, TypeGuard, TIntersect, TUnion, TTemplateLiteral, IsTemplateLiteralFiniteCheck, UnionToTuple, Static, TSchema, TLiteralValue, TLiteral, TNumber, TInteger, TBigInt, TString, KeyResolverOptions, PatternNumber } from '@sinclair/typebox' +import { Type, AccessResolver, TemplateLiteralParser, TemplateLiteralFinite, TemplateLiteralResolver, TypeGuard, TIntersect, TUnion, TTemplateLiteral, IsTemplateLiteralFiniteCheck, UnionToTuple, Static, TSchema, TLiteralValue, TLiteral, TNumber, TInteger, TBigInt, TString, PatternNumber } from '@sinclair/typebox' import { TObject } from '@sinclair/typebox' const A = Type.Index(Type.Object({ diff --git a/examples/prototypes/evaluate.ts b/examples/prototypes/evaluate.ts index 576cf06bb..8c28b9a30 100644 --- a/examples/prototypes/evaluate.ts +++ b/examples/prototypes/evaluate.ts @@ -44,7 +44,7 @@ import { TTuple, TProperties, TIntersect, - IntersectTypeResolve, + IntersectType, TUnion, TNever } from '@sinclair/typebox' @@ -75,7 +75,7 @@ export type TEvaluateArray = T extends [infer L, ...infer [] // prettier-ignore export type TEvaluate = - T extends TIntersect ? IntersectTypeResolve> : + T extends TIntersect ? IntersectType.Resolve> : T extends TUnion ? TUnion> : T extends TConstructor ? TConstructor, TEvaluate> : T extends TFunction ? TFunction, TEvaluate> : diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index 59e7dafef..fe03f6d2e 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -253,11 +253,11 @@ export namespace TypeCompiler { function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: string): IterableIterator { const check1 = schema.allOf.map((schema: Types.TSchema) => CreateExpression(schema, references, value)).join(' && ') if (schema.unevaluatedProperties === false) { - const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.Pattern(schema))};`) + const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`) const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key))` yield `(${check1} && ${check2})` } else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) { - const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.Pattern(schema))};`) + const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.ResolvePattern(schema))};`) const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key) || ${CreateExpression(schema.unevaluatedProperties, references, `${value}[key]`)})` yield `(${check1} && ${check2})` } else { diff --git a/src/errors/errors.ts b/src/errors/errors.ts index c5814d545..9f09e1f55 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -262,7 +262,7 @@ function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], path } } if (schema.unevaluatedProperties === false) { - const keyCheck = new RegExp(Types.KeyResolver.Pattern(schema)) + const keyCheck = new RegExp(Types.KeyResolver.ResolvePattern(schema)) for (const valueKey of Object.getOwnPropertyNames(value)) { if (!keyCheck.test(valueKey)) { yield Create(ValueErrorType.IntersectUnevaluatedProperties, schema, `${path}/${valueKey}`, value) @@ -270,7 +270,7 @@ function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], path } } if (typeof schema.unevaluatedProperties === 'object') { - const keyCheck = new RegExp(Types.KeyResolver.Pattern(schema)) + const keyCheck = new RegExp(Types.KeyResolver.ResolvePattern(schema)) for (const valueKey of Object.getOwnPropertyNames(value)) { if (!keyCheck.test(valueKey)) { const next = Visit(schema.unevaluatedProperties, references, `${path}/${valueKey}`, value[valueKey]).next() diff --git a/src/typebox.ts b/src/typebox.ts index e6197d089..0e4268738 100644 --- a/src/typebox.ts +++ b/src/typebox.ts @@ -2612,46 +2612,237 @@ export namespace Increment { // ---------------------------------------------------------------- // KeyResolver // ---------------------------------------------------------------- -export interface KeyResolverOptions { - includePatterns: boolean -} +// export interface KeyResolverOptions { +// includePatterns: boolean +// } +// // prettier-ignore +// export namespace KeyResolver { +// function UnwrapPattern(key: string) { +// return key[0] === '^' && key[key.length - 1] === '$' ? key.slice(1, key.length - 1) : key +// } +// function TIntersect(schema: TIntersect, options: KeyResolverOptions): string[] { +// return schema.allOf.reduce((acc, schema) => [...acc, ...Visit(schema, options)], [] as string[]) +// } +// function TUnion(schema: TUnion, options: KeyResolverOptions): string[] { +// const sets = schema.anyOf.map((inner) => Visit(inner, options)) +// return [...sets.reduce((set, outer) => outer.map((key) => (sets.every((inner) => inner.includes(key)) ? set.add(key) : set))[0], new Set())] +// } +// function TObject(schema: TObject, options: KeyResolverOptions): string[] { +// return Object.getOwnPropertyNames(schema.properties) +// } +// function TRecord(schema: TRecord, options: KeyResolverOptions): string[] { +// return options.includePatterns ? Object.getOwnPropertyNames(schema.patternProperties) : [] +// } +// function Visit(schema: TSchema, options: KeyResolverOptions): string[] { +// return ( +// TypeGuard.TIntersect(schema) ? TIntersect(schema, options) : +// TypeGuard.TUnion(schema) ? TUnion(schema, options) : +// TypeGuard.TObject(schema) ? TObject(schema, options) : +// TypeGuard.TRecord(schema) ? TRecord(schema, options) : +// [] +// ) +// } +// /** Resolves a regular expression pattern matching all keys in this schema */ +// export function ResolvePattern(schema: TSchema): string { +// const keys = Resolve(schema, { includePatterns: true }) +// const pattern = keys.map((key) => `(${UnwrapPattern(key)})`) +// return `^(${pattern.join('|')})$` +// } +// /** Resolves an array of keys derived from this schema */ +// export function Resolve(schema: TSchema, options: KeyResolverOptions): string[] { +// return [...new Set(Visit(schema, options))] +// } +// } // prettier-ignore export namespace KeyResolver { - function UnwrapPattern(key: string) { - return key[0] === '^' && key[key.length - 1] === '$' ? key.slice(1, key.length - 1) : key + // ---------------------------------------------------------------- + // Intersect + // ---------------------------------------------------------------- + export type Intersect = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [...Resolve, ...Intersect] + : [] + ) + export function Intersect(T: [...T]): Intersect { + const [L, ...R] = T + return ( + T.length > 0 + ? [...Resolve(L), ...Intersect(R)] + : [] + ) as Intersect + } + // ---------------------------------------------------------------- + // UnionKeyIn + // ---------------------------------------------------------------- + export type UnionKeyIn = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? S extends L + ? true + : UnionKeyIn + : false + ) + export function UnionKeyIn(T: [...T], S: S) { + return ( + T.includes(S) + ) as UnionKeyIn + } + // ---------------------------------------------------------------- + // UnionKeysIn + // ---------------------------------------------------------------- + export type UnionKeysIn = ( + T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] + ? UnionKeyIn extends true + ? [L, ...UnionKeysIn] + : [...UnionKeysIn] + : [] + ) + export function UnionKeysIn(T: [...T], S: [...S]): UnionKeysIn { + const [L, ...R] = T + return ( + T.length > 0 + ? UnionKeyIn(S, L) === true + ? [L, ...UnionKeysIn(R, S)] + : [...UnionKeysIn(R, S)] + : [] + ) as UnionKeysIn + } + // ---------------------------------------------------------------- + // UnionKeys + // ---------------------------------------------------------------- + export type UnionKeys = ( + T extends [infer L extends PropertyKey[]] + ? L + : T extends [infer L extends PropertyKey[], ...infer R extends PropertyKey[][]] + ? UnionKeysIn> + : [] + ) + export function UnionKeys(T: [...T]): UnionKeys { + return ( + T.length === 1 + ? T[0] + : Into(() => { + const [L, ...R] = T + return L.length > 0 + ? UnionKeysIn(L, UnionKeys(R)) + : [] + }) + ) as UnionKeys + } + // ---------------------------------------------------------------- + // UnionCollect + // ---------------------------------------------------------------- + export type UnionCollect = ( + T extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? [Resolve, ...UnionCollect] + : [] + ) + export function UnionCollect(T: [...T]): UnionCollect { + const [L, ...R] = T + return ( + T.length > 0 + ? [Resolve(L), ...UnionCollect(R)] + : [] + ) as UnionCollect + } + // ---------------------------------------------------------------- + // Union + // ---------------------------------------------------------------- + export type Union> = ( + UnionKeys + ) + export function Union(T: [...T], C = UnionCollect(T)): Union { + return ( + UnionKeys(C as PropertyKey[][]) as Union + ) } - function TIntersect(schema: TIntersect, options: KeyResolverOptions): string[] { - return schema.allOf.reduce((acc, schema) => [...acc, ...Visit(schema, options)], [] as string[]) + // ---------------------------------------------------------------- + // Tuple + // ---------------------------------------------------------------- + export type TupleNext = ( + I extends [infer L extends string, ...infer _] + ? Increment.Next + : '0' + ) + export type Tuple = ( + T extends [infer _, ...infer R extends TSchema[]] + ? Tuple, ...I]> + : I + ) + export function Tuple(T: [...T]): Tuple { + return ( + T.map((_, index) => index.toString()) + ) as Tuple } - function TUnion(schema: TUnion, options: KeyResolverOptions): string[] { - const sets = schema.anyOf.map((inner) => Visit(inner, options)) - return [...sets.reduce((set, outer) => outer.map((key) => (sets.every((inner) => inner.includes(key)) ? set.add(key) : set))[0], new Set())] + // ---------------------------------------------------------------- + // Array + // ---------------------------------------------------------------- + export type Array<_ extends TSchema> = ( + ['number'] + ) + export function Array<_ extends TSchema>(_: _): Array<_> { + return ( + ['number'] + ) } - function TObject(schema: TObject, options: KeyResolverOptions): string[] { - return Object.getOwnPropertyNames(schema.properties) + // ---------------------------------------------------------------- + // Properties + // ---------------------------------------------------------------- + export type Properties = ( + UnionToTuple + ) + export function Properties(T: T): Properties { + return ( + globalThis.Object.getOwnPropertyNames(T) + ) as Properties } - function TRecord(schema: TRecord, options: KeyResolverOptions): string[] { - return options.includePatterns ? Object.getOwnPropertyNames(schema.patternProperties) : [] + // ---------------------------------------------------------------- + // Pattern + // ---------------------------------------------------------------- + function PatternProperties(patternProperties: Record): string[] { + if(!includePatternProperties) return [] + const patternPropertyKeys = globalThis.Object.getOwnPropertyNames(patternProperties) + return patternPropertyKeys.map(key => { + return (key[0] === '^' && key[key.length - 1] === '$') + ? key.slice(1, key.length - 1) + : key + }) } - function Visit(schema: TSchema, options: KeyResolverOptions): string[] { + // ---------------------------------------------------------------- + // Resolve + // ---------------------------------------------------------------- + export type Resolve = ( + T extends TRecursive ? Resolve : + T extends TIntersect ? Intersect : + T extends TUnion ? Union : + T extends TTuple ? Tuple : + T extends TArray ? Array : + T extends TObject ? Properties : + [] + ) + /** Resolves finite keys from this type */ + export function Resolve(T: T): Resolve { return ( - TypeGuard.TIntersect(schema) ? TIntersect(schema, options) : - TypeGuard.TUnion(schema) ? TUnion(schema, options) : - TypeGuard.TObject(schema) ? TObject(schema, options) : - TypeGuard.TRecord(schema) ? TRecord(schema, options) : + TypeGuard.TIntersect(T) ? Intersect(T.allOf) : + TypeGuard.TUnion(T) ? Union(T.anyOf) : + TypeGuard.TTuple(T) ? Tuple(T.items ?? []) : + TypeGuard.TArray(T) ? Array(T.items) : + TypeGuard.TObject(T) ? Properties(T.properties) : + TypeGuard.TRecord(T) ? PatternProperties(T.patternProperties) : [] - ) + ) as Resolve } - /** Resolves a regular expression pattern matching all keys in this schema */ - export function Pattern(schema: TSchema): string { - const keys = Keys(schema, { includePatterns: true }) - const pattern = keys.map((key) => `(${UnwrapPattern(key)})`) + // ---------------------------------------------------------------- + // ResolvePattern + // ---------------------------------------------------------------- + let includePatternProperties = false + /** Resolves keys as a regular expression, including pattern property keys */ + export function ResolvePattern(schema: TSchema): string { + includePatternProperties = true + const keys = Resolve(schema) + includePatternProperties = false + const pattern = keys.map((key) => `(${key})`) return `^(${pattern.join('|')})$` } - /** Resolves an array of keys derived from this schema */ - export function Keys(schema: TSchema, options: KeyResolverOptions): string[] { - return [...new Set(Visit(schema, options))] - } } // ------------------------------------------------------------------ // IndexedResolver @@ -2742,7 +2933,7 @@ export namespace AccessResolver { ? [Key, ...Collect] : [] ) - export function Collect(T: T, K: K): Collect { + export function Collect(T: [...T], K: K): Collect { const [L, ...R] = T return ( T.length > 0 @@ -2760,7 +2951,7 @@ export namespace AccessResolver { : [L, ...IntersectEvaluate] : [] ) - export function IntersectEvaluate(T: T): IntersectEvaluate { + export function IntersectEvaluate(T: [...T]): IntersectEvaluate { const [L, ...R] = T return ( T.length > 0 @@ -2773,11 +2964,9 @@ export namespace AccessResolver { export type Intersect = ( IntersectType.Resolve>> ) - export function Intersect(T: T, K: K): Intersect { - const C = Collect(T, K) - const E = IntersectEvaluate(C) + export function Intersect(T: [...T], K: K): Intersect { return ( - IntersectType.Resolve(IntersectEvaluate(Collect(T, K))) + IntersectType.Resolve(IntersectEvaluate(Collect(T as TSchema[], K))) ) as Intersect } // ---------------------------------------------------------------- @@ -2790,7 +2979,7 @@ export namespace AccessResolver { : UnionEvaluate : S ) - export function UnionEvaluate(T: T, S = T): UnionEvaluate { + export function UnionEvaluate(T: [...T], S = T): UnionEvaluate { const [L, ...R] = T return ( T.length > 0 @@ -2803,10 +2992,10 @@ export namespace AccessResolver { export type Union = ( UnionType.Resolve>> ) - export function Union(T: T, K: K): Union { + export function Union(T: [...T], K: K): Union { return ( - UnionType.Resolve(UnionEvaluate(Collect(T, K))) - ) + UnionType.Resolve(UnionEvaluate(Collect(T as TSchema[], K))) + ) as Union } // ---------------------------------------------------------------- // Tuple @@ -2816,7 +3005,7 @@ export namespace AccessResolver { K extends 'number' ? UnionType.Resolve : TNever ) - export function Tuple(T: T, K: K): Tuple { + export function Tuple(T: [...T], K: K): Tuple { return ( K in T ? T[K as number] : K === 'number' ? UnionType.Resolve(T) : @@ -2883,7 +3072,7 @@ export namespace AccessResolver { ? [Key, ...Keys] : [] ) - export function Keys(T: T, K: K): Keys { + export function Keys(T: T, K: [...K]): Keys { const [L, ...R] = K return ( K.length > 0 @@ -2897,7 +3086,7 @@ export namespace AccessResolver { export type Resolve = ( UnionType.Resolve> ) - export function Resolve(T: T, K: K): Resolve { + export function Resolve(T: T, K: [...K]): Resolve { return ( UnionType.Resolve(Keys(T, K)) ) as Resolve @@ -3325,7 +3514,7 @@ export class JsonTypeBuilder extends TypeBuilder { /** `[Json]` Creates a Composite object type */ public Composite(objects: [...T], options?: ObjectOptions): TComposite { const intersect: any = Type.Intersect(objects, {}) - const keys = KeyResolver.Keys(intersect, { includePatterns: false }) + const keys = KeyResolver.Resolve(intersect) const properties = keys.reduce((acc, key) => ({ ...acc, [key]: Type.Index(intersect, [key]) }), {} as TProperties) return Type.Object(properties, options) as TComposite } @@ -3427,7 +3616,7 @@ export class JsonTypeBuilder extends TypeBuilder { TypeGuard.TArray(schema) ? (() => { return this.Number(options) })() : (() => { - const keys = KeyResolver.Keys(schema, { includePatterns: false }) + const keys = KeyResolver.Resolve(schema) if (keys.length === 0) return this.Never(options) as TKeyOf const literals = keys.map((key) => this.Literal(key)) return this.Union(literals, options) diff --git a/src/value/check.ts b/src/value/check.ts index 3d048c5b4..7e987708c 100644 --- a/src/value/check.ts +++ b/src/value/check.ts @@ -164,11 +164,11 @@ function TInteger(schema: Types.TInteger, references: Types.TSchema[], value: an function TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: any): boolean { const check1 = schema.allOf.every((schema) => Visit(schema, references, value)) if (schema.unevaluatedProperties === false) { - const keyPattern = new RegExp(Types.KeyResolver.Pattern(schema)) + const keyPattern = new RegExp(Types.KeyResolver.ResolvePattern(schema)) const check2 = Object.getOwnPropertyNames(value).every((key) => keyPattern.test(key)) return check1 && check2 } else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) { - const keyCheck = new RegExp(Types.KeyResolver.Pattern(schema)) + const keyCheck = new RegExp(Types.KeyResolver.ResolvePattern(schema)) const check2 = Object.getOwnPropertyNames(value).every((key) => keyCheck.test(key) || Visit(schema.unevaluatedProperties as Types.TSchema, references, value[key])) return check1 && check2 } else { diff --git a/src/value/transform.ts b/src/value/transform.ts index b512824a2..157cea4e2 100644 --- a/src/value/transform.ts +++ b/src/value/transform.ts @@ -174,7 +174,7 @@ export namespace DecodeTransform { // prettier-ignore function TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: any) { if (!IsPlainObject(value) || IsValueType(value)) return Default(schema, value) - const knownKeys = Types.KeyResolver.Keys(schema, { includePatterns: false }) + const knownKeys = Types.KeyResolver.Resolve(schema, { includePatterns: false }) const knownProperties = knownKeys.reduce((value, key) => { return (key in value) ? { ...value, [key]: Visit(Types.AccessResolver.Resolve(schema, [key]), references, value[key]) } @@ -198,7 +198,7 @@ export namespace DecodeTransform { // prettier-ignore function TObject(schema: Types.TObject, references: Types.TSchema[], value: any) { if (!IsPlainObject(value)) return Default(schema, value) - const knownKeys = Types.KeyResolver.Keys(schema, { includePatterns: false }) + const knownKeys = Types.KeyResolver.Resolve(schema, { includePatterns: false }) const knownProperties = knownKeys.reduce((value, key) => { return (key in value) ? { ...value, [key]: Visit(schema.properties[key], references, value[key]) } @@ -315,7 +315,7 @@ export namespace EncodeTransform { function TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: any) { const defaulted = Default(schema, value) if (!IsPlainObject(value) || IsValueType(value)) return defaulted - const knownKeys = Types.KeyResolver.Keys(schema, { includePatterns: false }) + const knownKeys = Types.KeyResolver.Resolve(schema, { includePatterns: false }) const knownProperties = knownKeys.reduce((value, key) => { return key in defaulted ? { ...value, [key]: Visit(Types.AccessResolver.Resolve(schema, [key]), references, value[key]) } @@ -339,7 +339,7 @@ export namespace EncodeTransform { function TObject(schema: Types.TObject, references: Types.TSchema[], value: any) { const defaulted = Default(schema, value) if (!IsPlainObject(value)) return defaulted - const knownKeys = Types.KeyResolver.Keys(schema, { includePatterns: false }) + const knownKeys = Types.KeyResolver.Resolve(schema, { includePatterns: false }) const knownProperties = knownKeys.reduce((value, key) => { return key in value ? { ...value, [key]: Visit(schema.properties[key], references, value[key]) }