"use strict"; /* * Hashing and comparison utility functions for the RSpade framework. * These functions handle object hashing and deep comparison. */ // ============================================================================ // HASHING AND COMPARISON // ============================================================================ /** * Generates a unique hash for any value (handles objects, arrays, circular references) * @param {*} the_var - Value to hash * @param {boolean} [calc_sha1=true] - If true, returns SHA1 hash; if false, returns JSON * @param {Array} [ignored_keys=null] - Keys to ignore when hashing objects * @returns {string} SHA1 hash or JSON string of the value */ function hash(the_var) { let calc_sha1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; let ignored_keys = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; if (typeof the_var == undef) { the_var = '__undefined__'; } if (ignored_keys === null) { ignored_keys = ['$']; } // Converts value to json, discarding circular references let json_stringify_nocirc = function (value) { const cache = []; return JSON.stringify(value, function (key, v) { if (typeof v === 'object' && typeof the_var._cache_key == 'function') { return the_var._hash_key(); } else if (typeof v === 'object' && v !== null) { if (cache.indexOf(v) !== -1) { // Duplicate reference found, discard key return; } cache.push(v); } return v; }); }; // Turn every property and all its children into a single depth array of values that we can then // sort and hash as a whole let flat_var = {}; let _flatten = function (the_var, prefix) { let depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; // If a class object is provided, circular references can make the call stack recursive. // For the purposes of how the hash function is called, this should be sufficient. if (depth > 10) { return; } // Does not account for dates i think... if (is_object(the_var) && typeof the_var._cache_key == 'function') { // Use _cache_key to hash components flat_var[prefix] = the_var._hash_key(); } else if (is_object(the_var) && typeof Abstract !== 'undefined' && the_var instanceof Abstract) { // Stringify all class objects flat_var[prefix] = json_stringify_nocirc(the_var); } else if (is_object(the_var)) { // Iterate other objects flat_var[prefix] = {}; for (let k in the_var) { if (the_var.hasOwnProperty(k) && ignored_keys.indexOf(k) == -1) { _flatten(the_var[k], prefix + '..' + k, depth + 1); } } } else if (is_array(the_var)) { // Iterate arrays flat_var[prefix] = []; let i = 0; foreach(the_var, v => { _flatten(v, prefix + '..' + i, depth + 1); i++; }); } else if (is_function(the_var)) { // nothing } else if (!is_numeric(the_var)) { flat_var[prefix] = String(the_var); } else { flat_var[prefix] = the_var; } }; _flatten(the_var, '_'); let sorter = []; foreach(flat_var, function (v, k) { sorter.push([k, v]); }); sorter.sort(function (a, b) { return a[0] > b[0]; }); let json = JSON.stringify(sorter); if (calc_sha1) { let hashed = sha1.sha1(json); return hashed; } else { return json; } } /** * Deep comparison of two values (ignores property order and functions) * @param {*} a - First value to compare * @param {*} b - Second value to compare * @returns {boolean} True if values are deeply equal */ function deep_equal(a, b) { return hash(a, false) == hash(b, false); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJoYXNoIiwidGhlX3ZhciIsImNhbGNfc2hhMSIsImFyZ3VtZW50cyIsImxlbmd0aCIsInVuZGVmaW5lZCIsImlnbm9yZWRfa2V5cyIsInVuZGVmIiwianNvbl9zdHJpbmdpZnlfbm9jaXJjIiwidmFsdWUiLCJjYWNoZSIsIkpTT04iLCJzdHJpbmdpZnkiLCJrZXkiLCJ2IiwiX2NhY2hlX2tleSIsIl9oYXNoX2tleSIsImluZGV4T2YiLCJwdXNoIiwiZmxhdF92YXIiLCJfZmxhdHRlbiIsInByZWZpeCIsImRlcHRoIiwiaXNfb2JqZWN0IiwiQWJzdHJhY3QiLCJrIiwiaGFzT3duUHJvcGVydHkiLCJpc19hcnJheSIsImkiLCJmb3JlYWNoIiwiaXNfZnVuY3Rpb24iLCJpc19udW1lcmljIiwiU3RyaW5nIiwic29ydGVyIiwic29ydCIsImEiLCJiIiwianNvbiIsImhhc2hlZCIsInNoYTEiLCJkZWVwX2VxdWFsIl0sInNvdXJjZXMiOlsiYXBwL1JTcGFkZS9Db3JlL0pzL2hhc2guanMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIEhhc2hpbmcgYW5kIGNvbXBhcmlzb24gdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHRoZSBSU3BhZGUgZnJhbWV3b3JrLlxuICogVGhlc2UgZnVuY3Rpb25zIGhhbmRsZSBvYmplY3QgaGFzaGluZyBhbmQgZGVlcCBjb21wYXJpc29uLlxuICovXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEhBU0hJTkcgQU5EIENPTVBBUklTT05cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSB1bmlxdWUgaGFzaCBmb3IgYW55IHZhbHVlIChoYW5kbGVzIG9iamVjdHMsIGFycmF5cywgY2lyY3VsYXIgcmVmZXJlbmNlcylcbiAqIEBwYXJhbSB7Kn0gdGhlX3ZhciAtIFZhbHVlIHRvIGhhc2hcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NhbGNfc2hhMT10cnVlXSAtIElmIHRydWUsIHJldHVybnMgU0hBMSBoYXNoOyBpZiBmYWxzZSwgcmV0dXJucyBKU09OXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFtpZ25vcmVkX2tleXM9bnVsbF0gLSBLZXlzIHRvIGlnbm9yZSB3aGVuIGhhc2hpbmcgb2JqZWN0c1xuICogQHJldHVybnMge3N0cmluZ30gU0hBMSBoYXNoIG9yIEpTT04gc3RyaW5nIG9mIHRoZSB2YWx1ZVxuICovXG5mdW5jdGlvbiBoYXNoKHRoZV92YXIsIGNhbGNfc2hhMSA9IHRydWUsIGlnbm9yZWRfa2V5cyA9IG51bGwpIHtcbiAgICBpZiAodHlwZW9mIHRoZV92YXIgPT0gdW5kZWYpIHtcbiAgICAgICAgdGhlX3ZhciA9ICdfX3VuZGVmaW5lZF9fJztcbiAgICB9XG5cbiAgICBpZiAoaWdub3JlZF9rZXlzID09PSBudWxsKSB7XG4gICAgICAgIGlnbm9yZWRfa2V5cyA9IFsnJCddO1xuICAgIH1cblxuICAgIC8vIENvbnZlcnRzIHZhbHVlIHRvIGpzb24sIGRpc2NhcmRpbmcgY2lyY3VsYXIgcmVmZXJlbmNlc1xuICAgIGxldCBqc29uX3N0cmluZ2lmeV9ub2NpcmMgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgY29uc3QgY2FjaGUgPSBbXTtcbiAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHZhbHVlLCBmdW5jdGlvbiAoa2V5LCB2KSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHYgPT09ICdvYmplY3QnICYmIHR5cGVvZiB0aGVfdmFyLl9jYWNoZV9rZXkgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGVfdmFyLl9oYXNoX2tleSgpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdiA9PT0gJ29iamVjdCcgJiYgdiAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIGlmIChjYWNoZS5pbmRleE9mKHYpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBEdXBsaWNhdGUgcmVmZXJlbmNlIGZvdW5kLCBkaXNjYXJkIGtleVxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhY2hlLnB1c2godik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdjtcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8vIFR1cm4gZXZlcnkgcHJvcGVydHkgYW5kIGFsbCBpdHMgY2hpbGRyZW4gaW50byBhIHNpbmdsZSBkZXB0aCBhcnJheSBvZiB2YWx1ZXMgdGhhdCB3ZSBjYW4gdGhlblxuICAgIC8vIHNvcnQgYW5kIGhhc2ggYXMgYSB3aG9sZVxuICAgIGxldCBmbGF0X3ZhciA9IHt9O1xuICAgIGxldCBfZmxhdHRlbiA9IGZ1bmN0aW9uICh0aGVfdmFyLCBwcmVmaXgsIGRlcHRoID0gMCkge1xuICAgICAgICAvLyBJZiBhIGNsYXNzIG9iamVjdCBpcyBwcm92aWRlZCwgY2lyY3VsYXIgcmVmZXJlbmNlcyBjYW4gbWFrZSB0aGUgY2FsbCBzdGFjayByZWN1cnNpdmUuXG4gICAgICAgIC8vIEZvciB0aGUgcHVycG9zZXMgb2YgaG93IHRoZSBoYXNoIGZ1bmN0aW9uIGlzIGNhbGxlZCwgdGhpcyBzaG91bGQgYmUgc3VmZmljaWVudC5cbiAgICAgICAgaWYgKGRlcHRoID4gMTApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERvZXMgbm90IGFjY291bnQgZm9yIGRhdGVzIGkgdGhpbmsuLi5cblxuICAgICAgICBpZiAoaXNfb2JqZWN0KHRoZV92YXIpICYmIHR5cGVvZiB0aGVfdmFyLl9jYWNoZV9rZXkgPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgLy8gVXNlIF9jYWNoZV9rZXkgdG8gaGFzaCBjb21wb25lbnRzXG4gICAgICAgICAgICBmbGF0X3ZhcltwcmVmaXhdID0gdGhlX3Zhci5faGFzaF9rZXkoKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc19vYmplY3QodGhlX3ZhcikgJiYgdHlwZW9mIEFic3RyYWN0ICE9PSAndW5kZWZpbmVkJyAmJiB0aGVfdmFyIGluc3RhbmNlb2YgQWJzdHJhY3QpIHtcbiAgICAgICAgICAgIC8vIFN0cmluZ2lmeSBhbGwgY2xhc3Mgb2JqZWN0c1xuICAgICAgICAgICAgZmxhdF92YXJbcHJlZml4XSA9IGpzb25fc3RyaW5naWZ5X25vY2lyYyh0aGVfdmFyKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc19vYmplY3QodGhlX3ZhcikpIHtcbiAgICAgICAgICAgIC8vIEl0ZXJhdGUgb3RoZXIgb2JqZWN0c1xuICAgICAgICAgICAgZmxhdF92YXJbcHJlZml4XSA9IHt9O1xuICAgICAgICAgICAgZm9yIChsZXQgayBpbiB0aGVfdmFyKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoZV92YXIuaGFzT3duUHJvcGVydHkoaykgJiYgaWdub3JlZF9rZXlzLmluZGV4T2YoaykgPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgX2ZsYXR0ZW4odGhlX3ZhcltrXSwgcHJlZml4ICsgJy4uJyArIGssIGRlcHRoICsgMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGlzX2FycmF5KHRoZV92YXIpKSB7XG4gICAgICAgICAgICAvLyBJdGVyYXRlIGFycmF5c1xuICAgICAgICAgICAgZmxhdF92YXJbcHJlZml4XSA9IFtdO1xuICAgICAgICAgICAgbGV0IGkgPSAwO1xuICAgICAgICAgICAgZm9yZWFjaCh0aGVfdmFyLCAodikgPT4ge1xuICAgICAgICAgICAgICAgIF9mbGF0dGVuKHYsIHByZWZpeCArICcuLicgKyBpLCBkZXB0aCArIDEpO1xuICAgICAgICAgICAgICAgIGkrKztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGlzX2Z1bmN0aW9uKHRoZV92YXIpKSB7XG4gICAgICAgICAgICAvLyBub3RoaW5nXG4gICAgICAgIH0gZWxzZSBpZiAoIWlzX251bWVyaWModGhlX3ZhcikpIHtcbiAgICAgICAgICAgIGZsYXRfdmFyW3ByZWZpeF0gPSBTdHJpbmcodGhlX3Zhcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmbGF0X3ZhcltwcmVmaXhdID0gdGhlX3ZhcjtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBfZmxhdHRlbih0aGVfdmFyLCAnXycpO1xuXG4gICAgbGV0IHNvcnRlciA9IFtdO1xuXG4gICAgZm9yZWFjaChmbGF0X3ZhciwgZnVuY3Rpb24gKHYsIGspIHtcbiAgICAgICAgc29ydGVyLnB1c2goW2ssIHZdKTtcbiAgICB9KTtcblxuICAgIHNvcnRlci5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIHJldHVybiBhWzBdID4gYlswXTtcbiAgICB9KTtcblxuICAgIGxldCBqc29uID0gSlNPTi5zdHJpbmdpZnkoc29ydGVyKTtcblxuICAgIGlmIChjYWxjX3NoYTEpIHtcbiAgICAgICAgbGV0IGhhc2hlZCA9IHNoYTEuc2hhMShqc29uKTtcbiAgICAgICAgcmV0dXJuIGhhc2hlZDtcbiAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4ganNvbjtcbiAgICB9XG59XG5cbi8qKlxuICogRGVlcCBjb21wYXJpc29uIG9mIHR3byB2YWx1ZXMgKGlnbm9yZXMgcHJvcGVydHkgb3JkZXIgYW5kIGZ1bmN0aW9ucylcbiAqIEBwYXJhbSB7Kn0gYSAtIEZpcnN0IHZhbHVlIHRvIGNvbXBhcmVcbiAqIEBwYXJhbSB7Kn0gYiAtIFNlY29uZCB2YWx1ZSB0byBjb21wYXJlXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB2YWx1ZXMgYXJlIGRlZXBseSBlcXVhbFxuICovXG5mdW5jdGlvbiBkZWVwX2VxdWFsKGEsIGIpIHtcbiAgICByZXR1cm4gaGFzaChhLCBmYWxzZSkgPT0g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