import _ from "lodash"; /** * @class Web3Encoder */ export class Web3Encoder { /** * @param obj {Record} * @param exceptedKeys {Array} * @returns {Promise} */ public static encode( obj : Record, exceptedKeys ? : Array ) : Promise { return new Promise( async ( resolve, reject ) => { try { if ( ! obj ) { return reject( `invalid obj` ); } let keysToRemove : Array = [ 'sig', 'hash', 'createdAt', 'updatedAt' ]; if ( Array.isArray( exceptedKeys ) && exceptedKeys.length > 0 ) { keysToRemove = Array.from( new Set( [ ...keysToRemove, ...exceptedKeys ] ) ); } const cleanedUpObj : Record = this.removeObjectKeys( obj, keysToRemove ); const sortedObj : Record = this.sortObjectByKeys( cleanedUpObj ); const encodedMessage : string = JSON.stringify( sortedObj ); resolve( encodedMessage ); } catch ( err ) { reject( err ); } } ); } /** * @param encodedMessage {string} * @returns {Promise>} */ public static decode( encodedMessage : string ) : Promise> { return new Promise( async ( resolve, reject ) => { try { resolve( JSON.parse( encodedMessage ) ); } catch ( err ) { reject( err ); } } ); } /** * determine whether the key of an object is of string type * @param obj * @param key * @returns {boolean} */ public static isStringKey( obj : object, key : string ) : obj is Record { return key in obj; } /** * @param obj { Record } * @param keysToRemove { Array } * @returns { Record } */ public static removeObjectKeys( obj : Record, keysToRemove : Array ) : Record { if ( ! _.isObject( obj ) || null === obj ) { return obj; } if ( ! Array.isArray( keysToRemove ) || 0 === keysToRemove.length ) { return obj; } return Object.fromEntries( Object.entries( obj ).filter( ( [ key ] ) => ! keysToRemove.includes( key ) ) ); } /** * @param obj {Record} * @param reservedKeys {Array} * @returns {Record} */ public static reserveObjectKeys( obj : Record, reservedKeys : Array ) : Record { if ( ! _.isObject( obj ) || null === obj ) { return obj; } if ( ! Array.isArray( reservedKeys ) || 0 === reservedKeys.length ) { return obj; } return Object.fromEntries( Object.entries( obj ).filter( ( [ key ] ) => reservedKeys.includes( key ) ) ); } /** * @param obj {*} * @returns {*} */ public static sortObjectByKeys( obj : T ) : T | Array { try { if ( 'object' !== typeof obj || null === obj ) { return obj; } if ( Array.isArray( obj ) ) { return obj.map( this.sortObjectByKeys ); } const stringKeysObj : { [ key : string ] : any } = obj as { [ key : string ] : any }; const sortedObject : any = {}; // Get the keys and sort them alphabetically const keys : Array = Object.keys( stringKeysObj ).sort(); for ( const key of keys ) { if ( ! this.isStringKey( stringKeysObj, key ) ) { continue; } // recursively sort nested objects sortedObject[ key ] = this.sortObjectByKeys( stringKeysObj[ key ] ); } return sortedObject as T; } catch ( err ) { return obj; } } }