UNPKG

sendero

Version:
160 lines (143 loc) 4.72 kB
function get(data, path, options) { if (!options) options = {}; const lstrip = (str, chr) => (str[0] === chr ? str.substring(1) : str); const stringify = it => (typeof it === "object" ? JSON.stringify(it) : "" + it); if (typeof path === "string") { let seps = [".", "__"]; // default if (typeof options.sep === "string") { seps = [options.sep]; } else if (Array.isArray(options.sep)) { seps = options.sep; } if (seps.length > 1) { return seps.reduce((acc, sep) => { const split = lstrip(path, sep).split(sep); const subresults = get(data, split, options); return subresults.length > acc.length ? subresults : acc; }, []); } else if (seps.length === 1) { const sep = seps[0]; path = lstrip(path, sep).split(sep); } } else { path = Array.prototype.slice.call(path); // clone if (path[0] === "") path.shift(); // remove initial blank string } let previous = [data]; while (path.length > 0) { const active = []; const key = path.shift(); previous.forEach(obj => { if (typeof obj === "object" && obj !== null) { if (Array.isArray(obj)) { obj.forEach(item => { if (key in item) { const value = item[key]; if (Array.isArray(value)) { value.forEach(subvalue => { active.push(subvalue); }); } else { active.push(value); } } }); } else { if (key in obj) { const value = obj[key]; if (Array.isArray(value)) { value.forEach(subvalue => { active.push(subvalue); }); } else { active.push(value); } } } } }); previous = active; } let results = previous; if (options.clean) { results = results.filter(it => it !== null && it !== undefined && it !== ""); } if (options.unique || options.sort || options.stringify) { results = results.map(it => [it, stringify(it)]); // sort results by string version if (options.sort) { results = results.sort((a, b) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)); } if (options.unique) { results = results.filter( ([_, str], i) => results.slice(0, i).filter(([_, substr]) => str === substr).length === 0 ); } results = results.map(([it, str]) => (options.stringify ? str : it)); } return results; } // compute paths for an object function findPaths(obj, { debug = false, prev = "", sep = "." } = {}) { let paths = new Set(); if (Array.isArray(obj)) { obj.forEach(item => { const found = findPaths(item, { prev: prev ? prev + sep : "", sep }); if (found.size === 0) { if (Array.isArray(item) && item.length > 0) { if (prev) { paths.add(prev); } } } else { for (let el of found) { paths.add(el); } } }); } else if (typeof obj === "object") { for (let key in obj) { const value = obj[key]; if (Array.isArray(value)) { value.forEach(item => { if (Array.isArray(item)) { if (item.length > 0) { const found = findPaths(item, { prev: (prev ? prev + sep : "") + key, sep }); if (found.size === 0) { paths.add((prev ? prev + sep : "") + key); } else { for (let el of found) { paths.add(el); } } } } else if (typeof item === "object") { for (let el of findPaths(item, { prev: (prev ? prev + sep : "") + key, sep })) { paths.add(el); } } else { paths.add((prev ? prev + sep : "") + key); } }); } else if (typeof value === "object") { for (let el of findPaths(value, { prev: (prev ? prev + sep : "") + key, sep })) { paths.add(el); } } else { paths.add((prev ? prev + sep : "") + key); } } } if (debug) console.log("[sendero] paths for", obj, "is", paths); return paths; } function listPaths(data, { debug = false, prev = "", sep = "." } = {}) { return Array.from(findPaths(data, { debug, prev, sep })).sort(); } if (typeof define === "function" && define.amd) define(function () { return { get, listPaths }; }); if (typeof module === "object") module.exports = { get, listPaths }; if (typeof window === "object") window.sendero = { get, listPaths }; if (typeof self === "object") self.sendero = { get, listPaths };