UNPKG

flattener-kit

Version:

An object flatten/unflatten utility with OOP approach and transform support.

143 lines 5.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Flattener = void 0; class Flattener { payload; defaultFlattenConfig = { delimiter: '.', safe: false, safes: [], depth: Infinity, transformKey: (key) => key, }; defaultUnflattenConfig = { delimiter: '.', overwrite: false, object: false, transformKey: (key) => key, }; constructor(payload) { this.payload = payload; } flatten(config = {}) { const finalConfig = { ...this.defaultFlattenConfig, ...config }; return Flattener._flatten(this.payload, finalConfig); } unflatten(config = {}) { const finalConfig = { ...this.defaultUnflattenConfig, ...config }; return Flattener._unflatten(this.payload, finalConfig); } static _flatten(payload, config, prefix = '', step = 0) { const { delimiter, safes, safe, depth, transformKey } = config; const result = {}; if (prefix && safes.includes(prefix)) { result[transformKey(prefix)] = payload; return result; } if (safe && Array.isArray(payload)) { result[transformKey(prefix || 'array')] = payload; return result; } if (depth !== undefined && step >= depth) { result[transformKey(prefix || 'root')] = payload; return result; } if (Array.isArray(payload)) { payload.forEach((item, index) => { const arrayKey = prefix ? `${prefix}${delimiter}${index}` : `${index}`; if (typeof item === 'object' && item !== null) { Object.assign(result, Flattener._flatten(item, config, arrayKey, step + 1)); } else { result[transformKey(arrayKey)] = item; } }); return result; } if (typeof payload !== 'object' || payload === null) { if (prefix) result[transformKey(prefix)] = payload; return result; } for (const key in payload) { if (!Object.prototype.hasOwnProperty.call(payload, key)) continue; const value = payload[key]; const fullKey = prefix ? `${prefix}${delimiter}${key}` : key; if (typeof value === 'object' && value !== null) { Object.assign(result, Flattener._flatten(value, config, fullKey, step + 1)); } else { result[transformKey(fullKey)] = value; } } return result; } static _unflatten(flat, config) { const result = {}; const { delimiter, overwrite, object, transformKey } = config; // Helper function to safely get numeric key const getKey = (key) => { const parsedKey = Number(key); return isNaN(parsedKey) || key.indexOf('.') !== -1 || object ? key : parsedKey; }; // Helper function to check if value is an object const isObject = (value) => { const type = Object.prototype.toString.call(value); return type === '[object Object]' || type === '[object Array]'; }; for (const flatKey in flat) { const value = flat[flatKey]; const keys = flatKey.split(delimiter).map(transformKey); let current = result; for (let i = 0; i < keys.length; i++) { const key = getKey(keys[i]); const isLast = i === keys.length - 1; if (isLast) { // Final key - assign the value if (!overwrite && current[key] !== undefined && !isObject(current[key])) { // Don't overwrite existing non-object values unless overwrite is true continue; } current[key] = value; } else { // Intermediate key - ensure path exists const nextKey = keys[i + 1]; const nextIsNumeric = !isNaN(Number(nextKey)) && !object; if (current[key] === undefined || current[key] === null) { // Create new container current[key] = nextIsNumeric ? [] : {}; } else if (!isObject(current[key])) { // Existing non-object value if (overwrite) { current[key] = nextIsNumeric ? [] : {}; } else { // Can't continue down this path without overwriting break; } } // If it's already an object/array, continue using it current = current[key]; } } } return result; } // Optional utility methods static flatten(payload, config) { return new Flattener(payload).flatten(config); } static unflatten(flat, config) { return new Flattener(flat).unflatten(config); } } exports.Flattener = Flattener; exports.default = Flattener; //# sourceMappingURL=index.js.map