UNPKG

json-canonicalize

Version:
110 lines (99 loc) 3.22 kB
export interface IOptions { exclude?: string | string[] include?: string[] allowCircular?: boolean } export function canonicalizeEx(obj: any, options?: IOptions) { let buffer = '' const vInclude = options && options.include let vExclude = options && options.exclude if (vExclude) { if (typeof vExclude === 'string') vExclude = [vExclude] } if (vInclude) vInclude.sort() const visited = new WeakMap<object, boolean>() const allowCircular = options && options?.allowCircular serialize(obj) return buffer function serialize(object: any, parent?: object) { if ( object === null || typeof object !== 'object' || object.toJSON != null ) { ///////////////////////////////////////////////// // Primitive data type - Use ES6/JSON // ///////////////////////////////////////////////// buffer += JSON.stringify(object) // } else if (object instanceof Date) { // buffer += JSON.stringify(object); } else if (Array.isArray(object)) { ///////////////////////////////////////////////// // Array - Maintain element order // ///////////////////////////////////////////////// if (visited.has(object)) { if (!allowCircular) { throw new Error('Circular reference detected') } buffer += '"[Circular]"' return } visited.set(object, true) buffer += '[' let next = false object.forEach((element) => { if (next) { buffer += ',' } next = true ///////////////////////////////////////// // Array element - Recursive expansion // ///////////////////////////////////////// serialize(element, object) }) buffer += ']' } else { ///////////////////////////////////////////////// // Object - Sort properties before serializing // ///////////////////////////////////////////////// if (visited.has(object)) { if (!allowCircular) { throw new Error('Circular reference detected') } buffer += '"[Circular]"' return } visited.set(object, true) buffer += '{' if (!parent && vInclude) { vInclude.forEach((property, index) => { if (!object.hasOwnProperty(property)) return addProp(object, property, index) }) } else { const vKeys = Object.keys(object).sort() vKeys.forEach((property, index) => addProp(object, property, index)) } buffer += '}' } } function addProp(object: any, property: string, index: number) { if (vExclude && vExclude.length) { for (const v of vExclude) { if (v === property) return } } if (index > 0) { buffer += ',' } /////////////////////////////////////////////// // Property names are strings - Use ES6/JSON // /////////////////////////////////////////////// buffer += JSON.stringify(property) buffer += ':' ////////////////////////////////////////// // Property value - Recursive expansion // ////////////////////////////////////////// serialize(object[property], object) } }