Fix bin/publish: use correct .env path for rspade_system Fix bin/publish script: prevent grep exit code 1 from terminating script 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
116 lines
3.8 KiB
JavaScript
Executable File
116 lines
3.8 KiB
JavaScript
Executable File
/*
|
|
* 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<string>} [ignored_keys=null] - Keys to ignore when hashing objects
|
|
* @returns {string} SHA1 hash or JSON string of the value
|
|
*/
|
|
function hash(the_var, calc_sha1 = true, ignored_keys = 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, depth = 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);
|
|
} |