diff --git a/src/value/transform.ts b/src/value/transform.ts index c312990dd..92cc43ee4 100644 --- a/src/value/transform.ts +++ b/src/value/transform.ts @@ -199,9 +199,11 @@ export namespace DecodeTransform { throw new TransformDecodeError(schema, value, error) } } + // prettier-ignore function TArray(schema: Types.TArray, references: Types.TSchema[], value: any): any { - const elements1 = value.map((value: any) => Visit(schema.items, references, value)) as unknown[] - return Default(schema, elements1) + return (IsArray(value)) + ? Default(schema, value.map((value: any) => Visit(schema.items, references, value))) + : Default(schema, value) } // prettier-ignore function TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: any) { @@ -225,8 +227,7 @@ export namespace DecodeTransform { return Default(schema, unknownProperties) } function TNot(schema: Types.TNot, references: Types.TSchema[], value: any) { - const value1 = Visit(schema.not, references, value) - return Default(schema, value1) + return Default(schema, Visit(schema.not, references, value)) } // prettier-ignore function TObject(schema: Types.TObject, references: Types.TSchema[], value: any) { @@ -249,22 +250,27 @@ export namespace DecodeTransform { }, knownProperties) return Default(schema, unknownProperties) } + // prettier-ignore function TRecord(schema: Types.TRecord, references: Types.TSchema[], value: any) { if (!IsPlainObject(value)) return Default(schema, value) const pattern = Object.getOwnPropertyNames(schema.patternProperties)[0] - const property = schema.patternProperties[pattern] - const regex = new RegExp(pattern) - const properties1 = Object.entries(value).reduce((acc, [key, value]) => { - return !regex.test(key) ? { ...acc, [key]: value } : { ...acc, [key]: Visit(property, references, value) } - }, {} as Record) + const knownKeys = new RegExp(pattern) + const knownProperties = Object.getOwnPropertyNames(value).reduce((value, key) => { + return knownKeys.test(key) + ? { ...value, [key]: Visit(schema.patternProperties[pattern], references, value[key]) } + : value + }, value) if (!Types.TypeGuard.TSchema(schema.additionalProperties)) { - return Default(schema, properties1) + return Default(schema, knownProperties) } + const unknownKeys = Object.getOwnPropertyNames(knownProperties) const additionalProperties = schema.additionalProperties as Types.TSchema - const properties2 = Object.entries(properties1).reduce((acc, [key, value]) => { - return regex.test(key) ? { ...acc, [key]: value } : { ...acc, [key]: Visit(additionalProperties, references, value) } - }, {} as Record) - return Default(schema, properties2) + const unknownProperties = unknownKeys.reduce((value, key) => { + return !knownKeys.test(key) + ? { ...value, [key]: Default(additionalProperties, value[key]) } + : value + }, knownProperties) + return Default(schema, unknownProperties) } function TRef(schema: Types.TRef, references: Types.TSchema[], value: any) { const target = Deref(schema, references) @@ -276,25 +282,24 @@ export namespace DecodeTransform { const resolved = Visit(target, references, value) return Default(schema, resolved) } + // prettier-ignore function TTuple(schema: Types.TTuple, references: Types.TSchema[], value: any) { - const value1 = IsArray(schema.items) ? schema.items.map((schema, index) => Visit(schema, references, value[index])) : [] - return Default(schema, value1) + return (IsArray(value) && IsArray(schema.items)) + ? Default(schema, schema.items.map((schema, index) => Visit(schema, references, value[index]))) + : Default(schema, value) } function TUnion(schema: Types.TUnion, references: Types.TSchema[], value: any) { - const value1 = Default(schema, value) + const defaulted = Default(schema, value) for (const subschema of schema.anyOf) { - if (!Check(subschema, references, value1)) continue - return Visit(subschema, references, value1) + if (!Check(subschema, references, defaulted)) continue + return Visit(subschema, references, defaulted) } - return value1 + return defaulted } function Visit(schema: Types.TSchema, references: Types.TSchema[], value: any): any { const references_ = typeof schema.$id === 'string' ? [...references, schema] : references const schema_ = schema as any switch (schema[Types.Kind]) { - // ------------------------------------------------------ - // Structural - // ------------------------------------------------------ case 'Array': return TArray(schema_, references_, value) case 'Intersect': @@ -315,32 +320,7 @@ export namespace DecodeTransform { return TTuple(schema_, references_, value) case 'Union': return TUnion(schema_, references_, value) - // ------------------------------------------------------ - // Default - // ------------------------------------------------------ - case 'Any': - case 'AsyncIterator': - case 'BigInt': - case 'Boolean': - case 'Constructor': - case 'Date': - case 'Function': - case 'Integer': - case 'Iterator': - case 'Literal': - case 'Never': - case 'Null': - case 'Number': - case 'Promise': - case 'String': - case 'TemplateLiteral': - case 'Undefined': - case 'Uint8Array': - case 'Unknown': - case 'Void': - return Default(schema_, value) default: - if (!Types.TypeRegistry.Has(schema_[Types.Kind])) throw new TransformUnknownTypeError(schema_) return Default(schema_, value) } }