function systemExtend()

in src/core/system.js [356:440]


function systemExtend(dest={}, src={}) {

  if(!isObject(dest)) {
    return {}
  }
  if(!isObject(src)) {
    return dest
  }

  // Wrap components
  // Parses existing components in the system, and prepares them for wrapping via getComponents
  if(src.wrapComponents) {
    objMap(src.wrapComponents, (wrapperFn, key) => {
      const ori = dest.components && dest.components[key]
      if(ori && Array.isArray(ori)) {
        dest.components[key] = ori.concat([wrapperFn])
        delete src.wrapComponents[key]
      } else if(ori) {
        dest.components[key] = [ori, wrapperFn]
        delete src.wrapComponents[key]
      }
    })

    if(!Object.keys(src.wrapComponents).length) {
      // only delete wrapComponents if we've matched all of our wrappers to components
      // this handles cases where the component to wrap may be out of our scope,
      // but a higher recursive `combinePlugins` call will be able to handle it.
      delete src.wrapComponents
    }
  }


  // Account for wrapActions, make it an array and append to it
  // Modifies `src`
  // 80% of this code is just safe traversal. We need to address that ( ie: use a lib )
  const { statePlugins } = dest
  if(isObject(statePlugins)) {
    for(let namespace in statePlugins) {
      const namespaceObj = statePlugins[namespace]
      if(!isObject(namespaceObj)) {
        continue
      }

      const { wrapActions, wrapSelectors } = namespaceObj

      // process action wrapping
      if (isObject(wrapActions)) {
        for(let actionName in wrapActions) {
          let action = wrapActions[actionName]

          // This should only happen if dest is the first plugin, since invocations after that will ensure its an array
          if(!Array.isArray(action)) {
            action = [action]
            wrapActions[actionName] = action // Put the value inside an array
          }

          if(src && src.statePlugins && src.statePlugins[namespace] && src.statePlugins[namespace].wrapActions && src.statePlugins[namespace].wrapActions[actionName]) {
            src.statePlugins[namespace].wrapActions[actionName] = wrapActions[actionName].concat(src.statePlugins[namespace].wrapActions[actionName])
          }

        }
      }

      // process selector wrapping
      if (isObject(wrapSelectors)) {
        for(let selectorName in wrapSelectors) {
          let selector = wrapSelectors[selectorName]

          // This should only happen if dest is the first plugin, since invocations after that will ensure its an array
          if(!Array.isArray(selector)) {
            selector = [selector]
            wrapSelectors[selectorName] = selector // Put the value inside an array
          }

          if(src && src.statePlugins && src.statePlugins[namespace] && src.statePlugins[namespace].wrapSelectors && src.statePlugins[namespace].wrapSelectors[selectorName]) {
            src.statePlugins[namespace].wrapSelectors[selectorName] = wrapSelectors[selectorName].concat(src.statePlugins[namespace].wrapSelectors[selectorName])
          }

        }
      }
    }
  }

  return deepExtend(dest, src)
}