import { warn } from './debug' import { resolveAsset } from './options' import { getAttr, getBindAttr } from './dom' import { isArray, isPlainObject } from './lang' export const commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/ export const reservedTagRE = /^(slot|partial|component)$/ /** * Check if an element is a component, if yes return its * component id. * * @param {Element} el * @param {Object} options * @return {Object|undefined} */ export function checkComponentAttr (el, options) { var tag = el.tagName.toLowerCase() var hasAttrs = el.hasAttributes() if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { if (resolveAsset(options, 'components', tag)) { return { id: tag } } else { var is = hasAttrs && getIsBinding(el) if (is) { return is } else if (process.env.NODE_ENV !== 'production') { if ( tag.indexOf('-') > -1 || ( /HTMLUnknownElement/.test(el.toString()) && // Chrome returns unknown for several HTML5 elements. // https://code.google.com/p/chromium/issues/detail?id=540526 !/^(data|time|rtc|rb)$/.test(tag) ) ) { warn( 'Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly?' ) } } } } else if (hasAttrs) { return getIsBinding(el) } } /** * Get "is" binding from an element. * * @param {Element} el * @return {Object|undefined} */ function getIsBinding (el) { // dynamic syntax var exp = getAttr(el, 'is') if (exp != null) { return { id: exp } } else { exp = getBindAttr(el, 'is') if (exp != null) { return { id: exp, dynamic: true } } } } /** * Set a prop's initial value on a vm and its data object. * * @param {Vue} vm * @param {Object} prop * @param {*} value */ export function initProp (vm, prop, value) { const key = prop.path value = coerceProp(prop, value) vm[key] = vm._data[key] = assertProp(prop, value) ? value : undefined } /** * Assert whether a prop is valid. * * @param {Object} prop * @param {*} value */ export function assertProp (prop, value) { // if a prop is not provided and is not required, // skip the check. if (prop.raw === null && !prop.required) { return true } var options = prop.options var type = options.type var valid = true var expectedType if (type) { if (type === String) { expectedType = 'string' valid = typeof value === expectedType } else if (type === Number) { expectedType = 'number' valid = typeof value === 'number' } else if (type === Boolean) { expectedType = 'boolean' valid = typeof value === 'boolean' } else if (type === Function) { expectedType = 'function' valid = typeof value === 'function' } else if (type === Object) { expectedType = 'object' valid = isPlainObject(value) } else if (type === Array) { expectedType = 'array' valid = isArray(value) } else { valid = value instanceof type } } if (!valid) { process.env.NODE_ENV !== 'production' && warn( 'Invalid prop: type check failed for ' + prop.path + '="' + prop.raw + '".' + ' Expected ' + formatType(expectedType) + ', got ' + formatValue(value) + '.' ) return false } var validator = options.validator if (validator) { if (!validator.call(null, value)) { process.env.NODE_ENV !== 'production' && warn( 'Invalid prop: custom validator check failed for ' + prop.path + '="' + prop.raw + '"' ) return false } } return true } /** * Force parsing value with coerce option. * * @param {*} value * @param {Object} options * @return {*} */ export function coerceProp (prop, value) { var coerce = prop.options.coerce if (!coerce) { return value } // coerce is a function return coerce(value) } function formatType (val) { return val ? val.charAt(0).toUpperCase() + val.slice(1) : 'custom type' } function formatValue (val) { return Object.prototype.toString.call(val).slice(8, -1) }