66 lines
1.7 KiB
TypeScript
66 lines
1.7 KiB
TypeScript
import { isObject, objectClone, objectLoop } from '@dzeio/object-util'
|
|
import SchemaItem from '../SchemaItem'
|
|
import { SchemaInfer, ValidationResult } from '../types'
|
|
|
|
type ModelInfer<M extends Record<string, SchemaItem>> = {
|
|
[key in keyof M]: SchemaInfer<M[key]>
|
|
}
|
|
|
|
export default class SchemaObject<T extends Record<string, SchemaItem> = any> extends SchemaItem<ModelInfer<T>> {
|
|
public id = 'object'
|
|
|
|
public constructor(public readonly model: T) {
|
|
super([model])
|
|
}
|
|
|
|
public override parse(input: unknown, options?: { fast?: boolean }): ValidationResult<ModelInfer<T>> {
|
|
// check errors from itself
|
|
const { valid, object, errors = [] } = super.parse(input, options)
|
|
|
|
// skip checking childs if self is not valid (maybe still try to check childs whan fast is false ?)
|
|
if (!valid) {
|
|
return {
|
|
valid,
|
|
object,
|
|
errors
|
|
} as ValidationResult<ModelInfer<T>>
|
|
}
|
|
|
|
const clone = objectClone(object)
|
|
|
|
// loop through the childs
|
|
objectLoop(this.model, (childSchema, key) => {
|
|
const childValue = clone[key]
|
|
|
|
// parse the child
|
|
const child = childSchema.parse(childValue)
|
|
|
|
// add errors
|
|
if (!child.valid) {
|
|
errors.push(...child.errors.map((it) => ({
|
|
...it,
|
|
field: it.field ? `${key}.${it.field}` : key
|
|
})))
|
|
}
|
|
|
|
// @ts-expect-error while it's a generic we know by proof above that it's valid !
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
clone[key] = child.object
|
|
|
|
// skip rest of items if current one is invalid
|
|
return child.valid || !options?.fast
|
|
})
|
|
|
|
// answer !
|
|
return {
|
|
valid: errors.length === 0,
|
|
errors: errors,
|
|
object: clone
|
|
} as ValidationResult<ModelInfer<T>>
|
|
}
|
|
|
|
public override isOfType(input: unknown): input is ModelInfer<T> {
|
|
return isObject(input)
|
|
}
|
|
}
|