226 lines
5.5 KiB
JavaScript
Executable File
226 lines
5.5 KiB
JavaScript
Executable File
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
define([
|
|
'underscore',
|
|
'mage/utils/objects'
|
|
], function (_, utils) {
|
|
'use strict';
|
|
|
|
var result = [];
|
|
|
|
/**
|
|
* Checks if all of the provided arrays contains equal values.
|
|
*
|
|
* @param {(Boolean|Array)} [keepOrder=false]
|
|
* @param {Array} target
|
|
* @returns {Boolean}
|
|
*/
|
|
function equalArrays(keepOrder, target) {
|
|
var args = _.toArray(arguments),
|
|
arrays;
|
|
|
|
if (!Array.isArray(keepOrder)) {
|
|
arrays = args.slice(2);
|
|
} else {
|
|
target = keepOrder;
|
|
keepOrder = false;
|
|
arrays = args.slice(1);
|
|
}
|
|
|
|
if (!arrays.length) {
|
|
return true;
|
|
}
|
|
|
|
return arrays.every(function (array) {
|
|
if (array === target) {
|
|
return true;
|
|
} else if (array.length !== target.length) {
|
|
return false;
|
|
} else if (!keepOrder) {
|
|
return !_.difference(target, array).length;
|
|
}
|
|
|
|
return array.every(function (value, index) {
|
|
return target[index] === value;
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Checks if two values are different.
|
|
*
|
|
* @param {*} a - First value.
|
|
* @param {*} b - Second value.
|
|
* @returns {Boolean}
|
|
*/
|
|
function isDifferent(a, b) {
|
|
var oldIsPrimitive = utils.isPrimitive(a);
|
|
|
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
return !equalArrays(true, a, b);
|
|
}
|
|
|
|
return oldIsPrimitive ? a !== b : true;
|
|
}
|
|
|
|
/**
|
|
* @param {String} prefix
|
|
* @param {String} part
|
|
*/
|
|
function getPath(prefix, part) {
|
|
return prefix ? prefix + '.' + part : part;
|
|
}
|
|
|
|
/**
|
|
* Checks if object has own specified property.
|
|
*
|
|
* @param {*} obj - Value to be checked.
|
|
* @param {String} key - Key of the property.
|
|
* @returns {Boolean}
|
|
*/
|
|
function hasOwn(obj, key) {
|
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
}
|
|
|
|
/**
|
|
* @param {Array} changes
|
|
*/
|
|
function getContainers(changes) {
|
|
var containers = {},
|
|
indexed = _.indexBy(changes, 'path');
|
|
|
|
_.each(indexed, function (change, name) {
|
|
var path;
|
|
|
|
name.split('.').forEach(function (part) {
|
|
path = getPath(path, part);
|
|
|
|
if (path in indexed) {
|
|
return;
|
|
}
|
|
|
|
(containers[path] = containers[path] || []).push(change);
|
|
});
|
|
});
|
|
|
|
return containers;
|
|
}
|
|
|
|
/**
|
|
* @param {String} path
|
|
* @param {String} name
|
|
* @param {String} type
|
|
* @param {String} newValue
|
|
* @param {String} oldValue
|
|
*/
|
|
function addChange(path, name, type, newValue, oldValue) {
|
|
var data;
|
|
|
|
data = {
|
|
path: path,
|
|
name: name,
|
|
type: type
|
|
};
|
|
|
|
if (type !== 'remove') {
|
|
data.value = newValue;
|
|
data.oldValue = oldValue;
|
|
} else {
|
|
data.oldValue = newValue;
|
|
}
|
|
|
|
result.push(data);
|
|
}
|
|
|
|
/**
|
|
* @param {String} ns
|
|
* @param {String} name
|
|
* @param {String} type
|
|
* @param {String} iterator
|
|
* @param {String} placeholder
|
|
*/
|
|
function setAll(ns, name, type, iterator, placeholder) {
|
|
var key;
|
|
|
|
if (arguments.length > 4) {
|
|
type === 'add' ?
|
|
addChange(ns, name, 'update', iterator, placeholder) :
|
|
addChange(ns, name, 'update', placeholder, iterator);
|
|
} else {
|
|
addChange(ns, name, type, iterator);
|
|
}
|
|
|
|
if (!utils.isObject(iterator)) {
|
|
return;
|
|
}
|
|
|
|
for (key in iterator) {
|
|
if (hasOwn(iterator, key)) {
|
|
setAll(getPath(ns, key), key, type, iterator[key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*eslint-disable max-depth*/
|
|
/**
|
|
* @param {Object} old
|
|
* @param {Object} current
|
|
* @param {String} ns
|
|
* @param {String} name
|
|
*/
|
|
function compare(old, current, ns, name) {
|
|
var key,
|
|
oldIsObj = utils.isObject(old),
|
|
newIsObj = utils.isObject(current);
|
|
|
|
if (oldIsObj && newIsObj) {
|
|
for (key in old) {
|
|
if (hasOwn(old, key) && !hasOwn(current, key)) {
|
|
setAll(getPath(ns, key), key, 'remove', old[key]);
|
|
}
|
|
}
|
|
|
|
for (key in current) {
|
|
if (hasOwn(current, key)) {
|
|
hasOwn(old, key) ?
|
|
compare(old[key], current[key], getPath(ns, key), key) :
|
|
setAll(getPath(ns, key), key, 'add', current[key]);
|
|
}
|
|
}
|
|
} else if (oldIsObj) {
|
|
setAll(ns, name, 'remove', old, current);
|
|
} else if (newIsObj) {
|
|
setAll(ns, name, 'add', current, old);
|
|
} else if (isDifferent(old, current)) {
|
|
addChange(ns, name, 'update', current, old);
|
|
}
|
|
}
|
|
|
|
/*eslint-enable max-depth*/
|
|
|
|
return {
|
|
|
|
/**
|
|
*
|
|
* @returns {Object}
|
|
*/
|
|
compare: function () {
|
|
var changes;
|
|
|
|
compare.apply(null, arguments);
|
|
|
|
changes = result.splice(0);
|
|
|
|
return {
|
|
containers: getContainers(changes),
|
|
changes: changes,
|
|
equal: !changes.length
|
|
};
|
|
},
|
|
|
|
equalArrays: equalArrays
|
|
};
|
|
});
|