UNPKG

vue-types

Version:
75 lines (66 loc) 2.17 kB
import { Prop, VueProp, VueTypeShape, VueTypeLooseShape } from '../types' import { toType, validateType, warn, isPlainObject, indent } from '../utils' // eslint-disable-next-line @typescript-eslint/ban-types export default function shape<T extends object>( obj: { [K in keyof T]: Prop<T[K]> | VueProp<T[K]> }, ): VueTypeShape<T> { const keys = Object.keys(obj) const requiredKeys = keys.filter((key) => !!(obj as any)[key]?.required) const type = toType('shape', { type: Object, validator(this: VueTypeShape<T> | VueTypeLooseShape<T>, value) { if (!isPlainObject(value)) { return false } const valueKeys = Object.keys(value) // check for required keys (if any) if ( requiredKeys.length > 0 && requiredKeys.some((req) => valueKeys.indexOf(req) === -1) ) { const missing = requiredKeys.filter( (req) => valueKeys.indexOf(req) === -1, ) if (missing.length === 1) { warn(`shape - required property "${missing[0]}" is not defined.`) } else { warn( `shape - required properties "${missing.join( '", "', )}" are not defined.`, ) } return false } return valueKeys.every((key) => { if (keys.indexOf(key) === -1) { if ((this as VueTypeLooseShape<T>)._vueTypes_isLoose === true) return true warn( `shape - shape definition does not include a "${key}" property. Allowed keys: "${keys.join( '", "', )}".`, ) return false } const type = (obj as any)[key] const valid = validateType(type, value[key], true) if (typeof valid === 'string') { warn(`shape - "${key}" property validation error:\n ${indent(valid)}`) } return valid === true }) }, }) as VueTypeShape<T> Object.defineProperty(type, '_vueTypes_isLoose', { writable: true, value: false, }) Object.defineProperty(type, 'loose', { get() { this._vueTypes_isLoose = true return this }, }) return type }