/
dataObject.js
227 lines (199 loc) · 6.54 KB
/
dataObject.js
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
'use strict';
/**
* Dependencies
*/
// True if Object
function _isObject(value) {
return typeof(value) === 'object' && value !== null;
}
// True if Array
function _isArray(value) {
return Array.isArray(value);
}
/// True if type is string
function _isString(value) {
return typeof(value) === 'string';
}
// True if undefined
function _isUndefined(value) {
return typeof(value) === 'undefined';
}
// True if Number
function _isNumber(value) {
return typeof(value) === 'number';
}
// True if Boolean
function _isBoolean(value) {
return typeof(value) === 'boolean';
}
// True if Date object
function _isDate(value) {
return value instanceof Date;
}
function SocialDataObjectParser($data){
this._data = $data || {};
}
/**
* Given a dot deliminated string set will create an object
* based on the structure of the string with the desired value
*
* @param {[String} $path path indicating where value should be placed
* @param {Mixed} $value the value desired to be set at the location determined by path
*/
SocialDataObjectParser.prototype.set = function($path, $value) {
if(!$path || $path==='') return void 0;
var _self = this;
var re = /[\$\w-|]+|\[\]|([^\[[\w]\]]|["'](.*?)['"])/g;
// parse $path on dots, and brackets
var pathList = $path.match(re);
var parent = this._data;
var parentKey;
var grandParent = null;
var grandParentKey = null;
var addObj = function($obj, $key, $data) {
if($key === '[]') {
$obj.push($data);
} else {
$obj[$key] = $data;
}
};
while(pathList.length > 0) {
parentKey = pathList.shift().replace(/["']/g, '');
// Number, treat it as an array
if (!isNaN(+parentKey) || parentKey === "[]") {
if(!_isArray(parent) /* prevent overwritting */ ) {
parent = [];
addObj(grandParent, grandParentKey, parent);
}
// String, treat it as a key
} else if (_isString(parentKey)) {
if(!_isObject(parent)) {
parent = {};
addObj(grandParent, grandParentKey, parent);
}
}
// Next
grandParent = parent;
grandParentKey = parentKey;
parent = parent[parentKey];
}
addObj(grandParent, grandParentKey, $value);
return this;
};
/**
* Returns the value defined by the path passed in
*
* @param {String} $path string leading to a desired value
* @return {Mixed} a value in an object
*/
SocialDataObjectParser.prototype.get = function($path) {
var data = this._data;
var regex = /[\$\w-|]+|\[\]|([^\[[\w]\]]|["'](.*?)['"])/g;
//check if $path is truthy
if (!$path) return void 0;
//parse $path on dots and brackets
var paths = $path.match(regex);
//step through data object until all keys in path have been processed
while (data !== null && paths.length > 0) {
if(data.propertyIsEnumerable(paths[0].replace(/"/g, ''))){
data = data[paths.shift().replace(/"/g, '')];
}
else{
return undefined;
}
}
return data;
};
SocialDataObjectParser.prototype.data = function($data) {
if(!_isUndefined($data)) {
this._data = $data;
return this;
}
return this._data;
};
/**
* "Transposes" data; receives flat data and returns structured
*
* @param {Object} $data Structured object
* @return {SocialDataObjectParser} An instance of a SocialDataObjectParser
*/
SocialDataObjectParser.transpose = function($flat) {
var parser = (new SocialDataObjectParser());
for(var n in $flat) {
if($flat[n]!==undefined) {
parser.set(n, $flat[n]);
}
}
return parser;
};
/**
* "Untransposes" data object; opposite of transpose
*
* @param {Mixed} $structured A Object or a SocialDataObjectParser
* @return {Object} Flat object
*/
SocialDataObjectParser.untranspose = function($structured) {
//check to see if $structured is passed
$structured = $structured || {};
//handles if an object or a SocialDataObjectParser is passed in
var structuredData = $structured._data || $structured;
var traverse = function($data, $isIndex) {
var result = [];
var createMapHandler = function($name, $data) {
return function($item, $i) {
var name = $name;
//check if $name is a key of form "hello.world"
if((/\./).test($name)) name = '["'+name+'"]';
//add name to $item.key
$item.key.unshift(name+".");
//return $item.key with updated key
return {
key: $item.key,
data: $item.data
};
};
};
for(var name in $data) {
var modifiedName;
// check if current name is an arrays index
if($isIndex) modifiedName = "["+name+"]";
else modifiedName = name;
// check if current name is linked to a value
if(_isString($data[name]) || _isNumber($data[name]) || $data[name]===null || _isBoolean($data[name]) || _isDate($data[name])) {
if((/\./).test(name)) modifiedName = '["'+name+'"]';
result.push({
key: [modifiedName],
data: $data[name]
});
}
// check if current name is an array
else if(_isArray($data[name])) {
// tell traverse next name is an array's index
var subArray = traverse($data[name],true);
result = result.concat(subArray.map(createMapHandler(modifiedName, $data)));
}
//check if current name is an object
else if(_isObject($data[name])) {
var subObject = traverse($data[name],false);
result = result.concat(subObject.map(createMapHandler(modifiedName, $data)));
}
}
return result;
};
var flatArray = traverse(structuredData,false);
var flatObj = {};
flatArray.every(function($item) {
//check for any dots followed by brackets and remove the dots
for(var i = 0;i<$item.key.length-1;i++){
var name = $item.key[i];
var nextName = $item.key[i+1];
if((/^\[/).test(nextName)){
$item.key[i] = name.replace(/\.$/,"");
}
}
//join all the keys in flatArray to form one key
flatObj[$item.key.join("")] = $item.data;
return true;
});
return flatObj;
};