File: /var/www/vhost/disk-apps/alq-cali.bikenow.co/node_modules/vue/src/core/util/props.ts
import { warn } from './debug'
import { observe, toggleObserving, shouldObserve } from '../observer/index'
import {
hasOwn,
isArray,
isObject,
isFunction,
toRawType,
hyphenate,
capitalize,
isPlainObject
} from 'shared/util'
import type { Component } from 'types/component'
type PropOptions = {
type: Function | Array<Function> | null
default: any
required?: boolean
validator?: Function
}
export function validateProp(
key: string,
propOptions: Object,
propsData: Object,
vm?: Component
): any {
const prop = propOptions[key]
const absent = !hasOwn(propsData, key)
let value = propsData[key]
// boolean casting
const booleanIndex = getTypeIndex(Boolean, prop.type)
if (booleanIndex > -1) {
if (absent && !hasOwn(prop, 'default')) {
value = false
} else if (value === '' || value === hyphenate(key)) {
// only cast empty string / same name to boolean if
// boolean has higher priority
const stringIndex = getTypeIndex(String, prop.type)
if (stringIndex < 0 || booleanIndex < stringIndex) {
value = true
}
}
}
// check default value
if (value === undefined) {
value = getPropDefaultValue(vm, prop, key)
// since the default value is a fresh copy,
// make sure to observe it.
const prevShouldObserve = shouldObserve
toggleObserving(true)
observe(value)
toggleObserving(prevShouldObserve)
}
if (__DEV__) {
assertProp(prop, key, value, vm, absent)
}
return value
}
/**
* Get the default value of a prop.
*/
function getPropDefaultValue(
vm: Component | undefined,
prop: PropOptions,
key: string
): any {
// no default, return undefined
if (!hasOwn(prop, 'default')) {
return undefined
}
const def = prop.default
// warn against non-factory defaults for Object & Array
if (__DEV__ && isObject(def)) {
warn(
'Invalid default value for prop "' +
key +
'": ' +
'Props with type Object/Array must use a factory function ' +
'to return the default value.',
vm
)
}
// the raw prop value was also undefined from previous render,
// return previous default value to avoid unnecessary watcher trigger
if (
vm &&
vm.$options.propsData &&
vm.$options.propsData[key] === undefined &&
vm._props[key] !== undefined
) {
return vm._props[key]
}
// call factory function for non-Function types
// a value is Function if its prototype is function even across different execution context
return isFunction(def) && getType(prop.type) !== 'Function'
? def.call(vm)
: def
}
/**
* Assert whether a prop is valid.
*/
function assertProp(
prop: PropOptions,
name: string,
value: any,
vm?: Component,
absent?: boolean
) {
if (prop.required && absent) {
warn('Missing required prop: "' + name + '"', vm)
return
}
if (value == null && !prop.required) {
return
}
let type = prop.type
let valid = !type || (type as any) === true
const expectedTypes: string[] = []
if (type) {
if (!isArray(type)) {
type = [type]
}
for (let i = 0; i < type.length && !valid; i++) {
const assertedType = assertType(value, type[i], vm)
expectedTypes.push(assertedType.expectedType || '')
valid = assertedType.valid
}
}
const haveExpectedTypes = expectedTypes.some(t => t)
if (!valid && haveExpectedTypes) {
warn(getInvalidTypeMessage(name, value, expectedTypes), vm)
return
}
const validator = prop.validator
if (validator) {
if (!validator(value)) {
warn(
'Invalid prop: custom validator check failed for prop "' + name + '".',
vm
)
}
}
}
const simpleCheckRE = /^(String|Number|Boolean|Function|Symbol|BigInt)$/
function assertType(
value: any,
type: Function,
vm?: Component
): {
valid: boolean
expectedType: string
} {
let valid
const expectedType = getType(type)
if (simpleCheckRE.test(expectedType)) {
const t = typeof value
valid = t === expectedType.toLowerCase()
// for primitive wrapper objects
if (!valid && t === 'object') {
valid = value instanceof type
}
} else if (expectedType === 'Object') {
valid = isPlainObject(value)
} else if (expectedType === 'Array') {
valid = isArray(value)
} else {
try {
valid = value instanceof type
} catch (e: any) {
warn('Invalid prop type: "' + String(type) + '" is not a constructor', vm)
valid = false
}
}
return {
valid,
expectedType
}
}
const functionTypeCheckRE = /^\s*function (\w+)/
/**
* Use function string name to check built-in types,
* because a simple equality check will fail when running
* across different vms / iframes.
*/
function getType(fn) {
const match = fn && fn.toString().match(functionTypeCheckRE)
return match ? match[1] : ''
}
function isSameType(a, b) {
return getType(a) === getType(b)
}
function getTypeIndex(type, expectedTypes): number {
if (!isArray(expectedTypes)) {
return isSameType(expectedTypes, type) ? 0 : -1
}
for (let i = 0, len = expectedTypes.length; i < len; i++) {
if (isSameType(expectedTypes[i], type)) {
return i
}
}
return -1
}
function getInvalidTypeMessage(name, value, expectedTypes) {
let message =
`Invalid prop: type check failed for prop "${name}".` +
` Expected ${expectedTypes.map(capitalize).join(', ')}`
const expectedType = expectedTypes[0]
const receivedType = toRawType(value)
// check if we need to specify expected value
if (
expectedTypes.length === 1 &&
isExplicable(expectedType) &&
isExplicable(typeof value) &&
!isBoolean(expectedType, receivedType)
) {
message += ` with value ${styleValue(value, expectedType)}`
}
message += `, got ${receivedType} `
// check if we need to specify received value
if (isExplicable(receivedType)) {
message += `with value ${styleValue(value, receivedType)}.`
}
return message
}
function styleValue(value, type) {
if (type === 'String') {
return `"${value}"`
} else if (type === 'Number') {
return `${Number(value)}`
} else {
return `${value}`
}
}
const EXPLICABLE_TYPES = ['string', 'number', 'boolean']
function isExplicable(value) {
return EXPLICABLE_TYPES.some(elem => value.toLowerCase() === elem)
}
function isBoolean(...args) {
return args.some(elem => elem.toLowerCase() === 'boolean')
}