/* @flow */ import { emptyObject } from 'shared/util' import { parseFilters } from './parser/filter-parser' type Range = { start?: number, end?: number }; /* eslint-disable no-unused-vars */ export function baseWarn (msg: string, range?: Range) { console.error(`[Vue compiler]: ${msg}`) } /* eslint-enable no-unused-vars */ export function pluckModuleFunction<F: Function> ( modules: ?Array<Object>, key: string ): Array<F> { return modules ? modules.map(m => m[key]).filter(_ => _) : [] } export function addProp (el: ASTElement, name: string, value: string, range?: Range, dynamic?: boolean) { (el.props || (el.props = [])).push(rangeSetItem({ name, value, dynamic }, range)) el.plain = false } export function addAttr (el: ASTElement, name: string, value: any, range?: Range, dynamic?: boolean) { const attrs = dynamic ? (el.dynamicAttrs || (el.dynamicAttrs = [])) : (el.attrs || (el.attrs = [])) attrs.push(rangeSetItem({ name, value, dynamic }, range)) el.plain = false } // add a raw attr (use this in preTransforms) export function addRawAttr (el: ASTElement, name: string, value: any, range?: Range) { el.attrsMap[name] = value el.attrsList.push(rangeSetItem({ name, value }, range)) } export function addDirective ( el: ASTElement, name: string, rawName: string, value: string, arg: ?string, isDynamicArg: boolean, modifiers: ?ASTModifiers, range?: Range ) { (el.directives || (el.directives = [])).push(rangeSetItem({ name, rawName, value, arg, isDynamicArg, modifiers }, range)) el.plain = false } function prependModifierMarker (symbol: string, name: string, dynamic?: boolean): string { return dynamic ? `_p(${name},"${symbol}")` : symbol + name // mark the event as captured } export function addHandler ( el: ASTElement, name: string, value: string, modifiers: ?ASTModifiers, important?: boolean, warn?: ?Function, range?: Range, dynamic?: boolean ) { modifiers = modifiers || emptyObject // warn prevent and passive modifier /* istanbul ignore if */ if ( process.env.NODE_ENV !== 'production' && warn && modifiers.prevent && modifiers.passive ) { warn( 'passive and prevent can\'t be used together. ' + 'Passive handler can\'t prevent default event.', range ) } // normalize click.right and click.middle since they don't actually fire // this is technically browser-specific, but at least for now browsers are // the only target envs that have right/middle clicks. if (modifiers.right) { if (dynamic) { name = `(${name})==='click'?'contextmenu':(${name})` } else if (name === 'click') { name = 'contextmenu' delete modifiers.right } } else if (modifiers.middle) { if (dynamic) { name = `(${name})==='click'?'mouseup':(${name})` } else if (name === 'click') { name = 'mouseup' } } // check capture modifier if (modifiers.capture) { delete modifiers.capture name = prependModifierMarker('!', name, dynamic) } if (modifiers.once) { delete modifiers.once name = prependModifierMarker('~', name, dynamic) } /* istanbul ignore if */ if (modifiers.passive) { delete modifiers.passive name = prependModifierMarker('&', name, dynamic) } let events if (modifiers.native) { delete modifiers.native events = el.nativeEvents || (el.nativeEvents = {}) } else { events = el.events || (el.events = {}) } const newHandler: any = rangeSetItem({ value: value.trim(), dynamic }, range) if (modifiers !== emptyObject) { newHandler.modifiers = modifiers } const handlers = events[name] /* istanbul ignore if */ if (Array.isArray(handlers)) { important ? handlers.unshift(newHandler) : handlers.push(newHandler) } else if (handlers) { events[name] = important ? [newHandler, handlers] : [handlers, newHandler] } else { events[name] = newHandler } el.plain = false } export function getRawBindingAttr ( el: ASTElement, name: string ) { return el.rawAttrsMap[':' + name] || el.rawAttrsMap['v-bind:' + name] || el.rawAttrsMap[name] } export function getBindingAttr ( el: ASTElement, name: string, getStatic?: boolean ): ?string { const dynamicValue = getAndRemoveAttr(el, ':' + name) || getAndRemoveAttr(el, 'v-bind:' + name) if (dynamicValue != null) { return parseFilters(dynamicValue) } else if (getStatic !== false) { const staticValue = getAndRemoveAttr(el, name) if (staticValue != null) { return JSON.stringify(staticValue) } } } // note: this only removes the attr from the Array (attrsList) so that it // doesn't get processed by processAttrs. // By default it does NOT remove it from the map (attrsMap) because the map is // needed during codegen. export function getAndRemoveAttr ( el: ASTElement, name: string, removeFromMap?: boolean ): ?string { let val if ((val = el.attrsMap[name]) != null) { const list = el.attrsList for (let i = 0, l = list.length; i < l; i++) { if (list[i].name === name) { list.splice(i, 1) break } } } if (removeFromMap) { delete el.attrsMap[name] } return val } export function getAndRemoveAttrByRegex ( el: ASTElement, name: RegExp ) { const list = el.attrsList for (let i = 0, l = list.length; i < l; i++) { const attr = list[i] if (name.test(attr.name)) { list.splice(i, 1) return attr } } } function rangeSetItem ( item: any, range?: { start?: number, end?: number } ) { if (range) { if (range.start != null) { item.start = range.start } if (range.end != null) { item.end = range.end } } return item }