123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- module.exports = flatten
- flatten.flatten = flatten
- flatten.unflatten = unflatten
- function isBuffer (obj) {
- return obj &&
- obj.constructor &&
- (typeof obj.constructor.isBuffer === 'function') &&
- obj.constructor.isBuffer(obj)
- }
- function keyIdentity (key) {
- return key
- }
- function flatten (target, opts) {
- opts = opts || {}
- const delimiter = opts.delimiter || '.'
- const maxDepth = opts.maxDepth
- const transformKey = opts.transformKey || keyIdentity
- const output = {}
- function step (object, prev, currentDepth) {
- currentDepth = currentDepth || 1
- Object.keys(object).forEach(function (key) {
- const value = object[key]
- const isarray = opts.safe && Array.isArray(value)
- const type = Object.prototype.toString.call(value)
- const isbuffer = isBuffer(value)
- const isobject = (
- type === '[object Object]' ||
- type === '[object Array]'
- )
- const newKey = prev
- ? prev + delimiter + transformKey(key)
- : transformKey(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 || {}
- const delimiter = opts.delimiter || '.'
- const overwrite = opts.overwrite || false
- const transformKey = opts.transformKey || keyIdentity
- const result = {}
- const 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) {
- const parsedKey = Number(key)
- return (
- isNaN(parsedKey) ||
- key.indexOf('.') !== -1 ||
- opts.object
- ) ? key
- : parsedKey
- }
- function addKeys (keyPrefix, recipient, target) {
- return Object.keys(target).reduce(function (result, key) {
- result[keyPrefix + delimiter + key] = target[key]
- return result
- }, recipient)
- }
- function isEmpty (val) {
- const type = Object.prototype.toString.call(val)
- const isArray = type === '[object Array]'
- const isObject = type === '[object Object]'
- if (!val) {
- return true
- } else if (isArray) {
- return !val.length
- } else if (isObject) {
- return !Object.keys(val).length
- }
- }
- target = Object.keys(target).reduce(function (result, key) {
- const type = Object.prototype.toString.call(target[key])
- const isObject = (type === '[object Object]' || type === '[object Array]')
- if (!isObject || isEmpty(target[key])) {
- result[key] = target[key]
- return result
- } else {
- return addKeys(
- key,
- result,
- flatten(target[key], opts)
- )
- }
- }, {})
- Object.keys(target).forEach(function (key) {
- const split = key.split(delimiter).map(transformKey)
- let key1 = getkey(split.shift())
- let key2 = getkey(split[0])
- let recipient = result
- while (key2 !== undefined) {
- if (key1 === '__proto__') {
- return
- }
- const type = Object.prototype.toString.call(recipient[key1])
- const 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
- }
|