My dotfiles
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

1007 řádky
43 KiB

  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", "./format", "./edit"], 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. var format_1 = require("./format");
  17. var edit_1 = require("./edit");
  18. var ScanError;
  19. (function (ScanError) {
  20. ScanError[ScanError["None"] = 0] = "None";
  21. ScanError[ScanError["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
  22. ScanError[ScanError["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
  23. ScanError[ScanError["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
  24. ScanError[ScanError["InvalidUnicode"] = 4] = "InvalidUnicode";
  25. ScanError[ScanError["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
  26. ScanError[ScanError["InvalidCharacter"] = 6] = "InvalidCharacter";
  27. })(ScanError = exports.ScanError || (exports.ScanError = {}));
  28. var SyntaxKind;
  29. (function (SyntaxKind) {
  30. SyntaxKind[SyntaxKind["Unknown"] = 0] = "Unknown";
  31. SyntaxKind[SyntaxKind["OpenBraceToken"] = 1] = "OpenBraceToken";
  32. SyntaxKind[SyntaxKind["CloseBraceToken"] = 2] = "CloseBraceToken";
  33. SyntaxKind[SyntaxKind["OpenBracketToken"] = 3] = "OpenBracketToken";
  34. SyntaxKind[SyntaxKind["CloseBracketToken"] = 4] = "CloseBracketToken";
  35. SyntaxKind[SyntaxKind["CommaToken"] = 5] = "CommaToken";
  36. SyntaxKind[SyntaxKind["ColonToken"] = 6] = "ColonToken";
  37. SyntaxKind[SyntaxKind["NullKeyword"] = 7] = "NullKeyword";
  38. SyntaxKind[SyntaxKind["TrueKeyword"] = 8] = "TrueKeyword";
  39. SyntaxKind[SyntaxKind["FalseKeyword"] = 9] = "FalseKeyword";
  40. SyntaxKind[SyntaxKind["StringLiteral"] = 10] = "StringLiteral";
  41. SyntaxKind[SyntaxKind["NumericLiteral"] = 11] = "NumericLiteral";
  42. SyntaxKind[SyntaxKind["LineCommentTrivia"] = 12] = "LineCommentTrivia";
  43. SyntaxKind[SyntaxKind["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
  44. SyntaxKind[SyntaxKind["LineBreakTrivia"] = 14] = "LineBreakTrivia";
  45. SyntaxKind[SyntaxKind["Trivia"] = 15] = "Trivia";
  46. SyntaxKind[SyntaxKind["EOF"] = 16] = "EOF";
  47. })(SyntaxKind = exports.SyntaxKind || (exports.SyntaxKind = {}));
  48. /**
  49. * Creates a JSON scanner on the given text.
  50. * If ignoreTrivia is set, whitespaces or comments are ignored.
  51. */
  52. function createScanner(text, ignoreTrivia) {
  53. if (ignoreTrivia === void 0) { ignoreTrivia = false; }
  54. var pos = 0, len = text.length, value = '', tokenOffset = 0, token = SyntaxKind.Unknown, scanError = ScanError.None;
  55. function scanHexDigits(count, exact) {
  56. var digits = 0;
  57. var value = 0;
  58. while (digits < count || !exact) {
  59. var ch = text.charCodeAt(pos);
  60. if (ch >= 48 /* _0 */ && ch <= 57 /* _9 */) {
  61. value = value * 16 + ch - 48 /* _0 */;
  62. }
  63. else if (ch >= 65 /* A */ && ch <= 70 /* F */) {
  64. value = value * 16 + ch - 65 /* A */ + 10;
  65. }
  66. else if (ch >= 97 /* a */ && ch <= 102 /* f */) {
  67. value = value * 16 + ch - 97 /* a */ + 10;
  68. }
  69. else {
  70. break;
  71. }
  72. pos++;
  73. digits++;
  74. }
  75. if (digits < count) {
  76. value = -1;
  77. }
  78. return value;
  79. }
  80. function setPosition(newPosition) {
  81. pos = newPosition;
  82. value = '';
  83. tokenOffset = 0;
  84. token = SyntaxKind.Unknown;
  85. scanError = ScanError.None;
  86. }
  87. function scanNumber() {
  88. var start = pos;
  89. if (text.charCodeAt(pos) === 48 /* _0 */) {
  90. pos++;
  91. }
  92. else {
  93. pos++;
  94. while (pos < text.length && isDigit(text.charCodeAt(pos))) {
  95. pos++;
  96. }
  97. }
  98. if (pos < text.length && text.charCodeAt(pos) === 46 /* dot */) {
  99. pos++;
  100. if (pos < text.length && isDigit(text.charCodeAt(pos))) {
  101. pos++;
  102. while (pos < text.length && isDigit(text.charCodeAt(pos))) {
  103. pos++;
  104. }
  105. }
  106. else {
  107. scanError = ScanError.UnexpectedEndOfNumber;
  108. return text.substring(start, pos);
  109. }
  110. }
  111. var end = pos;
  112. if (pos < text.length && (text.charCodeAt(pos) === 69 /* E */ || text.charCodeAt(pos) === 101 /* e */)) {
  113. pos++;
  114. if (pos < text.length && text.charCodeAt(pos) === 43 /* plus */ || text.charCodeAt(pos) === 45 /* minus */) {
  115. pos++;
  116. }
  117. if (pos < text.length && isDigit(text.charCodeAt(pos))) {
  118. pos++;
  119. while (pos < text.length && isDigit(text.charCodeAt(pos))) {
  120. pos++;
  121. }
  122. end = pos;
  123. }
  124. else {
  125. scanError = ScanError.UnexpectedEndOfNumber;
  126. }
  127. }
  128. return text.substring(start, end);
  129. }
  130. function scanString() {
  131. var result = '', start = pos;
  132. while (true) {
  133. if (pos >= len) {
  134. result += text.substring(start, pos);
  135. scanError = ScanError.UnexpectedEndOfString;
  136. break;
  137. }
  138. var ch = text.charCodeAt(pos);
  139. if (ch === 34 /* doubleQuote */) {
  140. result += text.substring(start, pos);
  141. pos++;
  142. break;
  143. }
  144. if (ch === 92 /* backslash */) {
  145. result += text.substring(start, pos);
  146. pos++;
  147. if (pos >= len) {
  148. scanError = ScanError.UnexpectedEndOfString;
  149. break;
  150. }
  151. ch = text.charCodeAt(pos++);
  152. switch (ch) {
  153. case 34 /* doubleQuote */:
  154. result += '\"';
  155. break;
  156. case 92 /* backslash */:
  157. result += '\\';
  158. break;
  159. case 47 /* slash */:
  160. result += '/';
  161. break;
  162. case 98 /* b */:
  163. result += '\b';
  164. break;
  165. case 102 /* f */:
  166. result += '\f';
  167. break;
  168. case 110 /* n */:
  169. result += '\n';
  170. break;
  171. case 114 /* r */:
  172. result += '\r';
  173. break;
  174. case 116 /* t */:
  175. result += '\t';
  176. break;
  177. case 117 /* u */:
  178. var ch_1 = scanHexDigits(4, true);
  179. if (ch_1 >= 0) {
  180. result += String.fromCharCode(ch_1);
  181. }
  182. else {
  183. scanError = ScanError.InvalidUnicode;
  184. }
  185. break;
  186. default:
  187. scanError = ScanError.InvalidEscapeCharacter;
  188. }
  189. start = pos;
  190. continue;
  191. }
  192. if (ch >= 0 && ch <= 0x1f) {
  193. if (isLineBreak(ch)) {
  194. result += text.substring(start, pos);
  195. scanError = ScanError.UnexpectedEndOfString;
  196. break;
  197. }
  198. else {
  199. scanError = ScanError.InvalidCharacter;
  200. // mark as error but continue with string
  201. }
  202. }
  203. pos++;
  204. }
  205. return result;
  206. }
  207. function scanNext() {
  208. value = '';
  209. scanError = ScanError.None;
  210. tokenOffset = pos;
  211. if (pos >= len) {
  212. // at the end
  213. tokenOffset = len;
  214. return token = SyntaxKind.EOF;
  215. }
  216. var code = text.charCodeAt(pos);
  217. // trivia: whitespace
  218. if (isWhiteSpace(code)) {
  219. do {
  220. pos++;
  221. value += String.fromCharCode(code);
  222. code = text.charCodeAt(pos);
  223. } while (isWhiteSpace(code));
  224. return token = SyntaxKind.Trivia;
  225. }
  226. // trivia: newlines
  227. if (isLineBreak(code)) {
  228. pos++;
  229. value += String.fromCharCode(code);
  230. if (code === 13 /* carriageReturn */ && text.charCodeAt(pos) === 10 /* lineFeed */) {
  231. pos++;
  232. value += '\n';
  233. }
  234. return token = SyntaxKind.LineBreakTrivia;
  235. }
  236. switch (code) {
  237. // tokens: []{}:,
  238. case 123 /* openBrace */:
  239. pos++;
  240. return token = SyntaxKind.OpenBraceToken;
  241. case 125 /* closeBrace */:
  242. pos++;
  243. return token = SyntaxKind.CloseBraceToken;
  244. case 91 /* openBracket */:
  245. pos++;
  246. return token = SyntaxKind.OpenBracketToken;
  247. case 93 /* closeBracket */:
  248. pos++;
  249. return token = SyntaxKind.CloseBracketToken;
  250. case 58 /* colon */:
  251. pos++;
  252. return token = SyntaxKind.ColonToken;
  253. case 44 /* comma */:
  254. pos++;
  255. return token = SyntaxKind.CommaToken;
  256. // strings
  257. case 34 /* doubleQuote */:
  258. pos++;
  259. value = scanString();
  260. return token = SyntaxKind.StringLiteral;
  261. // comments
  262. case 47 /* slash */:
  263. var start = pos - 1;
  264. // Single-line comment
  265. if (text.charCodeAt(pos + 1) === 47 /* slash */) {
  266. pos += 2;
  267. while (pos < len) {
  268. if (isLineBreak(text.charCodeAt(pos))) {
  269. break;
  270. }
  271. pos++;
  272. }
  273. value = text.substring(start, pos);
  274. return token = SyntaxKind.LineCommentTrivia;
  275. }
  276. // Multi-line comment
  277. if (text.charCodeAt(pos + 1) === 42 /* asterisk */) {
  278. pos += 2;
  279. var commentClosed = false;
  280. while (pos < len) {
  281. var ch = text.charCodeAt(pos);
  282. if (ch === 42 /* asterisk */ && (pos + 1 < len) && text.charCodeAt(pos + 1) === 47 /* slash */) {
  283. pos += 2;
  284. commentClosed = true;
  285. break;
  286. }
  287. pos++;
  288. }
  289. if (!commentClosed) {
  290. pos++;
  291. scanError = ScanError.UnexpectedEndOfComment;
  292. }
  293. value = text.substring(start, pos);
  294. return token = SyntaxKind.BlockCommentTrivia;
  295. }
  296. // just a single slash
  297. value += String.fromCharCode(code);
  298. pos++;
  299. return token = SyntaxKind.Unknown;
  300. // numbers
  301. case 45 /* minus */:
  302. value += String.fromCharCode(code);
  303. pos++;
  304. if (pos === len || !isDigit(text.charCodeAt(pos))) {
  305. return token = SyntaxKind.Unknown;
  306. }
  307. // found a minus, followed by a number so
  308. // we fall through to proceed with scanning
  309. // numbers
  310. case 48 /* _0 */:
  311. case 49 /* _1 */:
  312. case 50 /* _2 */:
  313. case 51 /* _3 */:
  314. case 52 /* _4 */:
  315. case 53 /* _5 */:
  316. case 54 /* _6 */:
  317. case 55 /* _7 */:
  318. case 56 /* _8 */:
  319. case 57 /* _9 */:
  320. value += scanNumber();
  321. return token = SyntaxKind.NumericLiteral;
  322. // literals and unknown symbols
  323. default:
  324. // is a literal? Read the full word.
  325. while (pos < len && isUnknownContentCharacter(code)) {
  326. pos++;
  327. code = text.charCodeAt(pos);
  328. }
  329. if (tokenOffset !== pos) {
  330. value = text.substring(tokenOffset, pos);
  331. // keywords: true, false, null
  332. switch (value) {
  333. case 'true': return token = SyntaxKind.TrueKeyword;
  334. case 'false': return token = SyntaxKind.FalseKeyword;
  335. case 'null': return token = SyntaxKind.NullKeyword;
  336. }
  337. return token = SyntaxKind.Unknown;
  338. }
  339. // some
  340. value += String.fromCharCode(code);
  341. pos++;
  342. return token = SyntaxKind.Unknown;
  343. }
  344. }
  345. function isUnknownContentCharacter(code) {
  346. if (isWhiteSpace(code) || isLineBreak(code)) {
  347. return false;
  348. }
  349. switch (code) {
  350. case 125 /* closeBrace */:
  351. case 93 /* closeBracket */:
  352. case 123 /* openBrace */:
  353. case 91 /* openBracket */:
  354. case 34 /* doubleQuote */:
  355. case 58 /* colon */:
  356. case 44 /* comma */:
  357. return false;
  358. }
  359. return true;
  360. }
  361. function scanNextNonTrivia() {
  362. var result;
  363. do {
  364. result = scanNext();
  365. } while (result >= SyntaxKind.LineCommentTrivia && result <= SyntaxKind.Trivia);
  366. return result;
  367. }
  368. return {
  369. setPosition: setPosition,
  370. getPosition: function () { return pos; },
  371. scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
  372. getToken: function () { return token; },
  373. getTokenValue: function () { return value; },
  374. getTokenOffset: function () { return tokenOffset; },
  375. getTokenLength: function () { return pos - tokenOffset; },
  376. getTokenError: function () { return scanError; }
  377. };
  378. }
  379. exports.createScanner = createScanner;
  380. function isWhiteSpace(ch) {
  381. return ch === 32 /* space */ || ch === 9 /* tab */ || ch === 11 /* verticalTab */ || ch === 12 /* formFeed */ ||
  382. ch === 160 /* nonBreakingSpace */ || ch === 5760 /* ogham */ || ch >= 8192 /* enQuad */ && ch <= 8203 /* zeroWidthSpace */ ||
  383. ch === 8239 /* narrowNoBreakSpace */ || ch === 8287 /* mathematicalSpace */ || ch === 12288 /* ideographicSpace */ || ch === 65279 /* byteOrderMark */;
  384. }
  385. function isLineBreak(ch) {
  386. return ch === 10 /* lineFeed */ || ch === 13 /* carriageReturn */ || ch === 8232 /* lineSeparator */ || ch === 8233 /* paragraphSeparator */;
  387. }
  388. function isDigit(ch) {
  389. return ch >= 48 /* _0 */ && ch <= 57 /* _9 */;
  390. }
  391. /**
  392. * Takes JSON with JavaScript-style comments and remove
  393. * them. Optionally replaces every none-newline character
  394. * of comments with a replaceCharacter
  395. */
  396. function stripComments(text, replaceCh) {
  397. var _scanner = createScanner(text), parts = [], kind, offset = 0, pos;
  398. do {
  399. pos = _scanner.getPosition();
  400. kind = _scanner.scan();
  401. switch (kind) {
  402. case SyntaxKind.LineCommentTrivia:
  403. case SyntaxKind.BlockCommentTrivia:
  404. case SyntaxKind.EOF:
  405. if (offset !== pos) {
  406. parts.push(text.substring(offset, pos));
  407. }
  408. if (replaceCh !== void 0) {
  409. parts.push(_scanner.getTokenValue().replace(/[^\r\n]/g, replaceCh));
  410. }
  411. offset = _scanner.getPosition();
  412. break;
  413. }
  414. } while (kind !== SyntaxKind.EOF);
  415. return parts.join('');
  416. }
  417. exports.stripComments = stripComments;
  418. var ParseErrorCode;
  419. (function (ParseErrorCode) {
  420. ParseErrorCode[ParseErrorCode["InvalidSymbol"] = 0] = "InvalidSymbol";
  421. ParseErrorCode[ParseErrorCode["InvalidNumberFormat"] = 1] = "InvalidNumberFormat";
  422. ParseErrorCode[ParseErrorCode["PropertyNameExpected"] = 2] = "PropertyNameExpected";
  423. ParseErrorCode[ParseErrorCode["ValueExpected"] = 3] = "ValueExpected";
  424. ParseErrorCode[ParseErrorCode["ColonExpected"] = 4] = "ColonExpected";
  425. ParseErrorCode[ParseErrorCode["CommaExpected"] = 5] = "CommaExpected";
  426. ParseErrorCode[ParseErrorCode["CloseBraceExpected"] = 6] = "CloseBraceExpected";
  427. ParseErrorCode[ParseErrorCode["CloseBracketExpected"] = 7] = "CloseBracketExpected";
  428. ParseErrorCode[ParseErrorCode["EndOfFileExpected"] = 8] = "EndOfFileExpected";
  429. ParseErrorCode[ParseErrorCode["InvalidCommentToken"] = 9] = "InvalidCommentToken";
  430. ParseErrorCode[ParseErrorCode["UnexpectedEndOfComment"] = 10] = "UnexpectedEndOfComment";
  431. ParseErrorCode[ParseErrorCode["UnexpectedEndOfString"] = 11] = "UnexpectedEndOfString";
  432. ParseErrorCode[ParseErrorCode["UnexpectedEndOfNumber"] = 12] = "UnexpectedEndOfNumber";
  433. ParseErrorCode[ParseErrorCode["InvalidUnicode"] = 13] = "InvalidUnicode";
  434. ParseErrorCode[ParseErrorCode["InvalidEscapeCharacter"] = 14] = "InvalidEscapeCharacter";
  435. ParseErrorCode[ParseErrorCode["InvalidCharacter"] = 15] = "InvalidCharacter";
  436. })(ParseErrorCode = exports.ParseErrorCode || (exports.ParseErrorCode = {}));
  437. function getLiteralNodeType(value) {
  438. switch (typeof value) {
  439. case 'boolean': return 'boolean';
  440. case 'number': return 'number';
  441. case 'string': return 'string';
  442. default: return 'null';
  443. }
  444. }
  445. /**
  446. * 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.
  447. */
  448. function getLocation(text, position) {
  449. var segments = []; // strings or numbers
  450. var earlyReturnException = new Object();
  451. var previousNode = void 0;
  452. var previousNodeInst = {
  453. value: {},
  454. offset: 0,
  455. length: 0,
  456. type: 'object'
  457. };
  458. var isAtPropertyKey = false;
  459. function setPreviousNode(value, offset, length, type) {
  460. previousNodeInst.value = value;
  461. previousNodeInst.offset = offset;
  462. previousNodeInst.length = length;
  463. previousNodeInst.type = type;
  464. previousNodeInst.columnOffset = void 0;
  465. previousNode = previousNodeInst;
  466. }
  467. try {
  468. visit(text, {
  469. onObjectBegin: function (offset, length) {
  470. if (position <= offset) {
  471. throw earlyReturnException;
  472. }
  473. previousNode = void 0;
  474. isAtPropertyKey = position > offset;
  475. segments.push(''); // push a placeholder (will be replaced)
  476. },
  477. onObjectProperty: function (name, offset, length) {
  478. if (position < offset) {
  479. throw earlyReturnException;
  480. }
  481. setPreviousNode(name, offset, length, 'property');
  482. segments[segments.length - 1] = name;
  483. if (position <= offset + length) {
  484. throw earlyReturnException;
  485. }
  486. },
  487. onObjectEnd: function (offset, length) {
  488. if (position <= offset) {
  489. throw earlyReturnException;
  490. }
  491. previousNode = void 0;
  492. segments.pop();
  493. },
  494. onArrayBegin: function (offset, length) {
  495. if (position <= offset) {
  496. throw earlyReturnException;
  497. }
  498. previousNode = void 0;
  499. segments.push(0);
  500. },
  501. onArrayEnd: function (offset, length) {
  502. if (position <= offset) {
  503. throw earlyReturnException;
  504. }
  505. previousNode = void 0;
  506. segments.pop();
  507. },
  508. onLiteralValue: function (value, offset, length) {
  509. if (position < offset) {
  510. throw earlyReturnException;
  511. }
  512. setPreviousNode(value, offset, length, getLiteralNodeType(value));
  513. if (position <= offset + length) {
  514. throw earlyReturnException;
  515. }
  516. },
  517. onSeparator: function (sep, offset, length) {
  518. if (position <= offset) {
  519. throw earlyReturnException;
  520. }
  521. if (sep === ':' && previousNode && previousNode.type === 'property') {
  522. previousNode.columnOffset = offset;
  523. isAtPropertyKey = false;
  524. previousNode = void 0;
  525. }
  526. else if (sep === ',') {
  527. var last = segments[segments.length - 1];
  528. if (typeof last === 'number') {
  529. segments[segments.length - 1] = last + 1;
  530. }
  531. else {
  532. isAtPropertyKey = true;
  533. segments[segments.length - 1] = '';
  534. }
  535. previousNode = void 0;
  536. }
  537. }
  538. });
  539. }
  540. catch (e) {
  541. if (e !== earlyReturnException) {
  542. throw e;
  543. }
  544. }
  545. return {
  546. path: segments,
  547. previousNode: previousNode,
  548. isAtPropertyKey: isAtPropertyKey,
  549. matches: function (pattern) {
  550. var k = 0;
  551. for (var i = 0; k < pattern.length && i < segments.length; i++) {
  552. if (pattern[k] === segments[i] || pattern[k] === '*') {
  553. k++;
  554. }
  555. else if (pattern[k] !== '**') {
  556. return false;
  557. }
  558. }
  559. return k === pattern.length;
  560. }
  561. };
  562. }
  563. exports.getLocation = getLocation;
  564. /**
  565. * 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.
  566. * Therefore always check the errors list to find out if the input was valid.
  567. */
  568. function parse(text, errors, options) {
  569. if (errors === void 0) { errors = []; }
  570. var currentProperty = null;
  571. var currentParent = [];
  572. var previousParents = [];
  573. function onValue(value) {
  574. if (Array.isArray(currentParent)) {
  575. currentParent.push(value);
  576. }
  577. else if (currentProperty) {
  578. currentParent[currentProperty] = value;
  579. }
  580. }
  581. var visitor = {
  582. onObjectBegin: function () {
  583. var object = {};
  584. onValue(object);
  585. previousParents.push(currentParent);
  586. currentParent = object;
  587. currentProperty = null;
  588. },
  589. onObjectProperty: function (name) {
  590. currentProperty = name;
  591. },
  592. onObjectEnd: function () {
  593. currentParent = previousParents.pop();
  594. },
  595. onArrayBegin: function () {
  596. var array = [];
  597. onValue(array);
  598. previousParents.push(currentParent);
  599. currentParent = array;
  600. currentProperty = null;
  601. },
  602. onArrayEnd: function () {
  603. currentParent = previousParents.pop();
  604. },
  605. onLiteralValue: onValue,
  606. onError: function (error, offset, length) {
  607. errors.push({ error: error, offset: offset, length: length });
  608. }
  609. };
  610. visit(text, visitor, options);
  611. return currentParent[0];
  612. }
  613. exports.parse = parse;
  614. /**
  615. * 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.
  616. */
  617. function parseTree(text, errors, options) {
  618. if (errors === void 0) { errors = []; }
  619. var currentParent = { type: 'array', offset: -1, length: -1, children: [] }; // artificial root
  620. function ensurePropertyComplete(endOffset) {
  621. if (currentParent.type === 'property') {
  622. currentParent.length = endOffset - currentParent.offset;
  623. currentParent = currentParent.parent;
  624. }
  625. }
  626. function onValue(valueNode) {
  627. currentParent.children.push(valueNode);
  628. return valueNode;
  629. }
  630. var visitor = {
  631. onObjectBegin: function (offset) {
  632. currentParent = onValue({ type: 'object', offset: offset, length: -1, parent: currentParent, children: [] });
  633. },
  634. onObjectProperty: function (name, offset, length) {
  635. currentParent = onValue({ type: 'property', offset: offset, length: -1, parent: currentParent, children: [] });
  636. currentParent.children.push({ type: 'string', value: name, offset: offset, length: length, parent: currentParent });
  637. },
  638. onObjectEnd: function (offset, length) {
  639. currentParent.length = offset + length - currentParent.offset;
  640. currentParent = currentParent.parent;
  641. ensurePropertyComplete(offset + length);
  642. },
  643. onArrayBegin: function (offset, length) {
  644. currentParent = onValue({ type: 'array', offset: offset, length: -1, parent: currentParent, children: [] });
  645. },
  646. onArrayEnd: function (offset, length) {
  647. currentParent.length = offset + length - currentParent.offset;
  648. currentParent = currentParent.parent;
  649. ensurePropertyComplete(offset + length);
  650. },
  651. onLiteralValue: function (value, offset, length) {
  652. onValue({ type: getLiteralNodeType(value), offset: offset, length: length, parent: currentParent, value: value });
  653. ensurePropertyComplete(offset + length);
  654. },
  655. onSeparator: function (sep, offset, length) {
  656. if (currentParent.type === 'property') {
  657. if (sep === ':') {
  658. currentParent.columnOffset = offset;
  659. }
  660. else if (sep === ',') {
  661. ensurePropertyComplete(offset);
  662. }
  663. }
  664. },
  665. onError: function (error, offset, length) {
  666. errors.push({ error: error, offset: offset, length: length });
  667. }
  668. };
  669. visit(text, visitor, options);
  670. var result = currentParent.children[0];
  671. if (result) {
  672. delete result.parent;
  673. }
  674. return result;
  675. }
  676. exports.parseTree = parseTree;
  677. /**
  678. * Finds the node at the given path in a JSON DOM.
  679. */
  680. function findNodeAtLocation(root, path) {
  681. if (!root) {
  682. return void 0;
  683. }
  684. var node = root;
  685. for (var _i = 0, path_1 = path; _i < path_1.length; _i++) {
  686. var segment = path_1[_i];
  687. if (typeof segment === 'string') {
  688. if (node.type !== 'object' || !Array.isArray(node.children)) {
  689. return void 0;
  690. }
  691. var found = false;
  692. for (var _a = 0, _b = node.children; _a < _b.length; _a++) {
  693. var propertyNode = _b[_a];
  694. if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment) {
  695. node = propertyNode.children[1];
  696. found = true;
  697. break;
  698. }
  699. }
  700. if (!found) {
  701. return void 0;
  702. }
  703. }
  704. else {
  705. var index = segment;
  706. if (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {
  707. return void 0;
  708. }
  709. node = node.children[index];
  710. }
  711. }
  712. return node;
  713. }
  714. exports.findNodeAtLocation = findNodeAtLocation;
  715. /**
  716. * Evaluates the JavaScript object of the given JSON DOM node
  717. */
  718. function getNodeValue(node) {
  719. if (node.type === 'array') {
  720. return node.children.map(getNodeValue);
  721. }
  722. else if (node.type === 'object') {
  723. var obj = Object.create(null);
  724. for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
  725. var prop = _a[_i];
  726. obj[prop.children[0].value] = getNodeValue(prop.children[1]);
  727. }
  728. return obj;
  729. }
  730. return node.value;
  731. }
  732. exports.getNodeValue = getNodeValue;
  733. /**
  734. * Parses the given text and invokes the visitor functions for each object, array and literal reached.
  735. */
  736. function visit(text, visitor, options) {
  737. var _scanner = createScanner(text, false);
  738. function toNoArgVisit(visitFunction) {
  739. return visitFunction ? function () { return visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength()); } : function () { return true; };
  740. }
  741. function toOneArgVisit(visitFunction) {
  742. return visitFunction ? function (arg) { return visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength()); } : function () { return true; };
  743. }
  744. 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);
  745. var disallowComments = options && options.disallowComments;
  746. var allowTrailingComma = options && options.allowTrailingComma;
  747. function scanNext() {
  748. while (true) {
  749. var token = _scanner.scan();
  750. switch (_scanner.getTokenError()) {
  751. case ScanError.InvalidUnicode:
  752. handleError(ParseErrorCode.InvalidUnicode);
  753. break;
  754. case ScanError.InvalidEscapeCharacter:
  755. handleError(ParseErrorCode.InvalidEscapeCharacter);
  756. break;
  757. case ScanError.UnexpectedEndOfNumber:
  758. handleError(ParseErrorCode.UnexpectedEndOfNumber);
  759. break;
  760. case ScanError.UnexpectedEndOfComment:
  761. if (!disallowComments) {
  762. handleError(ParseErrorCode.UnexpectedEndOfComment);
  763. }
  764. break;
  765. case ScanError.UnexpectedEndOfString:
  766. handleError(ParseErrorCode.UnexpectedEndOfString);
  767. break;
  768. case ScanError.InvalidCharacter:
  769. handleError(ParseErrorCode.InvalidCharacter);
  770. break;
  771. }
  772. switch (token) {
  773. case SyntaxKind.LineCommentTrivia:
  774. case SyntaxKind.BlockCommentTrivia:
  775. if (disallowComments) {
  776. handleError(ParseErrorCode.InvalidCommentToken);
  777. }
  778. else {
  779. onComment();
  780. }
  781. break;
  782. case SyntaxKind.Unknown:
  783. handleError(ParseErrorCode.InvalidSymbol);
  784. break;
  785. case SyntaxKind.Trivia:
  786. case SyntaxKind.LineBreakTrivia:
  787. break;
  788. default:
  789. return token;
  790. }
  791. }
  792. }
  793. function handleError(error, skipUntilAfter, skipUntil) {
  794. if (skipUntilAfter === void 0) { skipUntilAfter = []; }
  795. if (skipUntil === void 0) { skipUntil = []; }
  796. onError(error);
  797. if (skipUntilAfter.length + skipUntil.length > 0) {
  798. var token = _scanner.getToken();
  799. while (token !== SyntaxKind.EOF) {
  800. if (skipUntilAfter.indexOf(token) !== -1) {
  801. scanNext();
  802. break;
  803. }
  804. else if (skipUntil.indexOf(token) !== -1) {
  805. break;
  806. }
  807. token = scanNext();
  808. }
  809. }
  810. }
  811. function parseString(isValue) {
  812. var value = _scanner.getTokenValue();
  813. if (isValue) {
  814. onLiteralValue(value);
  815. }
  816. else {
  817. onObjectProperty(value);
  818. }
  819. scanNext();
  820. return true;
  821. }
  822. function parseLiteral() {
  823. switch (_scanner.getToken()) {
  824. case SyntaxKind.NumericLiteral:
  825. var value = 0;
  826. try {
  827. value = JSON.parse(_scanner.getTokenValue());
  828. if (typeof value !== 'number') {
  829. handleError(ParseErrorCode.InvalidNumberFormat);
  830. value = 0;
  831. }
  832. }
  833. catch (e) {
  834. handleError(ParseErrorCode.InvalidNumberFormat);
  835. }
  836. onLiteralValue(value);
  837. break;
  838. case SyntaxKind.NullKeyword:
  839. onLiteralValue(null);
  840. break;
  841. case SyntaxKind.TrueKeyword:
  842. onLiteralValue(true);
  843. break;
  844. case SyntaxKind.FalseKeyword:
  845. onLiteralValue(false);
  846. break;
  847. default:
  848. return false;
  849. }
  850. scanNext();
  851. return true;
  852. }
  853. function parseProperty() {
  854. if (_scanner.getToken() !== SyntaxKind.StringLiteral) {
  855. handleError(ParseErrorCode.PropertyNameExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);
  856. return false;
  857. }
  858. parseString(false);
  859. if (_scanner.getToken() === SyntaxKind.ColonToken) {
  860. onSeparator(':');
  861. scanNext(); // consume colon
  862. if (!parseValue()) {
  863. handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);
  864. }
  865. }
  866. else {
  867. handleError(ParseErrorCode.ColonExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);
  868. }
  869. return true;
  870. }
  871. function parseObject() {
  872. onObjectBegin();
  873. scanNext(); // consume open brace
  874. var needsComma = false;
  875. while (_scanner.getToken() !== SyntaxKind.CloseBraceToken && _scanner.getToken() !== SyntaxKind.EOF) {
  876. if (_scanner.getToken() === SyntaxKind.CommaToken) {
  877. if (!needsComma) {
  878. handleError(ParseErrorCode.ValueExpected, [], []);
  879. }
  880. onSeparator(',');
  881. scanNext(); // consume comma
  882. if (_scanner.getToken() === SyntaxKind.CloseBraceToken && allowTrailingComma) {
  883. break;
  884. }
  885. }
  886. else if (needsComma) {
  887. handleError(ParseErrorCode.CommaExpected, [], []);
  888. }
  889. if (!parseProperty()) {
  890. handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken]);
  891. }
  892. needsComma = true;
  893. }
  894. onObjectEnd();
  895. if (_scanner.getToken() !== SyntaxKind.CloseBraceToken) {
  896. handleError(ParseErrorCode.CloseBraceExpected, [SyntaxKind.CloseBraceToken], []);
  897. }
  898. else {
  899. scanNext(); // consume close brace
  900. }
  901. return true;
  902. }
  903. function parseArray() {
  904. onArrayBegin();
  905. scanNext(); // consume open bracket
  906. var needsComma = false;
  907. while (_scanner.getToken() !== SyntaxKind.CloseBracketToken && _scanner.getToken() !== SyntaxKind.EOF) {
  908. if (_scanner.getToken() === SyntaxKind.CommaToken) {
  909. if (!needsComma) {
  910. handleError(ParseErrorCode.ValueExpected, [], []);
  911. }
  912. onSeparator(',');
  913. scanNext(); // consume comma
  914. if (_scanner.getToken() === SyntaxKind.CloseBracketToken && allowTrailingComma) {
  915. break;
  916. }
  917. }
  918. else if (needsComma) {
  919. handleError(ParseErrorCode.CommaExpected, [], []);
  920. }
  921. if (!parseValue()) {
  922. handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken]);
  923. }
  924. needsComma = true;
  925. }
  926. onArrayEnd();
  927. if (_scanner.getToken() !== SyntaxKind.CloseBracketToken) {
  928. handleError(ParseErrorCode.CloseBracketExpected, [SyntaxKind.CloseBracketToken], []);
  929. }
  930. else {
  931. scanNext(); // consume close bracket
  932. }
  933. return true;
  934. }
  935. function parseValue() {
  936. switch (_scanner.getToken()) {
  937. case SyntaxKind.OpenBracketToken:
  938. return parseArray();
  939. case SyntaxKind.OpenBraceToken:
  940. return parseObject();
  941. case SyntaxKind.StringLiteral:
  942. return parseString(true);
  943. default:
  944. return parseLiteral();
  945. }
  946. }
  947. scanNext();
  948. if (_scanner.getToken() === SyntaxKind.EOF) {
  949. return true;
  950. }
  951. if (!parseValue()) {
  952. handleError(ParseErrorCode.ValueExpected, [], []);
  953. return false;
  954. }
  955. if (_scanner.getToken() !== SyntaxKind.EOF) {
  956. handleError(ParseErrorCode.EndOfFileExpected, [], []);
  957. }
  958. return true;
  959. }
  960. exports.visit = visit;
  961. /**
  962. * Computes the edits needed to format a JSON document.
  963. *
  964. * @param documentText The input text
  965. * @param range The range to format or `undefined` to format the full content
  966. * @param options The formatting options
  967. * @returns A list of edit operations describing the formatting changes to the original document. Edits can be either inserts, replacements or
  968. * removals of text segments. All offsets refer to the original state of the document. No two edits must change or remove the same range of
  969. * text in the original document. However, multiple edits can have
  970. * the same offset, for example multiple inserts, or an insert followed by a remove or replace. The order in the array defines which edit is applied first.
  971. * To apply edits to an input, you can use `applyEdits`
  972. */
  973. function format(documentText, range, options) {
  974. return format_1.format(documentText, range, options);
  975. }
  976. exports.format = format;
  977. /**
  978. * Computes the edits needed to modify a value in the JSON document.
  979. *
  980. * @param documentText The input text
  981. * @param path The path of the value to change. The path represents either to the document root, a property or an array item.
  982. * If the path points to an non-existing property or item, it will be created.
  983. * @param value The new value for the specified property or item. If the value is undefined,
  984. * the property or item will be removed.
  985. * @param options Options
  986. * @returns A list of edit operations describing the formatting changes to the original document. Edits can be either inserts, replacements or
  987. * removals of text segments. All offsets refer to the original state of the document. No two edits must change or remove the same range of
  988. * text in the original document. However, multiple edits can have
  989. * the same offset, for example multiple inserts, or an insert followed by a remove or replace. The order in the array defines which edit is applied first.
  990. * To apply edits to an input, you can use `applyEdits`
  991. */
  992. function modify(text, path, value, options) {
  993. return edit_1.setProperty(text, path, value, options.formattingOptions, options.getInsertionIndex);
  994. }
  995. exports.modify = modify;
  996. /**
  997. * Applies edits to a input string.
  998. */
  999. function applyEdits(text, edits) {
  1000. for (var i = edits.length - 1; i >= 0; i--) {
  1001. text = edit_1.applyEdit(text, edits[i]);
  1002. }
  1003. return text;
  1004. }
  1005. exports.applyEdits = applyEdits;
  1006. });
  1007. //# sourceMappingURL=main.js.map