|
@ -44,47 +44,53 @@ export function redactAttributes({ |
|
|
return object; |
|
|
return object; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Create deep clone
|
|
|
// Use efficient deep clone from lodash only on first run
|
|
|
const redactedObject = isFirstRun |
|
|
const redactedObject = isFirstRun ? cloneDeep(object) : object; |
|
|
? JSON.parse(JSON.stringify(object)) |
|
|
|
|
|
: object; |
|
|
|
|
|
|
|
|
|
|
|
for (const option of options) { |
|
|
// Create a Map for faster attribute lookup
|
|
|
if (redactedObject.hasOwnProperty(option.attribute)) { |
|
|
const attributeMap = new Map( |
|
|
if (option.valueMap['*'] || option.valueMap['*'] === null) { |
|
|
options.map((opt) => [opt.attribute, opt.valueMap]) |
|
|
redactedObject[option.attribute] = option.valueMap['*']; |
|
|
); |
|
|
} else if (option.valueMap[redactedObject[option.attribute]]) { |
|
|
|
|
|
redactedObject[option.attribute] = |
|
|
// Process current level attributes first
|
|
|
option.valueMap[redactedObject[option.attribute]]; |
|
|
for (const [attribute, valueMap] of attributeMap) { |
|
|
|
|
|
if (attribute in redactedObject) { |
|
|
|
|
|
const currentValue = redactedObject[attribute]; |
|
|
|
|
|
|
|
|
|
|
|
// Check for wildcard first, then specific value
|
|
|
|
|
|
if ('*' in valueMap) { |
|
|
|
|
|
redactedObject[attribute] = valueMap['*']; |
|
|
|
|
|
} else if (currentValue in valueMap) { |
|
|
|
|
|
redactedObject[attribute] = valueMap[currentValue]; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} |
|
|
// If the attribute is not present on the current object,
|
|
|
} |
|
|
// check if it exists on any nested objects
|
|
|
|
|
|
for (const property in redactedObject) { |
|
|
// Process nested objects and arrays efficiently
|
|
|
if (isArray(redactedObject[property])) { |
|
|
const propertyNames = Object.keys(redactedObject); |
|
|
redactedObject[property] = redactedObject[property].map( |
|
|
for (const property of propertyNames) { |
|
|
(currentObject) => { |
|
|
const redactedField = redactedObject[property]; |
|
|
return redactAttributes({ |
|
|
|
|
|
|
|
|
if (isArray(redactedField)) { |
|
|
|
|
|
// Process arrays in-place to avoid creating new arrays
|
|
|
|
|
|
for (let innerField of redactedField) { |
|
|
|
|
|
if (isObject(innerField)) { |
|
|
|
|
|
innerField = redactAttributes({ |
|
|
options, |
|
|
options, |
|
|
isFirstRun: false, |
|
|
isFirstRun: false, |
|
|
object: currentObject |
|
|
object: innerField |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
); |
|
|
} |
|
|
} else if ( |
|
|
} else if (isObject(redactedField) && !(redactedField instanceof Big)) { |
|
|
isObject(redactedObject[property]) && |
|
|
// Recursively process nested objects
|
|
|
!(redactedObject[property] instanceof Big) |
|
|
|
|
|
) { |
|
|
|
|
|
// Recursively call the function on the nested object
|
|
|
|
|
|
redactedObject[property] = redactAttributes({ |
|
|
redactedObject[property] = redactAttributes({ |
|
|
options, |
|
|
options, |
|
|
isFirstRun: false, |
|
|
isFirstRun: false, |
|
|
object: redactedObject[property] |
|
|
object: redactedField |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return redactedObject; |
|
|
return redactedObject; |
|
|
} |
|
|
} |
|
|