UNPKG

9.73 kBJavaScriptView Raw
1function _typeof(obj) { "@babel/helpers - typeof"; 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); }
2
3import { isBigNumber } from './is';
4/**
5 * Clone an object
6 *
7 * clone(x)
8 *
9 * Can clone any primitive type, array, and object.
10 * If x has a function clone, this function will be invoked to clone the object.
11 *
12 * @param {*} x
13 * @return {*} clone
14 */
15
16export function clone(x) {
17 var type = _typeof(x); // immutable primitive types
18
19
20 if (type === 'number' || type === 'string' || type === 'boolean' || x === null || x === undefined) {
21 return x;
22 } // use clone function of the object when available
23
24
25 if (typeof x.clone === 'function') {
26 return x.clone();
27 } // array
28
29
30 if (Array.isArray(x)) {
31 return x.map(function (value) {
32 return clone(value);
33 });
34 }
35
36 if (x instanceof Date) return new Date(x.valueOf());
37 if (isBigNumber(x)) return x; // bignumbers are immutable
38
39 if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp
40 // object
41
42 return mapObject(x, clone);
43}
44/**
45 * Apply map to all properties of an object
46 * @param {Object} object
47 * @param {function} callback
48 * @return {Object} Returns a copy of the object with mapped properties
49 */
50
51export function mapObject(object, callback) {
52 var clone = {};
53
54 for (var key in object) {
55 if (hasOwnProperty(object, key)) {
56 clone[key] = callback(object[key]);
57 }
58 }
59
60 return clone;
61}
62/**
63 * Extend object a with the properties of object b
64 * @param {Object} a
65 * @param {Object} b
66 * @return {Object} a
67 */
68
69export function extend(a, b) {
70 for (var prop in b) {
71 if (hasOwnProperty(b, prop)) {
72 a[prop] = b[prop];
73 }
74 }
75
76 return a;
77}
78/**
79 * Deep extend an object a with the properties of object b
80 * @param {Object} a
81 * @param {Object} b
82 * @returns {Object}
83 */
84
85export 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 (hasOwnProperty(b, prop)) {
93 if (b[prop] && b[prop].constructor === Object) {
94 if (a[prop] === undefined) {
95 a[prop] = {};
96 }
97
98 if (a[prop] && a[prop].constructor === Object) {
99 deepExtend(a[prop], b[prop]);
100 } else {
101 a[prop] = b[prop];
102 }
103 } else if (Array.isArray(b[prop])) {
104 throw new TypeError('Arrays are not supported by deepExtend');
105 } else {
106 a[prop] = b[prop];
107 }
108 }
109 }
110
111 return a;
112}
113/**
114 * Deep test equality of all fields in two pairs of arrays or objects.
115 * Compares values and functions strictly (ie. 2 is not the same as '2').
116 * @param {Array | Object} a
117 * @param {Array | Object} b
118 * @returns {boolean}
119 */
120
121export function deepStrictEqual(a, b) {
122 var prop, i, len;
123
124 if (Array.isArray(a)) {
125 if (!Array.isArray(b)) {
126 return false;
127 }
128
129 if (a.length !== b.length) {
130 return false;
131 }
132
133 for (i = 0, len = a.length; i < len; i++) {
134 if (!deepStrictEqual(a[i], b[i])) {
135 return false;
136 }
137 }
138
139 return true;
140 } else if (typeof a === 'function') {
141 return a === b;
142 } else if (a instanceof Object) {
143 if (Array.isArray(b) || !(b instanceof Object)) {
144 return false;
145 }
146
147 for (prop in a) {
148 // noinspection JSUnfilteredForInLoop
149 if (!(prop in b) || !deepStrictEqual(a[prop], b[prop])) {
150 return false;
151 }
152 }
153
154 for (prop in b) {
155 // noinspection JSUnfilteredForInLoop
156 if (!(prop in a) || !deepStrictEqual(a[prop], b[prop])) {
157 return false;
158 }
159 }
160
161 return true;
162 } else {
163 return a === b;
164 }
165}
166/**
167 * Recursively flatten a nested object.
168 * @param {Object} nestedObject
169 * @return {Object} Returns the flattened object
170 */
171
172export function deepFlatten(nestedObject) {
173 var flattenedObject = {};
174
175 _deepFlatten(nestedObject, flattenedObject);
176
177 return flattenedObject;
178} // helper function used by deepFlatten
179
180function _deepFlatten(nestedObject, flattenedObject) {
181 for (var prop in nestedObject) {
182 if (hasOwnProperty(nestedObject, prop)) {
183 var value = nestedObject[prop];
184
185 if (_typeof(value) === 'object' && value !== null) {
186 _deepFlatten(value, flattenedObject);
187 } else {
188 flattenedObject[prop] = value;
189 }
190 }
191 }
192}
193/**
194 * Test whether the current JavaScript engine supports Object.defineProperty
195 * @returns {boolean} returns true if supported
196 */
197
198
199export function canDefineProperty() {
200 // test needed for broken IE8 implementation
201 try {
202 if (Object.defineProperty) {
203 Object.defineProperty({}, 'x', {
204 get: function get() {}
205 });
206 return true;
207 }
208 } catch (e) {}
209
210 return false;
211}
212/**
213 * Attach a lazy loading property to a constant.
214 * The given function `fn` is called once when the property is first requested.
215 *
216 * @param {Object} object Object where to add the property
217 * @param {string} prop Property name
218 * @param {Function} valueResolver Function returning the property value. Called
219 * without arguments.
220 */
221
222export function lazy(object, prop, valueResolver) {
223 var _uninitialized = true;
224
225 var _value;
226
227 Object.defineProperty(object, prop, {
228 get: function get() {
229 if (_uninitialized) {
230 _value = valueResolver();
231 _uninitialized = false;
232 }
233
234 return _value;
235 },
236 set: function set(value) {
237 _value = value;
238 _uninitialized = false;
239 },
240 configurable: true,
241 enumerable: true
242 });
243}
244/**
245 * Traverse a path into an object.
246 * When a namespace is missing, it will be created
247 * @param {Object} object
248 * @param {string | string[]} path A dot separated string like 'name.space'
249 * @return {Object} Returns the object at the end of the path
250 */
251
252export function traverse(object, path) {
253 if (path && typeof path === 'string') {
254 return traverse(object, path.split('.'));
255 }
256
257 var obj = object;
258
259 if (path) {
260 for (var i = 0; i < path.length; i++) {
261 var key = path[i];
262
263 if (!(key in obj)) {
264 obj[key] = {};
265 }
266
267 obj = obj[key];
268 }
269 }
270
271 return obj;
272}
273/**
274 * A safe hasOwnProperty
275 * @param {Object} object
276 * @param {string} property
277 */
278
279export function hasOwnProperty(object, property) {
280 return object && Object.hasOwnProperty.call(object, property);
281}
282/**
283 * Test whether an object is a factory. a factory has fields:
284 *
285 * - factory: function (type: Object, config: Object, load: function, typed: function [, math: Object]) (required)
286 * - name: string (optional)
287 * - path: string A dot separated path (optional)
288 * - math: boolean If true (false by default), the math namespace is passed
289 * as fifth argument of the factory function
290 *
291 * @param {*} object
292 * @returns {boolean}
293 */
294
295export function isLegacyFactory(object) {
296 return object && typeof object.factory === 'function';
297}
298/**
299 * Get a nested property from an object
300 * @param {Object} object
301 * @param {string | string[]} path
302 * @returns {Object}
303 */
304
305export function get(object, path) {
306 if (typeof path === 'string') {
307 if (isPath(path)) {
308 return get(object, path.split('.'));
309 } else {
310 return object[path];
311 }
312 }
313
314 var child = object;
315
316 for (var i = 0; i < path.length; i++) {
317 var key = path[i];
318 child = child ? child[key] : undefined;
319 }
320
321 return child;
322}
323/**
324 * Set a nested property in an object
325 * Mutates the object itself
326 * If the path doesn't exist, it will be created
327 * @param {Object} object
328 * @param {string | string[]} path
329 * @param {*} value
330 * @returns {Object}
331 */
332
333export function set(object, path, value) {
334 if (typeof path === 'string') {
335 if (isPath(path)) {
336 return set(object, path.split('.'), value);
337 } else {
338 object[path] = value;
339 return object;
340 }
341 }
342
343 var child = object;
344
345 for (var i = 0; i < path.length - 1; i++) {
346 var key = path[i];
347
348 if (child[key] === undefined) {
349 child[key] = {};
350 }
351
352 child = child[key];
353 }
354
355 if (path.length > 0) {
356 var lastKey = path[path.length - 1];
357 child[lastKey] = value;
358 }
359
360 return object;
361}
362/**
363 * Create an object composed of the picked object properties
364 * @param {Object} object
365 * @param {string[]} properties
366 * @param {function} [transform] Optional value to transform a value when picking it
367 * @return {Object}
368 */
369
370export function pick(object, properties, transform) {
371 var copy = {};
372
373 for (var i = 0; i < properties.length; i++) {
374 var key = properties[i];
375 var value = get(object, key);
376
377 if (value !== undefined) {
378 set(copy, key, transform ? transform(value, key) : value);
379 }
380 }
381
382 return copy;
383}
384/**
385 * Shallow version of pick, creating an object composed of the picked object properties
386 * but not for nested properties
387 * @param {Object} object
388 * @param {string[]} properties
389 * @return {Object}
390 */
391
392export function pickShallow(object, properties) {
393 var copy = {};
394
395 for (var i = 0; i < properties.length; i++) {
396 var key = properties[i];
397 var value = object[key];
398
399 if (value !== undefined) {
400 copy[key] = value;
401 }
402 }
403
404 return copy;
405}
406export function values(object) {
407 return Object.keys(object).map(function (key) {
408 return object[key];
409 });
410} // helper function to test whether a string contains a path like 'user.name'
411
412function isPath(str) {
413 return str.indexOf('.') !== -1;
414}
\No newline at end of file