"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.typeOf = typeOf;
exports.isArrayLike = isArrayLike;
exports.isPromise = isPromise;
exports.isPlainObject = isPlainObject;
exports.shallowEqual = shallowEqual;
exports.each = each;
exports.pickOthers = pickOthers;
exports.pickAttrsWith = pickAttrsWith;
exports.isNil = isNil;
exports.deepMerge = deepMerge;
exports.pickAttrs = pickAttrs;

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _extends() { _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; }; return _extends.apply(this, arguments); }

function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

/**
 * 获取对象的类型
 * @param  {*} obj
 * @return {String}
 *
 * @example
 * typeOf([]) === 'Array'
 * typeOf() === 'Undefined'
 * typeOf(1) === 'Number'
 */
function typeOf(obj) {
  return Object.prototype.toString.call(obj).replace(/\[object\s|]/g, '');
}
/**
 * 判断是否是数组或类数组对象
 * @param  {*}  obj
 * @return {Boolean}
 *
 * @example
 * isArrayLike([]) === true
 * isArrayLike(arguments) === true
 * isArrayLike(this.props.children) === true
 */


function isArrayLike(obj) {
  var length = !!obj && 'length' in obj && obj.length;
  var type = typeOf(obj);
  return type === 'Array' || length === 0 || typeof length === 'number' && length > 0 && length - 1 in obj;
}
/**
 * 判断对象是否是一个promise，即是否可以用.then
 * @param  {*}  obj
 * @return {Boolean}
 */


function isPromise(obj) {
  return !!obj && (_typeof(obj) === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
}
/**
 * 是否是一个纯净的对象
 * @param  {*}  obj
 * @return {Boolean}
 * @reference https://github.com/jonschlinkert/is-plain-object
 */


function isPlainObject(obj) {
  if (typeOf(obj) !== 'Object') {
    return false;
  }

  var ctor = obj.constructor;

  if (typeof ctor !== 'function') {
    return false;
  }

  var prot = ctor.prototype;

  if (typeOf(prot) !== 'Object') {
    return false;
  }

  if (!prot.hasOwnProperty('isPrototypeOf')) {
    return false;
  }

  return true;
}
/**
 * 对象浅比较
 * @param  {Object} objA
 * @param  {Object} objB
 * @param  {Function}  [compare] 手动调用方法比较
 * @return {Boolean}      对象浅比较是否相等
 *
 * @example
 * object.shallowEqual({a: 100}, {a: 100}); // true
 */


function shallowEqual(objA, objB, compare) {
  if (objA === objB) {
    return true;
  } // 其中一个不是object，则不相等


  if (!objA || !objB || _typeof(objA) + _typeof(objB) !== 'objectobject') {
    return false;
  }

  var keyA = Object.keys(objA);
  var keyB = Object.keys(objB);
  var len = keyA.length; // key 数量不一致则不相等

  if (len !== keyB.length) {
    return false;
  }

  var hasCallback = typeof compare === 'function';

  for (var i = 0; i < len; i++) {
    var key = keyA[i];

    if (!Object.prototype.hasOwnProperty.call(objB, key)) {
      return false;
    }

    var valA = objA[key];
    var valB = objB[key];
    var ret = hasCallback ? compare(valA, valB, key) : void 0;

    if (ret === false || ret === void 0 && valA !== valB) {
      return false;
    }
  }

  return true;
}
/**
 * 遍历对象或数组，或者类数组，例如React中的children对象、arguments等
 * @param  {Object|Array}   obj
 * @param  {Function} callback fn(n, i) or fn(val, key)
 * @param  {Number}   [direction = 1] 是否倒序遍历，只对数组有效
 * @return {Object|Array}
 *
 * @example
 * // 遍历数组
 * object.each([100, 200, 300], (n, i) => console.log(n, i));
 * // 遍历json对象
 * object.each({a: 100, b: 200}, (value, key) => console.log(key, value));
 * // 遍历React子节点
 * object.each(this.props.children, (child, index) => console.log(child));
 * // 遍历arguments
 * object.each(arguments, (arg, i) => console.log(arg));
 */


function each(obj, callback, direction) {
  var reversed = direction === -1;
  var length = obj.length;
  var value,
      i = reversed ? length - 1 : 0;

  if (isArrayLike(obj)) {
    for (; i < length && i >= 0; reversed ? i-- : i++) {
      value = callback.call(obj[i], obj[i], i);

      if (value === false) {
        break;
      }
    }
  } else {
    for (i in obj) {
      /* istanbul ignore else */
      if (obj.hasOwnProperty(i)) {
        value = callback.call(obj[i], obj[i], i);

        if (value === false) {
          break;
        }
      }
    }
  }

  return obj;
} // @private 判断key是否在数组或对象中


var _isInObj = function _isInObj(key, obj, isArray) {
  return isArray ? obj.indexOf(key) > -1 : key in obj;
};
/**
 * 过滤出其它属性
 * @param  {Object|Array} holdProps 过滤的参照对象，最终的结果只保留不在参照对象中的key
 * @param  {Object} props     被过滤的对象
 * @return {Object}           others
 *
 * @example
 * object.pickOthers(FooComponent.propTypes, this.props);
 * object.pickOthers(['className', 'onChange'], this.props);
 */


function pickOthers(holdProps, props) {
  var others = {};
  var isArray = typeOf(holdProps) === 'Array';

  for (var key in props) {
    if (!_isInObj(key, holdProps, isArray)) {
      others[key] = props[key];
    }
  }

  return others;
}
/**
 * 过滤出带prefix的属性
 * @param  {Object} holdProps 过滤的参照对象，最终的结果只保留不在参照对象中的key
 * @param  {string} prefix    包含的字符串
 * @return {Object}           others
 *
 * @example
 * object.pickAttrsWith(FooComponent.propTypes, 'data-');
 */


function pickAttrsWith(holdProps, prefix) {
  var others = {};

  for (var key in holdProps) {
    if (key.match(prefix)) {
      others[key] = holdProps[key];
    }
  }

  return others;
}
/**
 * Checks if value is `null` or `undefined`.
 * @param {*} value
 * @return {Boolean}
 */


function isNil(value) {
  // It will returns `true` only if `null` or `undefined` compare with `null`
  // with loose equaliy
  return value == null; // eslint-disable-line eqeqeq
}
/**
 * Deep merge two objects.
 * @param target
 * @param ...sources
 * @reference https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge?page=1&tab=votes#tab-top
 */


function deepMerge(target) {
  for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    sources[_key - 1] = arguments[_key];
  }

  if (!sources.length) return target;
  var source = sources.shift();

  if (!isPlainObject(target)) {
    target = {};
  }

  if (isPlainObject(target) && isPlainObject(source)) {
    for (var key in source) {
      if (isPlainObject(source[key])) {
        if (!target[key]) _extends(target, _defineProperty({}, key, {})); // fix {a: 'te'}, {a:{b:3}}

        if (!isPlainObject(target[key])) {
          target[key] = source[key];
        }

        deepMerge(target[key], source[key]);
      } else {
        _extends(target, _defineProperty({}, key, source[key]));
      }
    }
  }

  return deepMerge.apply(void 0, [target].concat(sources));
}

var attributes = "accept acceptCharset accessKey action allowFullScreen allowTransparency\nalt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge\ncharSet checked classID className colSpan cols content contentEditable contextMenu\ncontrols coords crossOrigin data dateTime default defer dir disabled download draggable\nencType form formAction formEncType formMethod formNoValidate formTarget frameBorder\nheaders height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity\nis keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media\nmediaGroup method min minLength multiple muted name noValidate nonce open\noptimum pattern placeholder poster preload radioGroup readOnly rel required\nreversed role rowSpan rows sandbox scope scoped scrolling seamless selected\nshape size sizes span spellCheck src srcDoc srcLang srcSet start step style\nsummary tabIndex target title type useMap value width wmode wrap".replace(/\s+/g, ' ').replace(/\t|\n|\r/g, '').split(' ');
var eventsName = "onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown\n    onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick\n    onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown\n    onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel\n    onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough\n    onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata\n    onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError".replace(/\s+/g, ' ').replace(/\t|\n|\r/g, '').split(' ');
var attrsPrefix = ['data-', 'aria-'];

function pickAttrs(props) {
  var attrs = {};

  var _loop = function _loop(key) {
    if (attributes.indexOf(key) > -1 || eventsName.indexOf(key) > -1) {
      attrs[key] = props[key];
    } else if (attrsPrefix.map(function (prefix) {
      return new RegExp("^".concat(prefix));
    }).some(function (reg) {
      return key.replace(reg, '') != key;
    })) {
      attrs[key] = props[key];
    }
  };

  for (var key in props) {
    _loop(key);
  }

  return attrs;
}