text: /* @flow */
  
  import { emptyObject } from 'shared/util'
  import { parseFilters } from './parser/filter-parser'
  
  export function baseWarn (msg: string) {
    console.error(`[Vue compiler]: ${msg}`)
  }
  
  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) {
    (el.props || (el.props = [])).push({ name, value })
    el.plain = false
  }
  
  export function addAttr (el: ASTElement, name: string, value: any) {
    (el.attrs || (el.attrs = [])).push({ name, value })
    el.plain = false
  }
  
  // add a raw attr (use this in preTransforms)
  export function addRawAttr (el: ASTElement, name: string, value: any) {
    el.attrsMap[name] = value
    el.attrsList.push({ name, value })
  }
  
  export function addDirective (
    el: ASTElement,
    name: string,
    rawName: string,
    value: string,
    arg: ?string,
    modifiers: ?ASTModifiers
  ) {
    (el.directives || (el.directives = [])).push({ name, rawName, value, arg, modifiers })
    el.plain = false
  }
  
  export function addHandler (
    el: ASTElement,
    name: string,
    value: string,
    modifiers: ?ASTModifiers,
    important?: boolean,
    warn?: Function
  ) {
    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.'
      )
    }
  
    // check capture modifier
    if (modifiers.capture) {
      delete modifiers.capture
      name = '!' + name // mark the event as captured
    }
    if (modifiers.once) {
      delete modifiers.once
      name = '~' + name // mark the event as once
    }
    /* istanbul ignore if */
    if (modifiers.passive) {
      delete modifiers.passive
      name = '&' + name // mark the event as passive
    }
  
    // 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 (name === 'click') {
      if (modifiers.right) {
        name = 'contextmenu'
        delete modifiers.right
      } else if (modifiers.middle) {
        name = 'mouseup'
      }
    }
  
    let events
    if (modifiers.native) {
      delete modifiers.native
      events = el.nativeEvents || (el.nativeEvents = {})
    } else {
      events = el.events || (el.events = {})
    }
  
    const newHandler: any = { value }
    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 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
  }
  