massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-json / node_modules / jsonc-parser / lib / umd / impl / parser.js
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 });