This solution will work recursively and let you supply a callback that determines how to construct the accumulator. Note that it only works with objects, not a mix of nested objects and arrays.
const flatten = (tree, acc, branch = [], build) =>
Object.entries(tree).reduce(
(a, [key, val]) =>
typeof val !== 'object'
? build(a, branch, key, val)
: flatten(val, a, branch.concat(key), build),
acc
);
In your case you want the branch to be an array of nodes with the final leaf also being in the same array.
const source = {
a: {
b: {
c: 'c'
}
},
b: {
d: {
x: 'sdfdsgsf'
},
c: {
i: 'sdf',
f: {
one: {
two: {
three: 'deep'
}
}
}
}
}
};
const flatten = (tree, acc, branch = [], build) =>
Object.entries(tree).reduce(
(a, [key, val]) =>
typeof val !== 'object'
? build(a, branch, key, val)
: flatten(val, a, branch.concat(key), build),
acc
);
console.log(
flatten(source, [], [], (acc, branch, key, val) => [
...acc,
branch.concat(key, val)
])
);
output
[
[ 'a', 'b', 'c', 'c' ],
[ 'b', 'd', 'x', 'sdfdsgsf' ],
[ 'b', 'c', 'i', 'sdf' ],
[
'b', 'c',
'f', 'one',
'two', 'three',
'deep'
]
]
I need to concat the branch nodes into a string such as
{
'a.b.c.d': 'string',
'x.y.z': 'foo'
}
So I used
flatten(source, {}, [], (acc, branch, key, val) => ({
...acc,
[branch.concat(key).join('.')]: val
}))