diff --git a/src/js/serverUtils.js b/src/js/serverUtils.js index a1ebb76..74a9342 100644 --- a/src/js/serverUtils.js +++ b/src/js/serverUtils.js @@ -26,40 +26,41 @@ try { } // Optimized replaceJsonKeys function -const replaceJsonKeys = (obj) => { - if (!obj || typeof obj !== 'object') return obj; - - // Fast-path for arrays - if (Array.isArray(obj)) { - // Only process array if it has items - return obj.length > 0 ? obj.map(replaceJsonKeys) : obj; +const replaceJsonKeys = (obj, replacements) => { + // Handle non-objects early + if (!obj || typeof obj !== 'object') return obj; + + // Fast path for arrays + if (Array.isArray(obj)) { + return obj.length === 0 ? + obj + : obj.map((item) => replaceJsonKeys(item, replacements)); + } + + // Fast path for empty objects + const keys = Object.keys(obj); + if (keys.length === 0) return obj; + + // Process normal objects + const newObj = {}; + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const newKey = replacements[key] || key; + let value = obj[key]; + + // Replace string values if they match a key in replacements + if (typeof value === 'string' && replacements[value]) { + value = replacements[value]; + } else if (value && typeof value === 'object') { + // Only recurse for objects/arrays + value = replaceJsonKeys(value, replacements); } - - const newObj = {}; - const objKeys = Object.keys(obj); - - // Fast-path for empty objects - if (objKeys.length === 0) return obj; - - // Cache key check - const hasKeyReplacements = Object.keys(keyReplacements).length > 0; - - for (const key of objKeys) { - // Replace key if replacements exist - const newKey = hasKeyReplacements && keyReplacements[key] ? keyReplacements[key] : key; - let value = obj[key]; - - // Replace string values if needed - if (hasKeyReplacements && typeof value === 'string' && keyReplacements[value]) { - value = keyReplacements[value]; - } - - // Process recursively only if object/array - newObj[newKey] = (value && typeof value === 'object') ? replaceJsonKeys(value) : value; - } - - return newObj; - }; + + newObj[newKey] = value; + } + + return newObj; +}; // Utility regex function const sanitizeJsonOutput = (data) => { @@ -87,27 +88,18 @@ const sanitizeJsonOutput = (data) => { // Replace the processJsonOutput function with this more efficient version const processJsonOutput = ( data, - options = { sanitize: true, replaceKeys: true } + options = { + sanitize: true, + replaceKeys: true, + keyReplacements: {}, + } ) => { - // Use a more efficient deep clone approach instead of JSON.parse(JSON.stringify()) - function deepClone(obj) { - if (obj === null || typeof obj !== 'object') { - return obj; - } - - if (Array.isArray(obj)) { - return obj.map((item) => deepClone(item)); - } - - const clone = {}; - Object.keys(obj).forEach((key) => { - clone[key] = deepClone(obj[key]); - }); - - return clone; + // Early return for null or non-objects + if (data === null || typeof data !== 'object') { + return data; } - // Create a deep copy of the data to avoid reference issues + // Copy data first to avoid reference issues let processedData = deepClone(data); // Apply sanitization if needed @@ -115,14 +107,48 @@ const processJsonOutput = ( processedData = sanitizeJsonOutput(processedData); } - // Apply key replacement if needed - if (options.replaceKeys) { - processedData = replaceJsonKeys(processedData); + // Apply key replacement if needed - pass replacements directly + if ( + options.replaceKeys && + Object.keys(options.keyReplacements || {}).length > 0 + ) { + processedData = replaceJsonKeys(processedData, options.keyReplacements); } return processedData; }; +/** + * Optimized deep clone function + * @param {any} obj - The object to clone + * @returns {any} - The cloned object + */ +const deepClone = (obj) => { + if (obj === null || typeof obj !== 'object') { + return obj; + } + + // Fast path for arrays + if (Array.isArray(obj)) { + const length = obj.length; + const clone = new Array(length); + for (let i = 0; i < length; i++) { + clone[i] = deepClone(obj[i]); + } + return clone; + } + + // Fast path for objects + const clone = {}; + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + clone[key] = deepClone(obj[key]); + } + + return clone; +}; + // Store active sessions to avoid repeated logins const activeSessions = new Map(); @@ -248,5 +274,5 @@ module.exports = { ensureLogin, handleApiError, sanitizeHeaders, - processJsonOutput -}; \ No newline at end of file + processJsonOutput, +};