hashable-cli
Version:
Generate consistent and predictable JSON output for hashing, version control, and testing. Sorts arrays based on a configurable priority list of fields, handles nested objects and arrays, and optionally sorts object keys alphabetically. Provides a comma
93 lines (79 loc) • 2.06 kB
JavaScript
/**
* Generate consistent hashable JSON payload
* great for piping through hash functions.
*
* Use `sortObject` to sort object keys. Default: false
* Use `priority` to specify array sorting priority
* (default priority is used if not specified)
*
* @author CJ <lim@chernjie.com>
*/
const defaultSort = [
"id",
"_id",
"name",
"key",
"category",
"value",
"label",
"page",
"language",
"store_id",
"category_id",
]
export function getDefaultPriority() {
return [...defaultSort]
}
function hashable(data, { priority = getDefaultPriority(), sortObject = false } = {}) {
if (!_isObject(data)) return data
const sorted = {}
Object.keys(data).forEach(key => {
// array
if (Array.isArray(data[key])) {
sorted[key] = data[key].filter(e => e !== null)
.sort((a, b) => {
if (['number', 'string'].includes(typeof a)) return sortBy(a, b)
for (var i in priority) {
const field = priority[i]
const first = _get(a, field)
if (typeof first !== 'undefined') return sortBy(first, _get(b, field))
}
console.error('hashable sorting', a, b)
})
.map(obj => hashable(obj, { priority, sortObject }))
}
// object
else if (_isObject(data[key])) {
sorted[key] = hashable(data[key], { priority, sortObject })
}
// primitive
else {
sorted[key] = data[key]
}
})
if (sortObject) {
return Object.keys(sorted)
.sort()
.reduce((accumulator, key) => {
accumulator[key] = sorted[key]
return accumulator
}, {})
}
return sorted
}
function sortBy(a, b) {
if (a === b) return 0
return a > b ? 1 : -1
}
function _get(obj, path) {
return path.split('.').reduce((v, k) => {
if (typeof v === 'undefined') return undefined
if (typeof v[k] === 'undefined') return undefined
return v[k]
}, obj)
}
function _isObject(obj) {
const type = typeof obj
return type === 'function' || (type === 'object' && !!obj)
}
export default hashable