UNPKG

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