fast-redact
Advanced tools
Comparing version 3.2.0 to 3.3.0
@@ -44,24 +44,13 @@ 'use strict' | ||
function nestedRestore (arr) { | ||
const length = arr.length | ||
for (var i = 0; i < length; i++) { | ||
const { key, target, value, level } = arr[i] | ||
if (level === 0 || level === 1) { | ||
if (has(target, key)) { | ||
target[key] = value | ||
} | ||
/* istanbul ignore else */ | ||
if (typeof target === 'object') { | ||
const targetKeys = Object.keys(target) | ||
for (var j = 0; j < targetKeys.length; j++) { | ||
const tKey = targetKeys[j] | ||
const subTarget = target[tKey] | ||
if (has(subTarget, key)) { | ||
subTarget[key] = value | ||
} | ||
} | ||
} | ||
} else { | ||
restoreNthLevel(key, target, value, level) | ||
/** | ||
* @param {RestoreInstruction[]} instructions a set of instructions for restoring values to objects | ||
*/ | ||
function nestedRestore (instructions) { | ||
for (let i = 0; i < instructions.length; i++) { | ||
const { target, path, value } = instructions[i] | ||
let current = target | ||
for (let i = path.length - 1; i > 0; i--) { | ||
current = current[path[i]] | ||
} | ||
current[path[0]] = value | ||
} | ||
@@ -77,8 +66,3 @@ } | ||
const key = keys[i] | ||
const { value, parent, exists, level } = | ||
specialSet(target, key, path, ns, censor, isCensorFct, censorFctTakesPath) | ||
if (exists === true && parent !== null) { | ||
store.push({ key: ns[ns.length - 1], target: parent, value, level }) | ||
} | ||
specialSet(store, target, key, path, ns, censor, isCensorFct, censorFctTakesPath) | ||
} | ||
@@ -94,3 +78,3 @@ return store | ||
function specialSet (o, k, path, afterPath, censor, isCensorFct, censorFctTakesPath) { | ||
function specialSet (store, o, k, path, afterPath, censor, isCensorFct, censorFctTakesPath) { | ||
const afterPathLen = afterPath.length | ||
@@ -104,3 +88,2 @@ const lastPathIndex = afterPathLen - 1 | ||
var oov = null | ||
var exists = true | ||
var wc = null | ||
@@ -111,9 +94,12 @@ var kIsWc | ||
var level = 0 | ||
// need to track depth of the `redactPath` tree | ||
var depth = 0 | ||
var redactPathCurrent = tree() | ||
ov = n = o[k] | ||
if (typeof n !== 'object') return { value: null, parent: null, exists } | ||
if (typeof n !== 'object') return | ||
while (n != null && ++i < afterPathLen) { | ||
depth += 1 | ||
k = afterPath[i] | ||
oov = ov | ||
if (k !== '*' && !wc && !(typeof n === 'object' && k in n)) { | ||
exists = false | ||
break | ||
@@ -137,4 +123,5 @@ } | ||
if (consecutive) { | ||
redactPathCurrent = node(redactPathCurrent, wck, depth) | ||
level = i | ||
ov = iterateNthLevel(wcov, level - 1, k, path, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i, lastPathIndex, exists) | ||
ov = iterateNthLevel(wcov, level - 1, k, path, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i, lastPathIndex, redactPathCurrent, store, o[originalKey], depth + 1) | ||
} else { | ||
@@ -153,8 +140,15 @@ if (kIsWc || (typeof wcov === 'object' && wcov !== null && k in wcov)) { | ||
if (kIsWc) { | ||
const rv = restoreInstr(node(redactPathCurrent, wck, depth), ov, o[originalKey]) | ||
store.push(rv) | ||
n[wck] = nv | ||
} else { | ||
if (wcov[k] === nv) { | ||
exists = false | ||
// pass | ||
} else if ((nv === undefined && censor !== undefined) || (has(wcov, k) && nv === ov)) { | ||
redactPathCurrent = node(redactPathCurrent, wck, depth) | ||
} else { | ||
wcov[k] = (nv === undefined && censor !== undefined) || (has(wcov, k) && nv === ov) ? wcov[k] : nv | ||
redactPathCurrent = node(redactPathCurrent, wck, depth) | ||
const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, o[originalKey]) | ||
store.push(rv) | ||
wcov[k] = nv | ||
} | ||
@@ -168,2 +162,3 @@ } | ||
ov = n[k] | ||
redactPathCurrent = node(redactPathCurrent, k, depth) | ||
nv = (i !== lastPathIndex) | ||
@@ -174,3 +169,9 @@ ? ov | ||
: censor) | ||
n[k] = (has(n, k) && nv === ov) || (nv === undefined && censor !== undefined) ? n[k] : nv | ||
if ((has(n, k) && nv === ov) || (nv === undefined && censor !== undefined)) { | ||
// pass | ||
} else { | ||
const rv = restoreInstr(redactPathCurrent, ov, o[originalKey]) | ||
store.push(rv) | ||
n[k] = nv | ||
} | ||
n = n[k] | ||
@@ -181,7 +182,5 @@ } | ||
if (ov === oov || typeof ov === 'undefined') { | ||
exists = false | ||
// pass | ||
} | ||
} | ||
return { value: ov, parent: oov, exists, level } | ||
} | ||
@@ -199,3 +198,3 @@ | ||
function iterateNthLevel (wcov, level, k, path, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i, lastPathIndex, exists) { | ||
function iterateNthLevel (wcov, level, k, path, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i, lastPathIndex, redactPathCurrent, store, parent, depth) { | ||
if (level === 0) { | ||
@@ -214,17 +213,22 @@ if (kIsWc || (typeof wcov === 'object' && wcov !== null && k in wcov)) { | ||
if (kIsWc) { | ||
const rv = restoreInstr(redactPathCurrent, ov, parent) | ||
store.push(rv) | ||
n[wck] = nv | ||
} else { | ||
if (wcov[k] === nv) { | ||
exists = false | ||
// pass | ||
} else if ((nv === undefined && censor !== undefined) || (has(wcov, k) && nv === ov)) { | ||
// pass | ||
} else { | ||
wcov[k] = (nv === undefined && censor !== undefined) || (has(wcov, k) && nv === ov) ? wcov[k] : nv | ||
const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, parent) | ||
store.push(rv) | ||
wcov[k] = nv | ||
} | ||
} | ||
} | ||
return ov | ||
} | ||
for (const key in wcov) { | ||
if (typeof wcov[key] === 'object') { | ||
var temp = iterateNthLevel(wcov[key], level - 1, k, path, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i, lastPathIndex, exists) | ||
return temp | ||
redactPathCurrent = node(redactPathCurrent, key, depth) | ||
iterateNthLevel(wcov[key], level - 1, k, path, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i, lastPathIndex, redactPathCurrent, store, parent, depth + 1) | ||
} | ||
@@ -234,14 +238,67 @@ } | ||
function restoreNthLevel (key, target, value, level) { | ||
if (level === 0) { | ||
if (has(target, key)) { | ||
target[key] = value | ||
} | ||
return | ||
/** | ||
* @typedef {object} TreeNode | ||
* @prop {TreeNode} [parent] reference to the parent of this node in the tree, or `null` if there is no parent | ||
* @prop {string} key the key that this node represents (key here being part of the path being redacted | ||
* @prop {TreeNode[]} children the child nodes of this node | ||
* @prop {number} depth the depth of this node in the tree | ||
*/ | ||
/** | ||
* instantiate a new, empty tree | ||
* @returns {TreeNode} | ||
*/ | ||
function tree () { | ||
return { parent: null, key: null, children: [], depth: 0 } | ||
} | ||
/** | ||
* creates a new node in the tree, attaching it as a child of the provided parent node | ||
* if the specified depth matches the parent depth, adds the new node as a _sibling_ of the parent instead | ||
* @param {TreeNode} parent the parent node to add a new node to (if the parent depth matches the provided `depth` value, will instead add as a sibling of this | ||
* @param {string} key the key that the new node represents (key here being part of the path being redacted) | ||
* @param {number} depth the depth of the new node in the tree - used to determing whether to add the new node as a child or sibling of the provided `parent` node | ||
* @returns {TreeNode} a reference to the newly created node in the tree | ||
*/ | ||
function node (parent, key, depth) { | ||
if (parent.depth === depth) { | ||
return node(parent.parent, key, depth) | ||
} | ||
for (const objKey in target) { | ||
if (typeof target[objKey] === 'object') { | ||
restoreNthLevel(key, target[objKey], value, level - 1) | ||
} | ||
var child = { | ||
parent, | ||
key, | ||
depth, | ||
children: [] | ||
} | ||
parent.children.push(child) | ||
return child | ||
} | ||
/** | ||
* @typedef {object} RestoreInstruction | ||
* @prop {string[]} path a reverse-order path that can be used to find the correct insertion point to restore a `value` for the given `parent` object | ||
* @prop {*} value the value to restore | ||
* @prop {object} target the object to restore the `value` in | ||
*/ | ||
/** | ||
* create a restore instruction for the given redactPath node | ||
* generates a path in reverse order by walking up the redactPath tree | ||
* @param {TreeNode} node a tree node that should be at the bottom of the redact path (i.e. have no children) - this will be used to walk up the redact path tree to construct the path needed to restore | ||
* @param {*} value the value to restore | ||
* @param {object} target a reference to the parent object to apply the restore instruction to | ||
* @returns {RestoreInstruction} an instruction used to restore a nested value for a specific object | ||
*/ | ||
function restoreInstr (node, value, target) { | ||
let current = node | ||
const path = [] | ||
do { | ||
path.push(current.key) | ||
current = current.parent | ||
} while (current.parent != null) | ||
return { path, value, target } | ||
} |
{ | ||
"name": "fast-redact", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"description": "very fast object redaction", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -1358,1 +1358,85 @@ 'use strict' | ||
}) | ||
test('restores nested wildcard values', ({ end, is }) => { | ||
const o = { a: { b: [{ c: [ | ||
{ d: '123' }, | ||
{ d: '456' } | ||
] }] } } | ||
const censor = 'censor' | ||
const paths = ['a.b[*].c[*].d'] | ||
const redact = fastRedact({ paths, censor, serialize: false }) | ||
redact(o) | ||
is(o.a.b[0].c[0].d, censor) | ||
is(o.a.b[0].c[1].d, censor) | ||
redact.restore(o) | ||
is(o.a.b[0].c[0].d, '123') | ||
is(o.a.b[0].c[1].d, '456') | ||
end() | ||
}) | ||
test('restores multi nested wildcard values', ({ end, is }) => { | ||
const o = { | ||
a: { | ||
b1: { | ||
c1: { | ||
d1: { e: '123' }, | ||
d2: { e: '456' } | ||
}, | ||
c2: { | ||
d1: { e: '789' }, | ||
d2: { e: '012' } | ||
} | ||
}, | ||
b2: { | ||
c1: { | ||
d1: { e: '345' }, | ||
d2: { e: '678' } | ||
}, | ||
c2: { | ||
d1: { e: '901' }, | ||
d2: { e: '234' } | ||
} | ||
} | ||
} | ||
} | ||
const censor = 'censor' | ||
const paths = ['a.*.*.*.e'] | ||
const redact = fastRedact({ paths, censor, serialize: false }) | ||
redact(o) | ||
is(o.a.b1.c1.d1.e, censor) | ||
is(o.a.b1.c1.d2.e, censor) | ||
is(o.a.b1.c2.d1.e, censor) | ||
is(o.a.b1.c2.d2.e, censor) | ||
is(o.a.b2.c1.d1.e, censor) | ||
is(o.a.b2.c1.d2.e, censor) | ||
is(o.a.b2.c2.d1.e, censor) | ||
is(o.a.b2.c2.d2.e, censor) | ||
redact.restore(o) | ||
is(o.a.b1.c1.d1.e, '123') | ||
is(o.a.b1.c1.d2.e, '456') | ||
is(o.a.b1.c2.d1.e, '789') | ||
is(o.a.b1.c2.d2.e, '012') | ||
is(o.a.b2.c1.d1.e, '345') | ||
is(o.a.b2.c1.d2.e, '678') | ||
is(o.a.b2.c2.d1.e, '901') | ||
is(o.a.b2.c2.d2.e, '234') | ||
end() | ||
}) | ||
test('redact multi trailing wildcard', ({ end, is }) => { | ||
const o = { a: { b: { c: 'value' } } } | ||
const censor = 'censor' | ||
const paths = ['a.*.*'] | ||
const redact = fastRedact({ paths, censor, serialize: false }) | ||
redact(o) | ||
is(o.a.b.c, censor) | ||
redact.restore(o) | ||
is(o.a.b.c, 'value') | ||
end() | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
90497
2177