1 | function isBuffer (obj) {
|
2 | return obj &&
|
3 | obj.constructor &&
|
4 | (typeof obj.constructor.isBuffer === 'function') &&
|
5 | obj.constructor.isBuffer(obj)
|
6 | }
|
7 |
|
8 | function keyIdentity (key) {
|
9 | return key
|
10 | }
|
11 |
|
12 | export function flatten (target, opts) {
|
13 | opts = opts || {}
|
14 |
|
15 | const delimiter = opts.delimiter || '.'
|
16 | const maxDepth = opts.maxDepth
|
17 | const transformKey = opts.transformKey || keyIdentity
|
18 | const output = {}
|
19 |
|
20 | function step (object, prev, currentDepth) {
|
21 | currentDepth = currentDepth || 1
|
22 | Object.keys(object).forEach(function (key) {
|
23 | const value = object[key]
|
24 | const isarray = opts.safe && Array.isArray(value)
|
25 | const type = Object.prototype.toString.call(value)
|
26 | const isbuffer = isBuffer(value)
|
27 | const isobject = (
|
28 | type === '[object Object]' ||
|
29 | type === '[object Array]'
|
30 | )
|
31 |
|
32 | const newKey = prev
|
33 | ? prev + delimiter + transformKey(key)
|
34 | : transformKey(key)
|
35 |
|
36 | if (!isarray && !isbuffer && isobject && Object.keys(value).length &&
|
37 | (!opts.maxDepth || currentDepth < maxDepth)) {
|
38 | return step(value, newKey, currentDepth + 1)
|
39 | }
|
40 |
|
41 | output[newKey] = value
|
42 | })
|
43 | }
|
44 |
|
45 | step(target)
|
46 |
|
47 | return output
|
48 | }
|
49 |
|
50 | export function unflatten (target, opts) {
|
51 | opts = opts || {}
|
52 |
|
53 | const delimiter = opts.delimiter || '.'
|
54 | const overwrite = opts.overwrite || false
|
55 | const transformKey = opts.transformKey || keyIdentity
|
56 | const result = {}
|
57 |
|
58 | const isbuffer = isBuffer(target)
|
59 | if (isbuffer || Object.prototype.toString.call(target) !== '[object Object]') {
|
60 | return target
|
61 | }
|
62 |
|
63 |
|
64 |
|
65 | function getkey (key) {
|
66 | const parsedKey = Number(key)
|
67 |
|
68 | return (
|
69 | isNaN(parsedKey) ||
|
70 | key.indexOf('.') !== -1 ||
|
71 | opts.object
|
72 | )
|
73 | ? key
|
74 | : parsedKey
|
75 | }
|
76 |
|
77 | function addKeys (keyPrefix, recipient, target) {
|
78 | return Object.keys(target).reduce(function (result, key) {
|
79 | result[keyPrefix + delimiter + key] = target[key]
|
80 |
|
81 | return result
|
82 | }, recipient)
|
83 | }
|
84 |
|
85 | function isEmpty (val) {
|
86 | const type = Object.prototype.toString.call(val)
|
87 | const isArray = type === '[object Array]'
|
88 | const isObject = type === '[object Object]'
|
89 |
|
90 | if (!val) {
|
91 | return true
|
92 | } else if (isArray) {
|
93 | return !val.length
|
94 | } else if (isObject) {
|
95 | return !Object.keys(val).length
|
96 | }
|
97 | }
|
98 |
|
99 | target = Object.keys(target).reduce(function (result, key) {
|
100 | const type = Object.prototype.toString.call(target[key])
|
101 | const isObject = (type === '[object Object]' || type === '[object Array]')
|
102 | if (!isObject || isEmpty(target[key])) {
|
103 | result[key] = target[key]
|
104 | return result
|
105 | } else {
|
106 | return addKeys(
|
107 | key,
|
108 | result,
|
109 | flatten(target[key], opts)
|
110 | )
|
111 | }
|
112 | }, {})
|
113 |
|
114 | Object.keys(target).forEach(function (key) {
|
115 | const split = key.split(delimiter).map(transformKey)
|
116 | let key1 = getkey(split.shift())
|
117 | let key2 = getkey(split[0])
|
118 | let recipient = result
|
119 |
|
120 | while (key2 !== undefined) {
|
121 | if (key1 === '__proto__') {
|
122 | return
|
123 | }
|
124 |
|
125 | const type = Object.prototype.toString.call(recipient[key1])
|
126 | const isobject = (
|
127 | type === '[object Object]' ||
|
128 | type === '[object Array]'
|
129 | )
|
130 |
|
131 |
|
132 | if (!overwrite && !isobject && typeof recipient[key1] !== 'undefined') {
|
133 | return
|
134 | }
|
135 |
|
136 | if ((overwrite && !isobject) || (!overwrite && recipient[key1] == null)) {
|
137 | recipient[key1] = (
|
138 | typeof key2 === 'number' &&
|
139 | !opts.object
|
140 | ? []
|
141 | : {}
|
142 | )
|
143 | }
|
144 |
|
145 | recipient = recipient[key1]
|
146 | if (split.length > 0) {
|
147 | key1 = getkey(split.shift())
|
148 | key2 = getkey(split[0])
|
149 | }
|
150 | }
|
151 |
|
152 |
|
153 | recipient[key1] = unflatten(target[key], opts)
|
154 | })
|
155 |
|
156 | return result
|
157 | }
|