https://www.springerpub.com/static/version1789146322/base/Magento/base/default/mage/utils/objects.js
1/** 2 * Copyright © Magento, Inc. All rights reserved. 3 * See COPYING.txt for license details. 4 */ 5define([ 6 'ko', 7 'jquery', 8 'underscore', 9 'mage/utils/strings' 10], function (ko, $, _, stringUtils) { 11 'use strict'; 12 13 var primitives = [ 14 'undefined', 15 'boolean', 16 'number', 17 'string' 18 ]; 19 20 /** 21 * Sets nested property of a specified object. 22 * @private 23 * 24 * @param {Object} parent - Object to look inside for the properties. 25 * @param {Array} path - Splitted path the property. 26 * @param {*} value - Value of the last property in 'path' array. 27 * returns {*} New value for the property. 28 */ 29 function setNested(parent, path, value) { 30 var last = path.pop(), 31 len = path.length, 32 pi = 0, 33 part = path[pi]; 34 35 for (; pi < len; part = path[++pi]) { 36 if (!_.isObject(parent[part])) { 37 parent[part] = {}; 38 } 39 40 parent = parent[part]; 41 } 42 43 if (typeof parent[last] === 'function') { 44 parent[last](value); 45 } else { 46 parent[last] = value; 47 } 48 49 return value; 50 } 51 52 /** 53 * Retrieves value of a nested property. 54 * @private 55 * 56 * @param {Object} parent - Object to look inside for the properties. 57 * @param {Array} path - Splitted path the property. 58 * @returns {*} Value of the property. 59 */ 60 function getNested(parent, path) { 61 var exists = true, 62 len = path.length, 63 pi = 0; 64 65 for (; pi < len && exists; pi++) { 66 parent = parent[path[pi]]; 67 68 if (typeof parent === 'undefined') { 69 exists = false; 70 } 71 } 72 73 if (exists) { 74 if (ko.isObservable(parent)) { 75 parent = parent(); 76 } 77 78 return parent; 79 } 80 } 81 82 /** 83 * Removes property from a specified object. 84 * @private 85 * 86 * @param {Object} parent - Object from which to remove property. 87 * @param {Array} path - Splitted path to the property. 88 */ 89 function removeNested(parent, path) { 90 var field = path.pop(); 91 92 parent = getNested(parent, path); 93 94 if (_.isObject(parent)) { 95 delete parent[field]; 96 } 97 } 98 99 return { 100 101 /** 102 * Retrieves or defines objects' property by a composite path. 103 * 104 * @param {Object} data - Container for the properties specified in path. 105 * @param {String} path - Objects' properties divided by dots. 106 * @param {*} [value] - New value for the last property. 107 * @returns {*} Returns value of the last property in chain. 108 * 109 * @example 110 * utils.nested({}, 'one.two', 3); 111 * => { one: {two: 3} } 112 */ 113 nested: function (data, path, value) { 114 var action = arguments.length > 2 ? setNested : getNested; 115 116 path = path ? path.split('.') : []; 117 118 return action(data, path, value); 119 }, 120 121 /** 122 * Removes nested property from an object. 123 * 124 * @param {Object} data - Data source. 125 * @param {String} path - Path to the property e.g. 'one.two.three' 126 */ 127 nestedRemove: function (data, path) { 128 path = path.split('.'); 129 130 removeNested(data, path); 131 }, 132 133 /** 134 * Flattens objects' nested properties. 135 * 136 * @param {Object} data - Object to flatten. 137 * @param {String} [separator='.'] - Objects' keys separator. 138 * @returns {Object} Flattened object. 139 * 140 * @example Example with a default separator. 141 * utils.flatten({one: { two: { three: 'value'} }}); 142 * => { 'one.two.three': 'value' }; 143 * 144 * @example Example with a custom separator. 145 * utils.flatten({one: { two: { three: 'value'} }}, '=>'); 146 * => {'one=>two=>three': 'value'}; 147 */ 148 flatten: function (data, separator, parent, result) { 149 separator = separator || '.'; 150 result = result || {}; 151 152 if (!data) { 153 return result; 154 } 155 156 // UnderscoreJS each breaks when an object has a length property so we use Object.keys 157 _.each(Object.keys(data), function (name) { 158 var node = data[name]; 159 160 if ({}.toString.call(node) === '[object Function]') { 161 return; 162 } 163 164 if (parent) { 165 name = parent + separator + name; 166 } 167 168 typeof node === 'object' ? 169 this.flatten(node, separator, name, result) : 170 result[name] = node; 171 172 }, this); 173 174 return result; 175 }, 176 177 /** 178 * Opposite operation of the 'flatten' method. 179 * 180 * @param {Object} data - Previously flattened object. 181 * @param {String} [separator='.'] - Keys separator. 182 * @returns {Object} Object with nested properties. 183 * 184 * @example Example using custom separator. 185 * utils.unflatten({'one=>two': 'value'}, '=>'); 186 * => { 187 * one: { two: 'value' } 188 * }; 189 */ 190 unflatten: function (data, separator) { 191 var result = {}; 192 193 separator = separator || '.'; 194 195 _.each(data, function (value, nodes) { 196 nodes = nodes.split(separator); 197 198 setNested(result, nodes, value); 199 }); 200 201 return result; 202 }, 203 204 /** 205 * Same operation as 'flatten' method, 206 * but returns objects' keys wrapped in '[]'. 207 * 208 * @param {Object} data - Object that should be serialized. 209 * @returns {Object} Serialized data. 210 * 211 * @example
212 * utils.serialize({one: { two: { three: 'value'} }}); 213 * => { 'one[two][three]': 'value' } 214 */ 215 serialize: function (data) { 216 var result = {}; 217 218 data = this.flatten(data); 219 220 _.each(data, function (value, keys) { 221 keys = stringUtils.serializeName(keys); 222 value = _.isUndefined(value) ? '' : value; 223 224 result[keys] = value; 225 }, this); 226 227 return result; 228 }, 229 230 /** 231 * Performs deep extend of specified objects. 232 * 233 * @returns {Object|Array} Extended object. 234 */ 235 extend: function () { 236 var args = _.toArray(arguments); 237 238 args.unshift(true); 239 240 return $.extend.apply($, args); 241 }, 242 243 /** 244 * Performs a deep clone of a specified object. 245 * 246 * @param {(Object|Array)} data - Data that should be copied. 247 * @returns {Object|Array} Cloned object. 248 */ 249 copy: function (data) { 250 var result = data, 251 isArray = Array.isArray(data), 252 placeholder; 253 254 if (this.isObject(data) || isArray) { 255 placeholder = isArray ? [] : {}; 256 result = this.extend(placeholder, data); 257 } 258 259 return result; 260 }, 261 262 /** 263 * Performs a deep clone of a specified object. 264 * Doesn't save links to original object. 265 * 266 * @param {*} original - Object to clone 267 * @returns {*} 268 */ 269 hardCopy: function (original) { 270 if (original === null || typeof original !== 'object') { 271 return original; 272 } 273 274 return JSON.parse(JSON.stringify(original)); 275 }, 276 277 /** 278 * Removes specified nested properties from the target object. 279 * 280 * @param {Object} target - Object whose properties should be removed. 281 * @param {(...String|Array|Object)} list - List that specifies properties to be removed. 282 * @returns {Object} Modified object. 283 * 284 * @example Basic usage 285 * var obj = {a: {b: 2}, c: 'a'}; 286 * 287 * omit(obj, 'a.b'); 288 * => {'a.b': 2}; 289 * obj => {a: {}, c: 'a'}; 290 * 291 * @example Various syntaxes that would return same result 292 * omit(obj, ['a.b', 'c']); 293 * omit(obj, 'a.b', 'c'); 294 * omit(obj, {'a.b': true, 'c': true}); 295 */ 296 omit: function (target, list) { 297 var removed = {}, 298 ignored = list; 299 300 if (this.isObject(list)) { 301 ignored = []; 302 303 _.each(list, function (value, key) { 304 if (value) { 305 ignored.push(key); 306 } 307 }); 308 } else if (_.isString(list)) { 309 ignored = _.toArray(arguments).slice(1); 310 } 311 312 _.each(ignored, function (path) { 313 var value = this.nested(target, path); 314 315 if (!_.isUndefined(value)) { 316 removed[path] = value; 317 318 this.nestedRemove(target, path); 319 } 320 }, this); 321 322 return removed; 323 }, 324 325 /** 326 * Checks if provided value is a plain object. 327 * 328 * @param {*} value - Value to be checked. 329 * @returns {Boolean} 330 */ 331 isObject: function (value) { 332 var objProto = Object.prototype; 333 334 return typeof value == 'object' ? 335 objProto.toString.call(value) === '[object Object]' : 336 false; 337 }, 338 339 /** 340 * 341 * @param {*} value 342 * @returns {Boolean} 343 */ 344 isPrimitive: function (value) { 345 return value === null || ~primitives.indexOf(typeof value); 346 }, 347 348 /** 349 * Iterates over obj props/array elems recursively, applying action to each one 350 * 351 * @param {Object|Array} data - Data to be iterated. 352 * @param {Function} action - Callback to be called with each item as an argument. 353 * @param {Number} [maxDepth=7] - Max recursion depth. 354 */
355 forEachRecursive: function (data, action, maxDepth) { 356 maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7; 357 358 if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) { 359 return; 360 } 361 362 if (!_.isObject(data)) { 363 action(data); 364 365 return; 366 } 367 368 _.each(data, function (value) { 369 this.forEachRecursive(value, action, maxDepth); 370 }, this); 371 372 action(data); 373 }, 374 375 /** 376 * Maps obj props/array elems recursively 377 * 378 * @param {Object|Array} data - Data to be iterated. 379 * @param {Function} action - Callback to transform each item. 380 * @param {Number} [maxDepth=7] - Max recursion depth. 381 * 382 * @returns {Object|Array} 383 */ 384 mapRecursive: function (data, action, maxDepth) { 385 var newData; 386 387 maxDepth = typeof maxDepth === 'number' && !isNaN(maxDepth) ? maxDepth - 1 : 7; 388 389 if (!_.isFunction(action) || _.isFunction(data) || maxDepth < 0) { 390 return data; 391 } 392 393 if (!_.isObject(data)) { 394 return action(data); 395 } 396 397 if (_.isArray(data)) { 398 newData = _.map(data, function (item) { 399 return this.mapRecursive(item, action, maxDepth); 400 }, this); 401 402 return action(newData); 403 } 404 405 newData = _.mapObject(data, function (val, key) { 406 if (data.hasOwnProperty(key)) { 407 return this.mapRecursive(val, action, maxDepth); 408 } 409 410 return val; 411 }, this); 412 413 return action(newData); 414 }, 415 416 /** 417 * Removes empty(in common sence) obj props/array elems 418 * 419 * @param {*} data - Data to be cleaned. 420 * @returns {*} 421 */ 422 removeEmptyValues: function (data) { 423 if (!_.isObject(data)) { 424 return data; 425 } 426 427 if (_.isArray(data)) { 428 return data.filter(function (item) { 429 return !this.isEmptyObj(item); 430 }, this); 431 } 432 433 return _.omit(data, this.isEmptyObj.bind(this)); 434 }, 435 436 /** 437 * Checks that argument of any type is empty in common sence: 438 * empty string, string with spaces only, object without own props, empty array, null or undefined 439 * 440 * @param {*} val - Value to be checked. 441 * @returns {Boolean} 442 */ 443 isEmptyObj: function (val) { 444 445 return _.isObject(val) && _.isEmpty(val) || 446 this.isEmpty(val) || 447 val && val.trim && this.isEmpty(val.trim()); 448 } 449 }; 450}); 451
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.