parser.js 25 KB

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