text: 'use strict';
  
  exports.__esModule = true;
  
  var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
  
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  
  var _reactStandIn = require('react-stand-in');
  
  var _fastLevenshtein = require('fast-levenshtein');
  
  var _fastLevenshtein2 = _interopRequireDefault(_fastLevenshtein);
  
  var _proxies = require('./proxies');
  
  var _reactUtils = require('../internal/reactUtils');
  
  var _reactHotLoader = require('../reactHotLoader');
  
  var _reactHotLoader2 = _interopRequireDefault(_reactHotLoader);
  
  var _logger = require('../logger');
  
  var _logger2 = _interopRequireDefault(_logger);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  // some `empty` names, React can autoset display name to...
  var UNDEFINED_NAMES = {
    Unknown: true,
    Component: true
  };
  
  var areNamesEqual = function areNamesEqual(a, b) {
    return a === b || UNDEFINED_NAMES[a] && UNDEFINED_NAMES[b];
  };
  var isReactClass = function isReactClass(fn) {
    return fn && !!fn.render;
  };
  var isFunctional = function isFunctional(fn) {
    return typeof fn === 'function';
  };
  var isArray = function isArray(fn) {
    return Array.isArray(fn);
  };
  var asArray = function asArray(a) {
    return isArray(a) ? a : [a];
  };
  var getTypeOf = function getTypeOf(type) {
    if (isReactClass(type)) return 'ReactComponent';
    if (isFunctional(type)) return 'StatelessFunctional';
    return 'Fragment'; // ?
  };
  
  var filterNullArray = function filterNullArray(a) {
    if (!a) return [];
    return a.filter(function (x) {
      return !!x;
    });
  };
  
  var unflatten = function unflatten(a) {
    return a.reduce(function (acc, a) {
      if (Array.isArray(a)) {
        acc.push.apply(acc, unflatten(a));
      } else {
        acc.push(a);
      }
      return acc;
    }, []);
  };
  
  var getElementType = function getElementType(child) {
    return child.type[_reactStandIn.UNWRAP_PROXY] ? child.type[_reactStandIn.UNWRAP_PROXY]() : child.type;
  };
  
  var haveTextSimilarity = function haveTextSimilarity(a, b) {
    return (
      // equal or slight changed
      a === b || _fastLevenshtein2.default.get(a, b) < a.length * 0.2
    );
  };
  
  var equalClasses = function equalClasses(a, b) {
    var prototypeA = a.prototype;
    var prototypeB = Object.getPrototypeOf(b.prototype);
  
    var hits = 0;
    var misses = 0;
    Object.getOwnPropertyNames(prototypeA).forEach(function (key) {
      if (typeof prototypeA[key] === 'function') {
        if (haveTextSimilarity(String(prototypeA[key]), String(prototypeB[key]))) {
          hits++;
        } else {
          misses++;
          if (key === 'render') {
            misses++;
          }
        }
      }
    });
    // allow to add or remove one function
    return hits > 0 && misses <= 1;
  };
  
  var isSwappable = function isSwappable(a, b) {
    // both are registered components
    if ((0, _proxies.getIdByType)(b) && (0, _proxies.getIdByType)(a) === (0, _proxies.getIdByType)(b)) {
      return true;
    }
    if (getTypeOf(a) !== getTypeOf(b)) {
      return false;
    }
    if (isReactClass(a.prototype)) {
      return areNamesEqual((0, _reactUtils.getComponentDisplayName)(a), (0, _reactUtils.getComponentDisplayName)(b)) && equalClasses(a, b);
    }
    if (isFunctional(a)) {
      return areNamesEqual((0, _reactUtils.getComponentDisplayName)(a), (0, _reactUtils.getComponentDisplayName)(b)) && haveTextSimilarity(String(a), String(b));
    }
    return false;
  };
  
  var render = function render(component) {
    if (!component) {
      return [];
    }
    if (isReactClass(component)) {
      return component.render();
    }
    if (isArray(component)) {
      return component.map(render);
    }
    if (component.children) {
      return component.children;
    }
  
    return [];
  };
  
  var NO_CHILDREN = { children: [] };
  var mapChildren = function mapChildren(children, instances) {
    return {
      children: children.filter(function (c) {
        return c;
      }).map(function (child, index) {
        if ((typeof child === 'undefined' ? 'undefined' : _typeof(child)) !== 'object') {
          return child;
        }
        if (Array.isArray(child)) {
          return _extends({
            type: null
          }, mapChildren(child, instances[index].children));
        }
        return _extends({}, instances[index], {
          type: child.type
        });
      })
    };
  };
  
  var mergeInject = function mergeInject(a, b, instance) {
    if (a && !Array.isArray(a)) {
      return mergeInject([a], b);
    }
    if (b && !Array.isArray(b)) {
      return mergeInject(a, [b]);
    }
  
    if (!a || !b) {
      return NO_CHILDREN;
    }
    if (a.length === b.length) {
      return mapChildren(a, b);
    }
    var flatA = unflatten(a);
    var flatB = unflatten(b);
    if (flatA.length === flatB.length) {
      return mapChildren(flatA, flatB);
    }
    if (flatB.length === 0 && flatA.length === 1 && _typeof(flatA[0]) !== 'object') {
      // terminal node
    } else {
      _logger2.default.warn('React-hot-loader: unable to merge ', a, 'and children of ', instance);
    }
    return NO_CHILDREN;
  };
  
  var transformFlowNode = function transformFlowNode(flow) {
    return flow.reduce(function (acc, node) {
      if ((0, _reactUtils.isFragmentNode)(node) && node.props && node.props.children) {
        return [].concat(acc, node.props.children);
      }
      return [].concat(acc, [node]);
    }, []);
  };
  
  var hotReplacementRender = function hotReplacementRender(instance, stack) {
    var flow = transformFlowNode(filterNullArray(asArray(render(instance))));
  
    var children = stack.children;
  
  
    flow.forEach(function (child, index) {
      var stackChild = children[index];
      var next = function next(instance) {
        // copy over props as long new component may be hidden inside them
        // child does not have all props, as long some of them can be calculated on componentMount.
        var nextProps = _extends({}, instance.props);
        for (var key in child.props) {
          if (child.props[key]) {
            nextProps[key] = child.props[key];
          }
        }
        if (isReactClass(instance) && instance.componentWillUpdate) {
          // Force-refresh component (bypass redux renderedComponent)
          instance.componentWillUpdate(nextProps, instance.state);
        }
        instance.props = nextProps;
        hotReplacementRender(instance, stackChild);
      };
  
      // text node
      if ((typeof child === 'undefined' ? 'undefined' : _typeof(child)) !== 'object' || !stackChild || !stackChild.instance) {
        return;
      }
  
      if (typeof child.type !== 'function') {
        next(
        // move types from render to the instances of hydrated tree
        mergeInject(filterNullArray(asArray(child.props ? child.props.children : child.children)), stackChild.instance.children, stackChild.instance));
      } else {
        // unwrap proxy
        var childType = getElementType(child);
        if (!stackChild.type[_reactStandIn.PROXY_KEY]) {
          /* eslint-disable no-console */
          _logger2.default.error('React-hot-loader: fatal error caused by ', stackChild.type, ' - no instrumentation found. ', 'Please require react-hot-loader before React. More in troubleshooting.');
          throw new Error('React-hot-loader: wrong configuration');
        }
  
        if (child.type === stackChild.type) {
          next(stackChild.instance);
        } else if (isSwappable(childType, stackChild.type)) {
          // they are both registered, or have equal code/displayname/signature
  
          // update proxy using internal PROXY_KEY
          (0, _proxies.updateProxyById)(stackChild.type[_reactStandIn.PROXY_KEY], childType);
  
          next(stackChild.instance);
        } else {
          _logger2.default.warn('React-hot-loader: a ' + (0, _reactUtils.getComponentDisplayName)(childType) + ' was found where a ' + (0, _reactUtils.getComponentDisplayName)(stackChild) + ' was expected.\n          ' + childType);
        }
  
        (0, _reactUtils.updateInstance)(stackChild.instance);
      }
    });
  };
  
  exports.default = function (instance, stack) {
    try {
      // disable reconciler to prevent upcoming components from proxying.
      _reactHotLoader2.default.disableProxyCreation = true;
      hotReplacementRender(instance, stack);
    } catch (e) {
      _logger2.default.warn('React-hot-loader: reconcilation failed due to error', e);
    } finally {
      _reactHotLoader2.default.disableProxyCreation = false;
    }
  };