source: frontend/node_modules/jsonpath/lib/index.js@ ae6cd79

Last change on this file since ae6cd79 was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.8 KB
Line 
1var assert = require('assert');
2var dict = require('./dict');
3var Parser = require('./parser');
4var Handlers = require('./handlers');
5
6var JSONPath = function() {
7 this.initialize.apply(this, arguments);
8};
9
10JSONPath.prototype.initialize = function() {
11 this.parser = new Parser();
12 this.handlers = new Handlers();
13};
14
15JSONPath.prototype.parse = function(string) {
16 assert.ok(_is_string(string), "we need a path");
17 return this.parser.parse(string);
18};
19
20JSONPath.prototype.parent = function(obj, string) {
21
22 assert.ok(obj instanceof Object, "obj needs to be an object");
23 assert.ok(string, "we need a path");
24
25 var node = this.nodes(obj, string)[0];
26 if (node) this._assert_safe_path_keys(node.path);
27 var key = node.path.pop(); /* jshint unused:false */
28 return this.value(obj, node.path);
29}
30
31JSONPath.prototype.apply = function(obj, string, fn) {
32
33 assert.ok(obj instanceof Object, "obj needs to be an object");
34 assert.ok(string, "we need a path");
35 assert.equal(typeof fn, "function", "fn needs to be function")
36
37 var nodes = this.nodes(obj, string).sort(function(a, b) {
38 // sort nodes so we apply from the bottom up
39 return b.path.length - a.path.length;
40 });
41
42 nodes.forEach(function(node) {
43 this._assert_safe_path_keys(node.path);
44 var key = node.path.pop();
45 var parent = this.value(obj, this.stringify(node.path));
46 var val = node.value = fn.call(obj, parent[key]);
47 parent[key] = val;
48 }, this);
49
50 return nodes;
51}
52
53JSONPath.prototype.value = function(obj, path, value) {
54
55 assert.ok(obj instanceof Object, "obj needs to be an object");
56 assert.ok(path, "we need a path");
57
58 if (arguments.length >= 3) {
59 var node = this.nodes(obj, path).shift();
60 if (!node) return this._vivify(obj, path, value);
61 this._assert_safe_path_keys(node.path);
62 var key = node.path.slice(-1).shift();
63 var parent = this.parent(obj, this.stringify(node.path));
64 parent[key] = value;
65 }
66 return this.query(obj, this.stringify(path), 1).shift();
67}
68
69JSONPath.prototype._vivify = function(obj, string, value) {
70
71 var self = this;
72
73 assert.ok(obj instanceof Object, "obj needs to be an object");
74 assert.ok(string, "we need a path");
75
76 var path = this.parser.parse(string)
77 .map(function(component) { return component.expression.value });
78
79 this._assert_safe_path_keys(path);
80
81 var setValue = function(path, value) {
82 var key = path.pop();
83 var node = self.value(obj, path);
84 if (!node) {
85 setValue(path.concat(), typeof key === 'string' ? {} : []);
86 node = self.value(obj, path);
87 }
88 self._assert_safe_key(key);
89 node[key] = value;
90 }
91 setValue(path, value);
92 return this.query(obj, string)[0];
93}
94
95JSONPath.prototype.query = function(obj, string, count) {
96
97 assert.ok(obj instanceof Object, "obj needs to be an object");
98 assert.ok(_is_string(string), "we need a path");
99
100 var results = this.nodes(obj, string, count)
101 .map(function(r) { return r.value });
102
103 return results;
104};
105
106JSONPath.prototype.paths = function(obj, string, count) {
107
108 assert.ok(obj instanceof Object, "obj needs to be an object");
109 assert.ok(string, "we need a path");
110
111 var results = this.nodes(obj, string, count)
112 .map(function(r) { return r.path });
113
114 return results;
115};
116
117JSONPath.prototype.nodes = function(obj, string, count) {
118
119 assert.ok(obj instanceof Object, "obj needs to be an object");
120 assert.ok(string, "we need a path");
121
122 if (count === 0) return [];
123
124 var path = this.parser.parse(string);
125 this._assert_safe_components(path);
126 var handlers = this.handlers;
127
128 var partials = [ { path: ['$'], value: obj } ];
129 var matches = [];
130
131 if (path.length && path[0].expression.type == 'root') path.shift();
132
133 if (!path.length) return partials;
134
135 path.forEach(function(component, index) {
136
137 if (matches.length >= count) return;
138 var handler = handlers.resolve(component);
139 var _partials = [];
140
141 partials.forEach(function(p) {
142
143 if (matches.length >= count) return;
144 var results = handler(component, p, count);
145
146 if (index == path.length - 1) {
147 // if we're through the components we're done
148 matches = matches.concat(results || []);
149 } else {
150 // otherwise accumulate and carry on through
151 _partials = _partials.concat(results || []);
152 }
153 });
154
155 partials = _partials;
156
157 });
158
159 return count ? matches.slice(0, count) : matches;
160};
161
162JSONPath.prototype.stringify = function(path) {
163
164 assert.ok(path, "we need a path");
165
166 var string = '$';
167
168 var templates = {
169 'descendant-member': '..{{value}}',
170 'child-member': '.{{value}}',
171 'descendant-subscript': '..[{{value}}]',
172 'child-subscript': '[{{value}}]'
173 };
174
175 path = this._normalize(path);
176
177 path.forEach(function(component) {
178
179 if (component.expression.type == 'root') return;
180
181 var key = [component.scope, component.operation].join('-');
182 var template = templates[key];
183 var value;
184
185 if (component.expression.type == 'string_literal') {
186 value = JSON.stringify(component.expression.value)
187 } else {
188 value = component.expression.value;
189 }
190
191 if (!template) throw new Error("couldn't find template " + key);
192
193 string += template.replace(/{{value}}/, value);
194 });
195
196 return string;
197}
198
199JSONPath.prototype._normalize = function(path) {
200
201 assert.ok(path, "we need a path");
202
203 if (typeof path == "string") {
204
205 return this.parser.parse(path);
206
207 } else if (Array.isArray(path) && typeof path[0] == "string") {
208
209 var _path = [ { expression: { type: "root", value: "$" } } ];
210
211 path.forEach(function(component, index) {
212
213 if (component == '$' && index === 0) return;
214
215 if (typeof component == "string" && component.match("^" + dict.identifier + "$")) {
216 this._assert_safe_key(component);
217
218 _path.push({
219 operation: 'member',
220 scope: 'child',
221 expression: { value: component, type: 'identifier' }
222 });
223
224 } else {
225
226 var type = typeof component == "number" ?
227 'numeric_literal' : 'string_literal';
228
229 if (type === 'string_literal') this._assert_safe_key(component);
230
231 _path.push({
232 operation: 'subscript',
233 scope: 'child',
234 expression: { value: component, type: type }
235 });
236 }
237 }, this);
238
239 return _path;
240
241 } else if (Array.isArray(path) && typeof path[0] == "object") {
242
243 return path
244 }
245
246 throw new Error("couldn't understand path " + path);
247}
248
249JSONPath.prototype._assert_safe_key = function(key) {
250 if (_is_unsafe_key(key)) {
251 throw new Error("Unsafe key in JSONPath: " + key);
252 }
253}
254
255JSONPath.prototype._assert_safe_path_keys = function(path) {
256 if (!Array.isArray(path)) return;
257 path.forEach(function(key) {
258 if (key === '$') return;
259 if (typeof key === 'string') this._assert_safe_key(key);
260 }, this);
261}
262
263JSONPath.prototype._assert_safe_components = function(components) {
264 var self = this;
265 if (!Array.isArray(components)) return;
266
267 var checkExpression = function(expression) {
268 if (!expression) return;
269 if (expression.type === 'identifier' || expression.type === 'string_literal') {
270 self._assert_safe_key(expression.value);
271 return;
272 }
273
274 if (expression.type === 'union' && Array.isArray(expression.value)) {
275 expression.value.forEach(function(component) {
276 if (component && component.expression) {
277 checkExpression(component.expression);
278 }
279 });
280 }
281 };
282
283 components.forEach(function(component) {
284 if (component && component.expression) {
285 checkExpression(component.expression);
286 }
287 });
288}
289
290function _is_string(obj) {
291 return Object.prototype.toString.call(obj) == '[object String]';
292}
293
294function _is_unsafe_key(key) {
295 return key === '__proto__' || key === 'prototype' || key === 'constructor';
296}
297
298JSONPath.Handlers = Handlers;
299JSONPath.Parser = Parser;
300
301var instance = new JSONPath;
302instance.JSONPath = JSONPath;
303
304module.exports = instance;
Note: See TracBrowser for help on using the repository browser.