Skip to content

Instantly share code, notes, and snippets.

@lac5
Created April 29, 2019 20:55
Show Gist options
  • Save lac5/d8180ac77f978cf3c894914a198a4afa to your computer and use it in GitHub Desktop.
Save lac5/d8180ac77f978cf3c894914a198a4afa to your computer and use it in GitHub Desktop.
/** @typedef {string|boolean|number|Function|void} nonObject */
/**
* @typedef {[string, nonObject]} DenestedRow
* @property {string} path The dot/bracket notation of the variable. (Example: `a.b[0].c["d-e"].f`). Same as `this[0]`.
* @property {object} parent The object that holds this variable.
* @property {string} key The key to this variable. (`this.parent[this.key] === this[1]`)
*/
/**
* Concatenates an object and nested objects into a single key-value array.
* Useful for turning an object into a table.
* @param {object} object
* @return {DenestedRow[]}
*/
export default function denest(object) {
/** @type {DenestedRow[]} */
const table = [];
/** @type {string[]} */
const path = [];
/** @type {[object, string[], number][]} */
const state = [[
object,
Object.keys(object),
0
]];
const goodKey = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
loop: do {
const object = state[0][0];
const length = state[0][1].length;
for (let i = state[0][2]; i < length; i++) {
const k = state[0][1][i];
if (object[k] && typeof object[k] === 'object') {
state[0][2] = i + 1;
path.push(
goodKey.test(k)
? (path.length > 0 ? '.' : '') + k
: '['+ (isNaN(k) ? JSON.stringify(k) : k) +']'
);
state.unshift([
object[k],
Object.keys(object[k]),
0
]);
continue loop;
} else {
/** @type {DenestedRow} */
const row = [
path.concat(
goodKey.test(k)
? (path.length > 0 ? '.' : '') + k
: '['+ (isNaN(k) ? JSON.stringify(k) : k) +']'
).join(''),
object[k]
];
row.path = row[0];
row.parent = object;
row.key = k;
table.push(row);
}
}
path.pop();
state.shift();
} while (state.length > 0);
return table;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment