UNPKG

6.61 kBJavaScriptView Raw
1'use strict';
2
3var _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; };
4
5var isBigNumber = require('./bignumber/isBigNumber');
6
7/**
8 * Clone an object
9 *
10 * clone(x)
11 *
12 * Can clone any primitive type, array, and object.
13 * If x has a function clone, this function will be invoked to clone the object.
14 *
15 * @param {*} x
16 * @return {*} clone
17 */
18exports.clone = function clone(x) {
19 var type = typeof x === 'undefined' ? 'undefined' : _typeof(x);
20
21 // immutable primitive types
22 if (type === 'number' || type === 'string' || type === 'boolean' || x === null || x === undefined) {
23 return x;
24 }
25
26 // use clone function of the object when available
27 if (typeof x.clone === 'function') {
28 return x.clone();
29 }
30
31 // array
32 if (Array.isArray(x)) {
33 return x.map(function (value) {
34 return clone(value);
35 });
36 }
37
38 if (x instanceof Date) return new Date(x.valueOf());
39 if (isBigNumber(x)) return x; // bignumbers are immutable
40 if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp
41
42 // object
43 return exports.map(x, clone);
44};
45
46/**
47 * Apply map to all properties of an object
48 * @param {Object} object
49 * @param {function} callback
50 * @return {Object} Returns a copy of the object with mapped properties
51 */
52exports.map = function (object, callback) {
53 var clone = {};
54
55 for (var key in object) {
56 if (exports.hasOwnProperty(object, key)) {
57 clone[key] = callback(object[key]);
58 }
59 }
60
61 return clone;
62};
63
64/**
65 * Extend object a with the properties of object b
66 * @param {Object} a
67 * @param {Object} b
68 * @return {Object} a
69 */
70exports.extend = function (a, b) {
71 for (var prop in b) {
72 if (exports.hasOwnProperty(b, prop)) {
73 a[prop] = b[prop];
74 }
75 }
76 return a;
77};
78
79/**
80 * Deep extend an object a with the properties of object b
81 * @param {Object} a
82 * @param {Object} b
83 * @returns {Object}
84 */
85exports.deepExtend = function deepExtend(a, b) {
86 // TODO: add support for Arrays to deepExtend
87 if (Array.isArray(b)) {
88 throw new TypeError('Arrays are not supported by deepExtend');
89 }
90
91 for (var prop in b) {
92 if (exports.hasOwnProperty(b, prop)) {
93 if (b[prop] && b[prop].constructor === Object) {
94 if (a[prop] === undefined) {
95 a[prop] = {};
96 }
97 if (a[prop].constructor === Object) {
98 deepExtend(a[prop], b[prop]);
99 } else {
100 a[prop] = b[prop];
101 }
102 } else if (Array.isArray(b[prop])) {
103 throw new TypeError('Arrays are not supported by deepExtend');
104 } else {
105 a[prop] = b[prop];
106 }
107 }
108 }
109 return a;
110};
111
112/**
113 * Deep test equality of all fields in two pairs of arrays or objects.
114 * @param {Array | Object} a
115 * @param {Array | Object} b
116 * @returns {boolean}
117 */
118exports.deepEqual = function deepEqual(a, b) {
119 var prop = void 0,
120 i = void 0,
121 len = void 0;
122 if (Array.isArray(a)) {
123 if (!Array.isArray(b)) {
124 return false;
125 }
126
127 if (a.length !== b.length) {
128 return false;
129 }
130
131 for (i = 0, len = a.length; i < len; i++) {
132 if (!exports.deepEqual(a[i], b[i])) {
133 return false;
134 }
135 }
136 return true;
137 } else if (a instanceof Object) {
138 if (Array.isArray(b) || !(b instanceof Object)) {
139 return false;
140 }
141
142 for (prop in a) {
143 // noinspection JSUnfilteredForInLoop
144 if (!exports.deepEqual(a[prop], b[prop])) {
145 return false;
146 }
147 }
148 for (prop in b) {
149 // noinspection JSUnfilteredForInLoop
150 if (!exports.deepEqual(a[prop], b[prop])) {
151 return false;
152 }
153 }
154 return true;
155 } else {
156 return a === b;
157 }
158};
159
160/**
161 * Test whether the current JavaScript engine supports Object.defineProperty
162 * @returns {boolean} returns true if supported
163 */
164exports.canDefineProperty = function () {
165 // test needed for broken IE8 implementation
166 try {
167 if (Object.defineProperty) {
168 Object.defineProperty({}, 'x', { get: function get() {} });
169 return true;
170 }
171 } catch (e) {}
172
173 return false;
174};
175
176/**
177 * Attach a lazy loading property to a constant.
178 * The given function `fn` is called once when the property is first requested.
179 * On older browsers (<IE8), the function will fall back to direct evaluation
180 * of the properties value.
181 * @param {Object} object Object where to add the property
182 * @param {string} prop Property name
183 * @param {Function} fn Function returning the property value. Called
184 * without arguments.
185 */
186exports.lazy = function (object, prop, fn) {
187 if (exports.canDefineProperty()) {
188 var _uninitialized = true;
189 var _value = void 0;
190 Object.defineProperty(object, prop, {
191 get: function get() {
192 if (_uninitialized) {
193 _value = fn();
194 _uninitialized = false;
195 }
196 return _value;
197 },
198
199 set: function set(value) {
200 _value = value;
201 _uninitialized = false;
202 },
203
204 configurable: true,
205 enumerable: true
206 });
207 } else {
208 // fall back to immediate evaluation
209 object[prop] = fn();
210 }
211};
212
213/**
214 * Traverse a path into an object.
215 * When a namespace is missing, it will be created
216 * @param {Object} object
217 * @param {string} path A dot separated string like 'name.space'
218 * @return {Object} Returns the object at the end of the path
219 */
220exports.traverse = function (object, path) {
221 var obj = object;
222
223 if (path) {
224 var names = path.split('.');
225 for (var i = 0; i < names.length; i++) {
226 var name = names[i];
227 if (!(name in obj)) {
228 obj[name] = {};
229 }
230 obj = obj[name];
231 }
232 }
233
234 return obj;
235};
236
237/**
238 * A safe hasOwnProperty
239 * @param {Object} object
240 * @param {string} property
241 */
242exports.hasOwnProperty = function (object, property) {
243 return object && Object.hasOwnProperty.call(object, property);
244};
245
246/**
247 * Test whether an object is a factory. a factory has fields:
248 *
249 * - factory: function (type: Object, config: Object, load: function, typed: function [, math: Object]) (required)
250 * - name: string (optional)
251 * - path: string A dot separated path (optional)
252 * - math: boolean If true (false by default), the math namespace is passed
253 * as fifth argument of the factory function
254 *
255 * @param {*} object
256 * @returns {boolean}
257 */
258exports.isFactory = function (object) {
259 return object && typeof object.factory === 'function';
260};
\No newline at end of file