/
underscore.kv.co
97 lines (88 loc) · 3.34 KB
/
underscore.kv.co
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
_ = require 'underscore'
_nest = require 'underscore.nested'
/**
* @namespace Functions for key-value pairs serialization (aka, www-form-encoding) of objects
*/
_kv = do
/**
* Transforms an object to a string of URL-encoded KV-pairs (aka "www-form-encoding").
*
* Note:
* - All values end up as a string, implying all type information is lost.
* - Both keys and values are URL-encoded once.
*
* @param {Object} object The object to be serialized.
* @param {String} [item_delim='&'] String delimiting each pair.
* @param {String} [kv_delim='='] String delimiting key from value.
* @returns {String} Serialized and encoded KV-pairs.
*/
toKV: (object, item_delim='&', kv_delim='=') ->
_.reduce do
object
(acc, v, k) ->
acc.push encodeURIComponent(k) + kv_delim + encodeURIComponent(v) if k
acc
[]
.join item_delim
/**
* Restores an object from a string of URL-encoded KV-pairs (aka "www-form-encoding").
*
* Note:
* - All resulting values will be strings as all type information is lost.
* - Both keys and values will be URL-decoded once.
*
* @param {String} string String of serialized KV-pairs.
* @param {String} [item_delim='&'] String delimiting each pair.
* @param {String} [kv_delim='='] String delimiting key from value.
* @returns {Object} Deserialized object containing the KV-pairs.
*/
fromKV: (string, item_delim='&', kv_delim='=') ->
_.reduce do
string.split item_delim
(acc, pair) ->
idx = pair.indexOf kv_delim
if idx is not -1
[k, v] = [pair.slice(0, idx), pair.slice(idx+1)]
else
[k, v] = [pair, '']
acc[ decodeURIComponent k ] = decodeURIComponent v if k
acc
{}
/**
* Copies and flattens a tree of sub-objects into namespaced keys on the target object, such
* that `{ "foo":{ "bar":1 } }` becomes `{ "foo.bar":1 }`.
*
* @param {Object} source Object to collapse.
* @param {Object} [target={}] Target of the collapsed keys.
* @param {String} [prefix=''] Prefix applied to copied keys.
* @returns {Object} The collapsed object.
*/
collapseObject: (source, target={}, prefix='') ->
prefix += '.' if prefix
_.each source, (v, k) ->
if _nest.isPlainObject v
_kv.collapseObject v, parent, prefix+k
else
parent[prefix+k] = v
parent
/**
* Inverse of `_.collapseObject()` -- copies all keys onto the target object, expanding any
* dot-namespaced keys found, such that `{ "foo.bar":1 }` becomes `{ "foo":{ "bar":1 }}`.
*
* @param {Object} source Collapsed source object.
* @param {Object} [target={}] Target of the uncollapsed keys.
* @returns {Object} The uncollapsed object -- either `target` or a new object.
*/
uncollapseObject: (source, target={}) ->
_.reduce do
source
(acc, v, k) ->
_nest.setNested acc, k, v, {+ensure}
acc
target
if module?
module.exports = _kv
else if exports?
exports import _kv
else if window?
window.UnderscoreKV = _kv