| var isBuffer = require('is-buffer') | |
| module.exports = flatten | |
| flatten.flatten = flatten | |
| flatten.unflatten = unflatten | |
| function flatten (target, opts) { | |
| opts = opts || {} | |
| var delimiter = opts.delimiter || '.' | |
| var maxDepth = opts.maxDepth | |
| var output = {} | |
| function step (object, prev, currentDepth) { | |
| currentDepth = currentDepth || 1 | |
| Object.keys(object).forEach(function (key) { | |
| var value = object[key] | |
| var isarray = opts.safe && Array.isArray(value) | |
| var type = Object.prototype.toString.call(value) | |
| var isbuffer = isBuffer(value) | |
| var isobject = ( | |
| type === '[object Object]' || | |
| type === '[object Array]' | |
| ) | |
| var newKey = prev | |
| ? prev + delimiter + key | |
| : key | |
| if (!isarray && !isbuffer && isobject && Object.keys(value).length && | |
| (!opts.maxDepth || currentDepth < maxDepth)) { | |
| return step(value, newKey, currentDepth + 1) | |
| } | |
| output[newKey] = value | |
| }) | |
| } | |
| step(target) | |
| return output | |
| } | |
| function unflatten (target, opts) { | |
| opts = opts || {} | |
| var delimiter = opts.delimiter || '.' | |
| var overwrite = opts.overwrite || false | |
| var result = {} | |
| var isbuffer = isBuffer(target) | |
| if (isbuffer || Object.prototype.toString.call(target) !== '[object Object]') { | |
| return target | |
| } | |
| // safely ensure that the key is | |
| // an integer. | |
| function getkey (key) { | |
| var parsedKey = Number(key) | |
| return ( | |
| isNaN(parsedKey) || | |
| key.indexOf('.') !== -1 || | |
| opts.object | |
| ) ? key | |
| : parsedKey | |
| } | |
| var sortedKeys = Object.keys(target).sort(function (keyA, keyB) { | |
| return keyA.length - keyB.length | |
| }) | |
| sortedKeys.forEach(function (key) { | |
| var split = key.split(delimiter) | |
| var key1 = getkey(split.shift()) | |
| var key2 = getkey(split[0]) | |
| var recipient = result | |
| while (key2 !== undefined) { | |
| var type = Object.prototype.toString.call(recipient[key1]) | |
| var isobject = ( | |
| type === '[object Object]' || | |
| type === '[object Array]' | |
| ) | |
| // do not write over falsey, non-undefined values if overwrite is false | |
| if (!overwrite && !isobject && typeof recipient[key1] !== 'undefined') { | |
| return | |
| } | |
| if ((overwrite && !isobject) || (!overwrite && recipient[key1] == null)) { | |
| recipient[key1] = ( | |
| typeof key2 === 'number' && | |
| !opts.object ? [] : {} | |
| ) | |
| } | |
| recipient = recipient[key1] | |
| if (split.length > 0) { | |
| key1 = getkey(split.shift()) | |
| key2 = getkey(split[0]) | |
| } | |
| } | |
| // unflatten again for 'messy objects' | |
| recipient[key1] = unflatten(target[key], opts) | |
| }) | |
| return result | |
| } |