1 | (function (factory) {
|
2 | if (typeof module === "object" && typeof module.exports === "object") {
|
3 | var v = factory(require, exports);
|
4 | if (v !== undefined) module.exports = v;
|
5 | }
|
6 | else if (typeof define === "function" && define.amd) {
|
7 | define(["require", "exports", "./scanner"], factory);
|
8 | }
|
9 | })(function (require, exports) {
|
10 | |
11 |
|
12 |
|
13 |
|
14 | 'use strict';
|
15 | Object.defineProperty(exports, "__esModule", { value: true });
|
16 | var scanner_1 = require("./scanner");
|
17 | var ParseOptions;
|
18 | (function (ParseOptions) {
|
19 | ParseOptions.DEFAULT = {
|
20 | allowTrailingComma: false
|
21 | };
|
22 | })(ParseOptions || (ParseOptions = {}));
|
23 | |
24 |
|
25 |
|
26 | function getLocation(text, position) {
|
27 | var segments = [];
|
28 | var earlyReturnException = new Object();
|
29 | var previousNode = undefined;
|
30 | var previousNodeInst = {
|
31 | value: {},
|
32 | offset: 0,
|
33 | length: 0,
|
34 | type: 'object',
|
35 | parent: undefined
|
36 | };
|
37 | var isAtPropertyKey = false;
|
38 | function setPreviousNode(value, offset, length, type) {
|
39 | previousNodeInst.value = value;
|
40 | previousNodeInst.offset = offset;
|
41 | previousNodeInst.length = length;
|
42 | previousNodeInst.type = type;
|
43 | previousNodeInst.colonOffset = undefined;
|
44 | previousNode = previousNodeInst;
|
45 | }
|
46 | try {
|
47 | visit(text, {
|
48 | onObjectBegin: function (offset, length) {
|
49 | if (position <= offset) {
|
50 | throw earlyReturnException;
|
51 | }
|
52 | previousNode = undefined;
|
53 | isAtPropertyKey = position > offset;
|
54 | segments.push('');
|
55 | },
|
56 | onObjectProperty: function (name, offset, length) {
|
57 | if (position < offset) {
|
58 | throw earlyReturnException;
|
59 | }
|
60 | setPreviousNode(name, offset, length, 'property');
|
61 | segments[segments.length - 1] = name;
|
62 | if (position <= offset + length) {
|
63 | throw earlyReturnException;
|
64 | }
|
65 | },
|
66 | onObjectEnd: function (offset, length) {
|
67 | if (position <= offset) {
|
68 | throw earlyReturnException;
|
69 | }
|
70 | previousNode = undefined;
|
71 | segments.pop();
|
72 | },
|
73 | onArrayBegin: function (offset, length) {
|
74 | if (position <= offset) {
|
75 | throw earlyReturnException;
|
76 | }
|
77 | previousNode = undefined;
|
78 | segments.push(0);
|
79 | },
|
80 | onArrayEnd: function (offset, length) {
|
81 | if (position <= offset) {
|
82 | throw earlyReturnException;
|
83 | }
|
84 | previousNode = undefined;
|
85 | segments.pop();
|
86 | },
|
87 | onLiteralValue: function (value, offset, length) {
|
88 | if (position < offset) {
|
89 | throw earlyReturnException;
|
90 | }
|
91 | setPreviousNode(value, offset, length, getNodeType(value));
|
92 | if (position <= offset + length) {
|
93 | throw earlyReturnException;
|
94 | }
|
95 | },
|
96 | onSeparator: function (sep, offset, length) {
|
97 | if (position <= offset) {
|
98 | throw earlyReturnException;
|
99 | }
|
100 | if (sep === ':' && previousNode && previousNode.type === 'property') {
|
101 | previousNode.colonOffset = offset;
|
102 | isAtPropertyKey = false;
|
103 | previousNode = undefined;
|
104 | }
|
105 | else if (sep === ',') {
|
106 | var last = segments[segments.length - 1];
|
107 | if (typeof last === 'number') {
|
108 | segments[segments.length - 1] = last + 1;
|
109 | }
|
110 | else {
|
111 | isAtPropertyKey = true;
|
112 | segments[segments.length - 1] = '';
|
113 | }
|
114 | previousNode = undefined;
|
115 | }
|
116 | }
|
117 | });
|
118 | }
|
119 | catch (e) {
|
120 | if (e !== earlyReturnException) {
|
121 | throw e;
|
122 | }
|
123 | }
|
124 | return {
|
125 | path: segments,
|
126 | previousNode: previousNode,
|
127 | isAtPropertyKey: isAtPropertyKey,
|
128 | matches: function (pattern) {
|
129 | var k = 0;
|
130 | for (var i = 0; k < pattern.length && i < segments.length; i++) {
|
131 | if (pattern[k] === segments[i] || pattern[k] === '*') {
|
132 | k++;
|
133 | }
|
134 | else if (pattern[k] !== '**') {
|
135 | return false;
|
136 | }
|
137 | }
|
138 | return k === pattern.length;
|
139 | }
|
140 | };
|
141 | }
|
142 | exports.getLocation = getLocation;
|
143 | |
144 |
|
145 |
|
146 |
|
147 | function parse(text, errors, options) {
|
148 | if (errors === void 0) { errors = []; }
|
149 | if (options === void 0) { options = ParseOptions.DEFAULT; }
|
150 | var currentProperty = null;
|
151 | var currentParent = [];
|
152 | var previousParents = [];
|
153 | function onValue(value) {
|
154 | if (Array.isArray(currentParent)) {
|
155 | currentParent.push(value);
|
156 | }
|
157 | else if (currentProperty !== null) {
|
158 | currentParent[currentProperty] = value;
|
159 | }
|
160 | }
|
161 | var visitor = {
|
162 | onObjectBegin: function () {
|
163 | var object = {};
|
164 | onValue(object);
|
165 | previousParents.push(currentParent);
|
166 | currentParent = object;
|
167 | currentProperty = null;
|
168 | },
|
169 | onObjectProperty: function (name) {
|
170 | currentProperty = name;
|
171 | },
|
172 | onObjectEnd: function () {
|
173 | currentParent = previousParents.pop();
|
174 | },
|
175 | onArrayBegin: function () {
|
176 | var array = [];
|
177 | onValue(array);
|
178 | previousParents.push(currentParent);
|
179 | currentParent = array;
|
180 | currentProperty = null;
|
181 | },
|
182 | onArrayEnd: function () {
|
183 | currentParent = previousParents.pop();
|
184 | },
|
185 | onLiteralValue: onValue,
|
186 | onError: function (error, offset, length) {
|
187 | errors.push({ error: error, offset: offset, length: length });
|
188 | }
|
189 | };
|
190 | visit(text, visitor, options);
|
191 | return currentParent[0];
|
192 | }
|
193 | exports.parse = parse;
|
194 | |
195 |
|
196 |
|
197 | function parseTree(text, errors, options) {
|
198 | if (errors === void 0) { errors = []; }
|
199 | if (options === void 0) { options = ParseOptions.DEFAULT; }
|
200 | var currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: undefined };
|
201 | function ensurePropertyComplete(endOffset) {
|
202 | if (currentParent.type === 'property') {
|
203 | currentParent.length = endOffset - currentParent.offset;
|
204 | currentParent = currentParent.parent;
|
205 | }
|
206 | }
|
207 | function onValue(valueNode) {
|
208 | currentParent.children.push(valueNode);
|
209 | return valueNode;
|
210 | }
|
211 | var visitor = {
|
212 | onObjectBegin: function (offset) {
|
213 | currentParent = onValue({ type: 'object', offset: offset, length: -1, parent: currentParent, children: [] });
|
214 | },
|
215 | onObjectProperty: function (name, offset, length) {
|
216 | currentParent = onValue({ type: 'property', offset: offset, length: -1, parent: currentParent, children: [] });
|
217 | currentParent.children.push({ type: 'string', value: name, offset: offset, length: length, parent: currentParent });
|
218 | },
|
219 | onObjectEnd: function (offset, length) {
|
220 | ensurePropertyComplete(offset + length);
|
221 | currentParent.length = offset + length - currentParent.offset;
|
222 | currentParent = currentParent.parent;
|
223 | ensurePropertyComplete(offset + length);
|
224 | },
|
225 | onArrayBegin: function (offset, length) {
|
226 | currentParent = onValue({ type: 'array', offset: offset, length: -1, parent: currentParent, children: [] });
|
227 | },
|
228 | onArrayEnd: function (offset, length) {
|
229 | currentParent.length = offset + length - currentParent.offset;
|
230 | currentParent = currentParent.parent;
|
231 | ensurePropertyComplete(offset + length);
|
232 | },
|
233 | onLiteralValue: function (value, offset, length) {
|
234 | onValue({ type: getNodeType(value), offset: offset, length: length, parent: currentParent, value: value });
|
235 | ensurePropertyComplete(offset + length);
|
236 | },
|
237 | onSeparator: function (sep, offset, length) {
|
238 | if (currentParent.type === 'property') {
|
239 | if (sep === ':') {
|
240 | currentParent.colonOffset = offset;
|
241 | }
|
242 | else if (sep === ',') {
|
243 | ensurePropertyComplete(offset);
|
244 | }
|
245 | }
|
246 | },
|
247 | onError: function (error, offset, length) {
|
248 | errors.push({ error: error, offset: offset, length: length });
|
249 | }
|
250 | };
|
251 | visit(text, visitor, options);
|
252 | var result = currentParent.children[0];
|
253 | if (result) {
|
254 | delete result.parent;
|
255 | }
|
256 | return result;
|
257 | }
|
258 | exports.parseTree = parseTree;
|
259 | |
260 |
|
261 |
|
262 | function findNodeAtLocation(root, path) {
|
263 | if (!root) {
|
264 | return undefined;
|
265 | }
|
266 | var node = root;
|
267 | for (var _i = 0, path_1 = path; _i < path_1.length; _i++) {
|
268 | var segment = path_1[_i];
|
269 | if (typeof segment === 'string') {
|
270 | if (node.type !== 'object' || !Array.isArray(node.children)) {
|
271 | return undefined;
|
272 | }
|
273 | var found = false;
|
274 | for (var _a = 0, _b = node.children; _a < _b.length; _a++) {
|
275 | var propertyNode = _b[_a];
|
276 | if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment) {
|
277 | node = propertyNode.children[1];
|
278 | found = true;
|
279 | break;
|
280 | }
|
281 | }
|
282 | if (!found) {
|
283 | return undefined;
|
284 | }
|
285 | }
|
286 | else {
|
287 | var index = segment;
|
288 | if (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {
|
289 | return undefined;
|
290 | }
|
291 | node = node.children[index];
|
292 | }
|
293 | }
|
294 | return node;
|
295 | }
|
296 | exports.findNodeAtLocation = findNodeAtLocation;
|
297 | |
298 |
|
299 |
|
300 | function getNodePath(node) {
|
301 | if (!node.parent || !node.parent.children) {
|
302 | return [];
|
303 | }
|
304 | var path = getNodePath(node.parent);
|
305 | if (node.parent.type === 'property') {
|
306 | var key = node.parent.children[0].value;
|
307 | path.push(key);
|
308 | }
|
309 | else if (node.parent.type === 'array') {
|
310 | var index = node.parent.children.indexOf(node);
|
311 | if (index !== -1) {
|
312 | path.push(index);
|
313 | }
|
314 | }
|
315 | return path;
|
316 | }
|
317 | exports.getNodePath = getNodePath;
|
318 | |
319 |
|
320 |
|
321 | function getNodeValue(node) {
|
322 | switch (node.type) {
|
323 | case 'array':
|
324 | return node.children.map(getNodeValue);
|
325 | case 'object':
|
326 | var obj = Object.create(null);
|
327 | for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
|
328 | var prop = _a[_i];
|
329 | var valueNode = prop.children[1];
|
330 | if (valueNode) {
|
331 | obj[prop.children[0].value] = getNodeValue(valueNode);
|
332 | }
|
333 | }
|
334 | return obj;
|
335 | case 'null':
|
336 | case 'string':
|
337 | case 'number':
|
338 | case 'boolean':
|
339 | return node.value;
|
340 | default:
|
341 | return undefined;
|
342 | }
|
343 | }
|
344 | exports.getNodeValue = getNodeValue;
|
345 | function contains(node, offset, includeRightBound) {
|
346 | if (includeRightBound === void 0) { includeRightBound = false; }
|
347 | return (offset >= node.offset && offset < (node.offset + node.length)) || includeRightBound && (offset === (node.offset + node.length));
|
348 | }
|
349 | exports.contains = contains;
|
350 | |
351 |
|
352 |
|
353 | function findNodeAtOffset(node, offset, includeRightBound) {
|
354 | if (includeRightBound === void 0) { includeRightBound = false; }
|
355 | if (contains(node, offset, includeRightBound)) {
|
356 | var children = node.children;
|
357 | if (Array.isArray(children)) {
|
358 | for (var i = 0; i < children.length && children[i].offset <= offset; i++) {
|
359 | var item = findNodeAtOffset(children[i], offset, includeRightBound);
|
360 | if (item) {
|
361 | return item;
|
362 | }
|
363 | }
|
364 | }
|
365 | return node;
|
366 | }
|
367 | return undefined;
|
368 | }
|
369 | exports.findNodeAtOffset = findNodeAtOffset;
|
370 | |
371 |
|
372 |
|
373 | function visit(text, visitor, options) {
|
374 | if (options === void 0) { options = ParseOptions.DEFAULT; }
|
375 | var _scanner = scanner_1.createScanner(text, false);
|
376 | function toNoArgVisit(visitFunction) {
|
377 | return visitFunction ? function () { return visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()); } : function () { return true; };
|
378 | }
|
379 | function toOneArgVisit(visitFunction) {
|
380 | return visitFunction ? function (arg) { return visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()); } : function () { return true; };
|
381 | }
|
382 | var onObjectBegin = toNoArgVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisit(visitor.onObjectProperty), onObjectEnd = toNoArgVisit(visitor.onObjectEnd), onArrayBegin = toNoArgVisit(visitor.onArrayBegin), onArrayEnd = toNoArgVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisit(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
|
383 | var disallowComments = options && options.disallowComments;
|
384 | var allowTrailingComma = options && options.allowTrailingComma;
|
385 | function scanNext() {
|
386 | while (true) {
|
387 | var token = _scanner.scan();
|
388 | switch (_scanner.getTokenError()) {
|
389 | case 4 :
|
390 | handleError(14 );
|
391 | break;
|
392 | case 5 :
|
393 | handleError(15 );
|
394 | break;
|
395 | case 3 :
|
396 | handleError(13 );
|
397 | break;
|
398 | case 1 :
|
399 | if (!disallowComments) {
|
400 | handleError(11 );
|
401 | }
|
402 | break;
|
403 | case 2 :
|
404 | handleError(12 );
|
405 | break;
|
406 | case 6 :
|
407 | handleError(16 );
|
408 | break;
|
409 | }
|
410 | switch (token) {
|
411 | case 12 :
|
412 | case 13 :
|
413 | if (disallowComments) {
|
414 | handleError(10 );
|
415 | }
|
416 | else {
|
417 | onComment();
|
418 | }
|
419 | break;
|
420 | case 16 :
|
421 | handleError(1 );
|
422 | break;
|
423 | case 15 :
|
424 | case 14 :
|
425 | break;
|
426 | default:
|
427 | return token;
|
428 | }
|
429 | }
|
430 | }
|
431 | function handleError(error, skipUntilAfter, skipUntil) {
|
432 | if (skipUntilAfter === void 0) { skipUntilAfter = []; }
|
433 | if (skipUntil === void 0) { skipUntil = []; }
|
434 | onError(error);
|
435 | if (skipUntilAfter.length + skipUntil.length > 0) {
|
436 | var token = _scanner.getToken();
|
437 | while (token !== 17 ) {
|
438 | if (skipUntilAfter.indexOf(token) !== -1) {
|
439 | scanNext();
|
440 | break;
|
441 | }
|
442 | else if (skipUntil.indexOf(token) !== -1) {
|
443 | break;
|
444 | }
|
445 | token = scanNext();
|
446 | }
|
447 | }
|
448 | }
|
449 | function parseString(isValue) {
|
450 | var value = _scanner.getTokenValue();
|
451 | if (isValue) {
|
452 | onLiteralValue(value);
|
453 | }
|
454 | else {
|
455 | onObjectProperty(value);
|
456 | }
|
457 | scanNext();
|
458 | return true;
|
459 | }
|
460 | function parseLiteral() {
|
461 | switch (_scanner.getToken()) {
|
462 | case 11 :
|
463 | var value = 0;
|
464 | try {
|
465 | value = JSON.parse(_scanner.getTokenValue());
|
466 | if (typeof value !== 'number') {
|
467 | handleError(2 );
|
468 | value = 0;
|
469 | }
|
470 | }
|
471 | catch (e) {
|
472 | handleError(2 );
|
473 | }
|
474 | onLiteralValue(value);
|
475 | break;
|
476 | case 7 :
|
477 | onLiteralValue(null);
|
478 | break;
|
479 | case 8 :
|
480 | onLiteralValue(true);
|
481 | break;
|
482 | case 9 :
|
483 | onLiteralValue(false);
|
484 | break;
|
485 | default:
|
486 | return false;
|
487 | }
|
488 | scanNext();
|
489 | return true;
|
490 | }
|
491 | function parseProperty() {
|
492 | if (_scanner.getToken() !== 10 ) {
|
493 | handleError(3 , [], [2 , 5 ]);
|
494 | return false;
|
495 | }
|
496 | parseString(false);
|
497 | if (_scanner.getToken() === 6 ) {
|
498 | onSeparator(':');
|
499 | scanNext();
|
500 | if (!parseValue()) {
|
501 | handleError(4 , [], [2 , 5 ]);
|
502 | }
|
503 | }
|
504 | else {
|
505 | handleError(5 , [], [2 , 5 ]);
|
506 | }
|
507 | return true;
|
508 | }
|
509 | function parseObject() {
|
510 | onObjectBegin();
|
511 | scanNext();
|
512 | var needsComma = false;
|
513 | while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17 ) {
|
514 | if (_scanner.getToken() === 5 ) {
|
515 | if (!needsComma) {
|
516 | handleError(4 , [], []);
|
517 | }
|
518 | onSeparator(',');
|
519 | scanNext();
|
520 | if (_scanner.getToken() === 2 && allowTrailingComma) {
|
521 | break;
|
522 | }
|
523 | }
|
524 | else if (needsComma) {
|
525 | handleError(6 , [], []);
|
526 | }
|
527 | if (!parseProperty()) {
|
528 | handleError(4 , [], [2 , 5 ]);
|
529 | }
|
530 | needsComma = true;
|
531 | }
|
532 | onObjectEnd();
|
533 | if (_scanner.getToken() !== 2 ) {
|
534 | handleError(7 , [2 ], []);
|
535 | }
|
536 | else {
|
537 | scanNext();
|
538 | }
|
539 | return true;
|
540 | }
|
541 | function parseArray() {
|
542 | onArrayBegin();
|
543 | scanNext();
|
544 | var needsComma = false;
|
545 | while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17 ) {
|
546 | if (_scanner.getToken() === 5 ) {
|
547 | if (!needsComma) {
|
548 | handleError(4 , [], []);
|
549 | }
|
550 | onSeparator(',');
|
551 | scanNext();
|
552 | if (_scanner.getToken() === 4 && allowTrailingComma) {
|
553 | break;
|
554 | }
|
555 | }
|
556 | else if (needsComma) {
|
557 | handleError(6 , [], []);
|
558 | }
|
559 | if (!parseValue()) {
|
560 | handleError(4 , [], [4 , 5 ]);
|
561 | }
|
562 | needsComma = true;
|
563 | }
|
564 | onArrayEnd();
|
565 | if (_scanner.getToken() !== 4 ) {
|
566 | handleError(8 , [4 ], []);
|
567 | }
|
568 | else {
|
569 | scanNext();
|
570 | }
|
571 | return true;
|
572 | }
|
573 | function parseValue() {
|
574 | switch (_scanner.getToken()) {
|
575 | case 3 :
|
576 | return parseArray();
|
577 | case 1 :
|
578 | return parseObject();
|
579 | case 10 :
|
580 | return parseString(true);
|
581 | default:
|
582 | return parseLiteral();
|
583 | }
|
584 | }
|
585 | scanNext();
|
586 | if (_scanner.getToken() === 17 ) {
|
587 | if (options.allowEmptyContent) {
|
588 | return true;
|
589 | }
|
590 | handleError(4 , [], []);
|
591 | return false;
|
592 | }
|
593 | if (!parseValue()) {
|
594 | handleError(4 , [], []);
|
595 | return false;
|
596 | }
|
597 | if (_scanner.getToken() !== 17 ) {
|
598 | handleError(9 , [], []);
|
599 | }
|
600 | return true;
|
601 | }
|
602 | exports.visit = visit;
|
603 | |
604 |
|
605 |
|
606 |
|
607 |
|
608 | function stripComments(text, replaceCh) {
|
609 | var _scanner = scanner_1.createScanner(text), parts = [], kind, offset = 0, pos;
|
610 | do {
|
611 | pos = _scanner.getPosition();
|
612 | kind = _scanner.scan();
|
613 | switch (kind) {
|
614 | case 12 :
|
615 | case 13 :
|
616 | case 17 :
|
617 | if (offset !== pos) {
|
618 | parts.push(text.substring(offset, pos));
|
619 | }
|
620 | if (replaceCh !== undefined) {
|
621 | parts.push(_scanner.getTokenValue().replace(/[^\r\n]/g, replaceCh));
|
622 | }
|
623 | offset = _scanner.getPosition();
|
624 | break;
|
625 | }
|
626 | } while (kind !== 17 );
|
627 | return parts.join('');
|
628 | }
|
629 | exports.stripComments = stripComments;
|
630 | function getNodeType(value) {
|
631 | switch (typeof value) {
|
632 | case 'boolean': return 'boolean';
|
633 | case 'number': return 'number';
|
634 | case 'string': return 'string';
|
635 | case 'object': {
|
636 | if (!value) {
|
637 | return 'null';
|
638 | }
|
639 | else if (Array.isArray(value)) {
|
640 | return 'array';
|
641 | }
|
642 | return 'object';
|
643 | }
|
644 | default: return 'null';
|
645 | }
|
646 | }
|
647 | exports.getNodeType = getNodeType;
|
648 | });
|