UNPKG

flatten-to-key-value

Version:

Flatten JSON-like values into dot-path key/value pairs or unFlatten them back into nested objects, with support for arrays, dates, and customizable options.

124 lines (123 loc) 3.86 kB
// src/index.ts function flattenToKeyValue(input, opts = {}) { const delimiter = opts.delimiter ?? "."; const joiner = opts.joiner ?? ","; const includeNullUndefined = opts.includeNullUndefined ?? false; const dedupe = opts.dedupeArrayValues ?? false; const acc = /* @__PURE__ */ new Map(); const add = (key, val) => { if (!key) return; const list = acc.get(key); if (list) { if (!dedupe || !list.includes(val)) list.push(val); } else { acc.set(key, [val]); } }; const isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v); const isPrimitive = (v) => v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean" || typeof v === "bigint"; const toStr = (v) => { if (v === null || v === void 0) { return includeNullUndefined ? String(v) : void 0; } if (v instanceof Date) return v.toISOString(); if (isPrimitive(v)) return String(v); try { return JSON.stringify(v); } catch { return String(v); } }; const walk = (val, path) => { if (isPrimitive(val) || val instanceof Date) { const s2 = toStr(val); if (s2 !== void 0) add(path, s2); return; } if (Array.isArray(val)) { if (val.every(isPrimitive)) { for (const item of val) { const s2 = toStr(item); if (s2 !== void 0) add(path, s2); } return; } for (const item of val) { if (isPrimitive(item) || item instanceof Date) { const s2 = toStr(item); if (s2 !== void 0) add(path, s2); } else if (Array.isArray(item)) { walk(item, path); } else if (isPlainObject(item)) { for (const [k, v] of Object.entries(item)) { const next = path ? `${path}${delimiter}${k}` : k; walk(v, next); } } } return; } if (isPlainObject(val)) { for (const [k, v] of Object.entries(val)) { const next = path ? `${path}${delimiter}${k}` : k; walk(v, next); } return; } const s = toStr(val); if (s !== void 0) add(path, s); }; walk(input, ""); const entries = Array.from(acc.entries()).map(([k, arr]) => [ k, arr.join(joiner) ]); if (opts.sortKeys) entries.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0); return Object.fromEntries(entries); } function unFlattenKeyValue(input, opts = {}) { const delimiter = opts.delimiter ?? "."; const joiner = opts.joiner ?? ","; const result = {}; const setDeep = (obj, path, value) => { let curr = obj; for (let i = 0; i < path.length; i++) { const key = path[i]; if (i === path.length - 1) { curr[key] = value; } else { if (!(key in curr) || typeof curr[key] !== "object") { curr[key] = {}; } curr = curr[key]; } } }; for (const [flatKey, strVal] of Object.entries(input)) { const path = flatKey.split(delimiter); const parts = strVal.split(joiner).map((s) => s.trim()); const parsedValues = parts.map((s) => { if (s === "null") return null; if (s === "undefined") return void 0; if (s === "true") return true; if (s === "false") return false; if (!isNaN(Number(s)) && s.trim() !== "") return Number(s); const d = new Date(s); if (!isNaN(d.getTime()) && /^\d{4}-\d{2}-\d{2}T/.test(s)) { return d; } try { return JSON.parse(s); } catch { return s; } }); const value = parsedValues.length === 1 ? parsedValues[0] : parsedValues; setDeep(result, path, value); } return result; } var index_default = flattenToKeyValue; export { index_default as default, flattenToKeyValue, unFlattenKeyValue }; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map