source: trip-planner-front/node_modules/jsonc-parser/lib/umd/impl/parser.js@ fa375fe

Last change on this file since fa375fe was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

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