github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/util/options.js (about)

     1  import Vue from '../instance/vue'
     2  import config from '../config'
     3  import {
     4    extend,
     5    set,
     6    isObject,
     7    isArray,
     8    isPlainObject,
     9    hasOwn,
    10    camelize,
    11    hyphenate
    12  } from './lang'
    13  import { warn } from './debug'
    14  import { commonTagRE, reservedTagRE } from './component'
    15  
    16  /**
    17   * Option overwriting strategies are functions that handle
    18   * how to merge a parent option value and a child option
    19   * value into the final value.
    20   *
    21   * All strategy functions follow the same signature:
    22   *
    23   * @param {*} parentVal
    24   * @param {*} childVal
    25   * @param {Vue} [vm]
    26   */
    27  
    28  var strats = config.optionMergeStrategies = Object.create(null)
    29  
    30  /**
    31   * Helper that recursively merges two data objects together.
    32   */
    33  
    34  function mergeData (to, from) {
    35    var key, toVal, fromVal
    36    for (key in from) {
    37      toVal = to[key]
    38      fromVal = from[key]
    39      if (!hasOwn(to, key)) {
    40        set(to, key, fromVal)
    41      } else if (isObject(toVal) && isObject(fromVal)) {
    42        mergeData(toVal, fromVal)
    43      }
    44    }
    45    return to
    46  }
    47  
    48  /**
    49   * Data
    50   */
    51  
    52  strats.data = function (parentVal, childVal, vm) {
    53    if (!vm) {
    54      // in a Vue.extend merge, both should be functions
    55      if (!childVal) {
    56        return parentVal
    57      }
    58      if (typeof childVal !== 'function') {
    59        process.env.NODE_ENV !== 'production' && warn(
    60          'The "data" option should be a function ' +
    61          'that returns a per-instance value in component ' +
    62          'definitions.',
    63          vm
    64        )
    65        return parentVal
    66      }
    67      if (!parentVal) {
    68        return childVal
    69      }
    70      // when parentVal & childVal are both present,
    71      // we need to return a function that returns the
    72      // merged result of both functions... no need to
    73      // check if parentVal is a function here because
    74      // it has to be a function to pass previous merges.
    75      return function mergedDataFn () {
    76        return mergeData(
    77          childVal.call(this),
    78          parentVal.call(this)
    79        )
    80      }
    81    } else if (parentVal || childVal) {
    82      return function mergedInstanceDataFn () {
    83        // instance merge
    84        var instanceData = typeof childVal === 'function'
    85          ? childVal.call(vm)
    86          : childVal
    87        var defaultData = typeof parentVal === 'function'
    88          ? parentVal.call(vm)
    89          : undefined
    90        if (instanceData) {
    91          return mergeData(instanceData, defaultData)
    92        } else {
    93          return defaultData
    94        }
    95      }
    96    }
    97  }
    98  
    99  /**
   100   * El
   101   */
   102  
   103  strats.el = function (parentVal, childVal, vm) {
   104    if (!vm && childVal && typeof childVal !== 'function') {
   105      process.env.NODE_ENV !== 'production' && warn(
   106        'The "el" option should be a function ' +
   107        'that returns a per-instance value in component ' +
   108        'definitions.',
   109        vm
   110      )
   111      return
   112    }
   113    var ret = childVal || parentVal
   114    // invoke the element factory if this is instance merge
   115    return vm && typeof ret === 'function'
   116      ? ret.call(vm)
   117      : ret
   118  }
   119  
   120  /**
   121   * Hooks and param attributes are merged as arrays.
   122   */
   123  
   124  strats.init =
   125  strats.created =
   126  strats.ready =
   127  strats.attached =
   128  strats.detached =
   129  strats.beforeCompile =
   130  strats.compiled =
   131  strats.beforeDestroy =
   132  strats.destroyed =
   133  strats.activate = function (parentVal, childVal) {
   134    return childVal
   135      ? parentVal
   136        ? parentVal.concat(childVal)
   137        : isArray(childVal)
   138          ? childVal
   139          : [childVal]
   140      : parentVal
   141  }
   142  
   143  /**
   144   * Assets
   145   *
   146   * When a vm is present (instance creation), we need to do
   147   * a three-way merge between constructor options, instance
   148   * options and parent options.
   149   */
   150  
   151  function mergeAssets (parentVal, childVal) {
   152    var res = Object.create(parentVal || null)
   153    return childVal
   154      ? extend(res, guardArrayAssets(childVal))
   155      : res
   156  }
   157  
   158  config._assetTypes.forEach(function (type) {
   159    strats[type + 's'] = mergeAssets
   160  })
   161  
   162  /**
   163   * Events & Watchers.
   164   *
   165   * Events & watchers hashes should not overwrite one
   166   * another, so we merge them as arrays.
   167   */
   168  
   169  strats.watch =
   170  strats.events = function (parentVal, childVal) {
   171    if (!childVal) return parentVal
   172    if (!parentVal) return childVal
   173    var ret = {}
   174    extend(ret, parentVal)
   175    for (var key in childVal) {
   176      var parent = ret[key]
   177      var child = childVal[key]
   178      if (parent && !isArray(parent)) {
   179        parent = [parent]
   180      }
   181      ret[key] = parent
   182        ? parent.concat(child)
   183        : [child]
   184    }
   185    return ret
   186  }
   187  
   188  /**
   189   * Other object hashes.
   190   */
   191  
   192  strats.props =
   193  strats.methods =
   194  strats.computed = function (parentVal, childVal) {
   195    if (!childVal) return parentVal
   196    if (!parentVal) return childVal
   197    var ret = Object.create(null)
   198    extend(ret, parentVal)
   199    extend(ret, childVal)
   200    return ret
   201  }
   202  
   203  /**
   204   * Default strategy.
   205   */
   206  
   207  var defaultStrat = function (parentVal, childVal) {
   208    return childVal === undefined
   209      ? parentVal
   210      : childVal
   211  }
   212  
   213  /**
   214   * Make sure component options get converted to actual
   215   * constructors.
   216   *
   217   * @param {Object} options
   218   */
   219  
   220  function guardComponents (options) {
   221    if (options.components) {
   222      var components = options.components =
   223        guardArrayAssets(options.components)
   224      var ids = Object.keys(components)
   225      var def
   226      if (process.env.NODE_ENV !== 'production') {
   227        var map = options._componentNameMap = {}
   228      }
   229      for (var i = 0, l = ids.length; i < l; i++) {
   230        var key = ids[i]
   231        if (commonTagRE.test(key) || reservedTagRE.test(key)) {
   232          process.env.NODE_ENV !== 'production' && warn(
   233            'Do not use built-in or reserved HTML elements as component ' +
   234            'id: ' + key
   235          )
   236          continue
   237        }
   238        // record a all lowercase <-> kebab-case mapping for
   239        // possible custom element case error warning
   240        if (process.env.NODE_ENV !== 'production') {
   241          map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key)
   242        }
   243        def = components[key]
   244        if (isPlainObject(def)) {
   245          components[key] = Vue.extend(def)
   246        }
   247      }
   248    }
   249  }
   250  
   251  /**
   252   * Ensure all props option syntax are normalized into the
   253   * Object-based format.
   254   *
   255   * @param {Object} options
   256   */
   257  
   258  function guardProps (options) {
   259    var props = options.props
   260    var i, val
   261    if (isArray(props)) {
   262      options.props = {}
   263      i = props.length
   264      while (i--) {
   265        val = props[i]
   266        if (typeof val === 'string') {
   267          options.props[val] = null
   268        } else if (val.name) {
   269          options.props[val.name] = val
   270        }
   271      }
   272    } else if (isPlainObject(props)) {
   273      var keys = Object.keys(props)
   274      i = keys.length
   275      while (i--) {
   276        val = props[keys[i]]
   277        if (typeof val === 'function') {
   278          props[keys[i]] = { type: val }
   279        }
   280      }
   281    }
   282  }
   283  
   284  /**
   285   * Guard an Array-format assets option and converted it
   286   * into the key-value Object format.
   287   *
   288   * @param {Object|Array} assets
   289   * @return {Object}
   290   */
   291  
   292  function guardArrayAssets (assets) {
   293    if (isArray(assets)) {
   294      var res = {}
   295      var i = assets.length
   296      var asset
   297      while (i--) {
   298        asset = assets[i]
   299        var id = typeof asset === 'function'
   300          ? ((asset.options && asset.options.name) || asset.id)
   301          : (asset.name || asset.id)
   302        if (!id) {
   303          process.env.NODE_ENV !== 'production' && warn(
   304            'Array-syntax assets must provide a "name" or "id" field.'
   305          )
   306        } else {
   307          res[id] = asset
   308        }
   309      }
   310      return res
   311    }
   312    return assets
   313  }
   314  
   315  /**
   316   * Merge two option objects into a new one.
   317   * Core utility used in both instantiation and inheritance.
   318   *
   319   * @param {Object} parent
   320   * @param {Object} child
   321   * @param {Vue} [vm] - if vm is present, indicates this is
   322   *                     an instantiation merge.
   323   */
   324  
   325  export function mergeOptions (parent, child, vm) {
   326    guardComponents(child)
   327    guardProps(child)
   328    if (process.env.NODE_ENV !== 'production') {
   329      if (child.propsData && !vm) {
   330        warn('propsData can only be used as an instantiation option.')
   331      }
   332    }
   333    var options = {}
   334    var key
   335    if (child.extends) {
   336      parent = typeof child.extends === 'function'
   337        ? mergeOptions(parent, child.extends.options, vm)
   338        : mergeOptions(parent, child.extends, vm)
   339    }
   340    if (child.mixins) {
   341      for (var i = 0, l = child.mixins.length; i < l; i++) {
   342        parent = mergeOptions(parent, child.mixins[i], vm)
   343      }
   344    }
   345    for (key in parent) {
   346      mergeField(key)
   347    }
   348    for (key in child) {
   349      if (!hasOwn(parent, key)) {
   350        mergeField(key)
   351      }
   352    }
   353    function mergeField (key) {
   354      var strat = strats[key] || defaultStrat
   355      options[key] = strat(parent[key], child[key], vm, key)
   356    }
   357    return options
   358  }
   359  
   360  /**
   361   * Resolve an asset.
   362   * This function is used because child instances need access
   363   * to assets defined in its ancestor chain.
   364   *
   365   * @param {Object} options
   366   * @param {String} type
   367   * @param {String} id
   368   * @param {Boolean} warnMissing
   369   * @return {Object|Function}
   370   */
   371  
   372  export function resolveAsset (options, type, id, warnMissing) {
   373    /* istanbul ignore if */
   374    if (typeof id !== 'string') {
   375      return
   376    }
   377    var assets = options[type]
   378    var camelizedId
   379    var res = assets[id] ||
   380      // camelCase ID
   381      assets[camelizedId = camelize(id)] ||
   382      // Pascal Case ID
   383      assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]
   384    if (process.env.NODE_ENV !== 'production' && warnMissing && !res) {
   385      warn(
   386        'Failed to resolve ' + type.slice(0, -1) + ': ' + id,
   387        options
   388      )
   389    }
   390    return res
   391  }