[6a3a178] | 1 | 'use strict';
|
---|
| 2 |
|
---|
| 3 | var typeOf = require('kind-of');
|
---|
| 4 | var copyDescriptor = require('copy-descriptor');
|
---|
| 5 | var define = require('define-property');
|
---|
| 6 |
|
---|
| 7 | /**
|
---|
| 8 | * Copy static properties, prototype properties, and descriptors from one object to another.
|
---|
| 9 | *
|
---|
| 10 | * ```js
|
---|
| 11 | * function App() {}
|
---|
| 12 | * var proto = App.prototype;
|
---|
| 13 | * App.prototype.set = function() {};
|
---|
| 14 | * App.prototype.get = function() {};
|
---|
| 15 | *
|
---|
| 16 | * var obj = {};
|
---|
| 17 | * copy(obj, proto);
|
---|
| 18 | * ```
|
---|
| 19 | * @param {Object} `receiver`
|
---|
| 20 | * @param {Object} `provider`
|
---|
| 21 | * @param {String|Array} `omit` One or more properties to omit
|
---|
| 22 | * @return {Object}
|
---|
| 23 | * @api public
|
---|
| 24 | */
|
---|
| 25 |
|
---|
| 26 | function copy(receiver, provider, omit) {
|
---|
| 27 | if (!isObject(receiver)) {
|
---|
| 28 | throw new TypeError('expected receiving object to be an object.');
|
---|
| 29 | }
|
---|
| 30 | if (!isObject(provider)) {
|
---|
| 31 | throw new TypeError('expected providing object to be an object.');
|
---|
| 32 | }
|
---|
| 33 |
|
---|
| 34 | var props = nativeKeys(provider);
|
---|
| 35 | var keys = Object.keys(provider);
|
---|
| 36 | var len = props.length;
|
---|
| 37 | omit = arrayify(omit);
|
---|
| 38 |
|
---|
| 39 | while (len--) {
|
---|
| 40 | var key = props[len];
|
---|
| 41 |
|
---|
| 42 | if (has(keys, key)) {
|
---|
| 43 | define(receiver, key, provider[key]);
|
---|
| 44 | } else if (!(key in receiver) && !has(omit, key)) {
|
---|
| 45 | copyDescriptor(receiver, provider, key);
|
---|
| 46 | }
|
---|
| 47 | }
|
---|
| 48 | };
|
---|
| 49 |
|
---|
| 50 | /**
|
---|
| 51 | * Return true if the given value is an object or function
|
---|
| 52 | */
|
---|
| 53 |
|
---|
| 54 | function isObject(val) {
|
---|
| 55 | return typeOf(val) === 'object' || typeof val === 'function';
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | /**
|
---|
| 59 | * Returns true if an array has any of the given elements, or an
|
---|
| 60 | * object has any of the give keys.
|
---|
| 61 | *
|
---|
| 62 | * ```js
|
---|
| 63 | * has(['a', 'b', 'c'], 'c');
|
---|
| 64 | * //=> true
|
---|
| 65 | *
|
---|
| 66 | * has(['a', 'b', 'c'], ['c', 'z']);
|
---|
| 67 | * //=> true
|
---|
| 68 | *
|
---|
| 69 | * has({a: 'b', c: 'd'}, ['c', 'z']);
|
---|
| 70 | * //=> true
|
---|
| 71 | * ```
|
---|
| 72 | * @param {Object} `obj`
|
---|
| 73 | * @param {String|Array} `val`
|
---|
| 74 | * @return {Boolean}
|
---|
| 75 | */
|
---|
| 76 |
|
---|
| 77 | function has(obj, val) {
|
---|
| 78 | val = arrayify(val);
|
---|
| 79 | var len = val.length;
|
---|
| 80 |
|
---|
| 81 | if (isObject(obj)) {
|
---|
| 82 | for (var key in obj) {
|
---|
| 83 | if (val.indexOf(key) > -1) {
|
---|
| 84 | return true;
|
---|
| 85 | }
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | var keys = nativeKeys(obj);
|
---|
| 89 | return has(keys, val);
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | if (Array.isArray(obj)) {
|
---|
| 93 | var arr = obj;
|
---|
| 94 | while (len--) {
|
---|
| 95 | if (arr.indexOf(val[len]) > -1) {
|
---|
| 96 | return true;
|
---|
| 97 | }
|
---|
| 98 | }
|
---|
| 99 | return false;
|
---|
| 100 | }
|
---|
| 101 |
|
---|
| 102 | throw new TypeError('expected an array or object.');
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | /**
|
---|
| 106 | * Cast the given value to an array.
|
---|
| 107 | *
|
---|
| 108 | * ```js
|
---|
| 109 | * arrayify('foo');
|
---|
| 110 | * //=> ['foo']
|
---|
| 111 | *
|
---|
| 112 | * arrayify(['foo']);
|
---|
| 113 | * //=> ['foo']
|
---|
| 114 | * ```
|
---|
| 115 | *
|
---|
| 116 | * @param {String|Array} `val`
|
---|
| 117 | * @return {Array}
|
---|
| 118 | */
|
---|
| 119 |
|
---|
| 120 | function arrayify(val) {
|
---|
| 121 | return val ? (Array.isArray(val) ? val : [val]) : [];
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 | /**
|
---|
| 125 | * Returns true if a value has a `contructor`
|
---|
| 126 | *
|
---|
| 127 | * ```js
|
---|
| 128 | * hasConstructor({});
|
---|
| 129 | * //=> true
|
---|
| 130 | *
|
---|
| 131 | * hasConstructor(Object.create(null));
|
---|
| 132 | * //=> false
|
---|
| 133 | * ```
|
---|
| 134 | * @param {Object} `value`
|
---|
| 135 | * @return {Boolean}
|
---|
| 136 | */
|
---|
| 137 |
|
---|
| 138 | function hasConstructor(val) {
|
---|
| 139 | return isObject(val) && typeof val.constructor !== 'undefined';
|
---|
| 140 | }
|
---|
| 141 |
|
---|
| 142 | /**
|
---|
| 143 | * Get the native `ownPropertyNames` from the constructor of the
|
---|
| 144 | * given `object`. An empty array is returned if the object does
|
---|
| 145 | * not have a constructor.
|
---|
| 146 | *
|
---|
| 147 | * ```js
|
---|
| 148 | * nativeKeys({a: 'b', b: 'c', c: 'd'})
|
---|
| 149 | * //=> ['a', 'b', 'c']
|
---|
| 150 | *
|
---|
| 151 | * nativeKeys(function(){})
|
---|
| 152 | * //=> ['length', 'caller']
|
---|
| 153 | * ```
|
---|
| 154 | *
|
---|
| 155 | * @param {Object} `obj` Object that has a `constructor`.
|
---|
| 156 | * @return {Array} Array of keys.
|
---|
| 157 | */
|
---|
| 158 |
|
---|
| 159 | function nativeKeys(val) {
|
---|
| 160 | if (!hasConstructor(val)) return [];
|
---|
| 161 | return Object.getOwnPropertyNames(val);
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 | /**
|
---|
| 165 | * Expose `copy`
|
---|
| 166 | */
|
---|
| 167 |
|
---|
| 168 | module.exports = copy;
|
---|
| 169 |
|
---|
| 170 | /**
|
---|
| 171 | * Expose `copy.has` for tests
|
---|
| 172 | */
|
---|
| 173 |
|
---|
| 174 | module.exports.has = has;
|
---|