import { emptyObject } from 'shared/util'
|
import { ASTElement, ASTModifiers } from 'types/compiler'
|
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<T, K extends keyof T>(
|
modules: Array<T> | undefined,
|
key: K
|
): Array<Exclude<T[K], undefined>> {
|
return modules ? (modules.map(m => m[key]).filter(_ => _) as any) : []
|
}
|
|
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 | null,
|
important?: boolean,
|
warn?: Function,
|
range?: Range,
|
dynamic?: boolean
|
) {
|
modifiers = modifiers || emptyObject
|
// warn prevent and passive modifier
|
/* istanbul ignore if */
|
if (__DEV__ && 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 | undefined {
|
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 | undefined {
|
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
|
}
|