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"], 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 | ;
|
15 | Object.defineProperty(exports, "__esModule", { value: true });
|
16 | /**
|
17 | * Creates a JSON scanner on the given text.
|
18 | * If ignoreTrivia is set, whitespaces or comments are ignored.
|
19 | */
|
20 | function createScanner(text, ignoreTrivia) {
|
21 | if (ignoreTrivia === void 0) { ignoreTrivia = false; }
|
22 | var len = text.length;
|
23 | var pos = 0, value = '', tokenOffset = 0, token = 16 /* Unknown */, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0 /* None */;
|
24 | function scanHexDigits(count, exact) {
|
25 | var digits = 0;
|
26 | var value = 0;
|
27 | while (digits < count || !exact) {
|
28 | var ch = text.charCodeAt(pos);
|
29 | if (ch >= 48 /* _0 */ && ch <= 57 /* _9 */) {
|
30 | value = value * 16 + ch - 48 /* _0 */;
|
31 | }
|
32 | else if (ch >= 65 /* A */ && ch <= 70 /* F */) {
|
33 | value = value * 16 + ch - 65 /* A */ + 10;
|
34 | }
|
35 | else if (ch >= 97 /* a */ && ch <= 102 /* f */) {
|
36 | value = value * 16 + ch - 97 /* a */ + 10;
|
37 | }
|
38 | else {
|
39 | break;
|
40 | }
|
41 | pos++;
|
42 | digits++;
|
43 | }
|
44 | if (digits < count) {
|
45 | value = -1;
|
46 | }
|
47 | return value;
|
48 | }
|
49 | function setPosition(newPosition) {
|
50 | pos = newPosition;
|
51 | value = '';
|
52 | tokenOffset = 0;
|
53 | token = 16 /* Unknown */;
|
54 | scanError = 0 /* None */;
|
55 | }
|
56 | function scanNumber() {
|
57 | var start = pos;
|
58 | if (text.charCodeAt(pos) === 48 /* _0 */) {
|
59 | pos++;
|
60 | }
|
61 | else {
|
62 | pos++;
|
63 | while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
64 | pos++;
|
65 | }
|
66 | }
|
67 | if (pos < text.length && text.charCodeAt(pos) === 46 /* dot */) {
|
68 | pos++;
|
69 | if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
70 | pos++;
|
71 | while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
72 | pos++;
|
73 | }
|
74 | }
|
75 | else {
|
76 | scanError = 3 /* UnexpectedEndOfNumber */;
|
77 | return text.substring(start, pos);
|
78 | }
|
79 | }
|
80 | var end = pos;
|
81 | if (pos < text.length && (text.charCodeAt(pos) === 69 /* E */ || text.charCodeAt(pos) === 101 /* e */)) {
|
82 | pos++;
|
83 | if (pos < text.length && text.charCodeAt(pos) === 43 /* plus */ || text.charCodeAt(pos) === 45 /* minus */) {
|
84 | pos++;
|
85 | }
|
86 | if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
87 | pos++;
|
88 | while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
89 | pos++;
|
90 | }
|
91 | end = pos;
|
92 | }
|
93 | else {
|
94 | scanError = 3 /* UnexpectedEndOfNumber */;
|
95 | }
|
96 | }
|
97 | return text.substring(start, end);
|
98 | }
|
99 | function scanString() {
|
100 | var result = '', start = pos;
|
101 | while (true) {
|
102 | if (pos >= len) {
|
103 | result += text.substring(start, pos);
|
104 | scanError = 2 /* UnexpectedEndOfString */;
|
105 | break;
|
106 | }
|
107 | var ch = text.charCodeAt(pos);
|
108 | if (ch === 34 /* doubleQuote */) {
|
109 | result += text.substring(start, pos);
|
110 | pos++;
|
111 | break;
|
112 | }
|
113 | if (ch === 92 /* backslash */) {
|
114 | result += text.substring(start, pos);
|
115 | pos++;
|
116 | if (pos >= len) {
|
117 | scanError = 2 /* UnexpectedEndOfString */;
|
118 | break;
|
119 | }
|
120 | var ch2 = text.charCodeAt(pos++);
|
121 | switch (ch2) {
|
122 | case 34 /* doubleQuote */:
|
123 | result += '\"';
|
124 | break;
|
125 | case 92 /* backslash */:
|
126 | result += '\\';
|
127 | break;
|
128 | case 47 /* slash */:
|
129 | result += '/';
|
130 | break;
|
131 | case 98 /* b */:
|
132 | result += '\b';
|
133 | break;
|
134 | case 102 /* f */:
|
135 | result += '\f';
|
136 | break;
|
137 | case 110 /* n */:
|
138 | result += '\n';
|
139 | break;
|
140 | case 114 /* r */:
|
141 | result += '\r';
|
142 | break;
|
143 | case 116 /* t */:
|
144 | result += '\t';
|
145 | break;
|
146 | case 117 /* u */:
|
147 | var ch3 = scanHexDigits(4, true);
|
148 | if (ch3 >= 0) {
|
149 | result += String.fromCharCode(ch3);
|
150 | }
|
151 | else {
|
152 | scanError = 4 /* InvalidUnicode */;
|
153 | }
|
154 | break;
|
155 | default:
|
156 | scanError = 5 /* InvalidEscapeCharacter */;
|
157 | }
|
158 | start = pos;
|
159 | continue;
|
160 | }
|
161 | if (ch >= 0 && ch <= 0x1f) {
|
162 | if (isLineBreak(ch)) {
|
163 | result += text.substring(start, pos);
|
164 | scanError = 2 /* UnexpectedEndOfString */;
|
165 | break;
|
166 | }
|
167 | else {
|
168 | scanError = 6 /* InvalidCharacter */;
|
169 | // mark as error but continue with string
|
170 | }
|
171 | }
|
172 | pos++;
|
173 | }
|
174 | return result;
|
175 | }
|
176 | function scanNext() {
|
177 | value = '';
|
178 | scanError = 0 /* None */;
|
179 | tokenOffset = pos;
|
180 | lineStartOffset = lineNumber;
|
181 | prevTokenLineStartOffset = tokenLineStartOffset;
|
182 | if (pos >= len) {
|
183 | // at the end
|
184 | tokenOffset = len;
|
185 | return token = 17 /* EOF */;
|
186 | }
|
187 | var code = text.charCodeAt(pos);
|
188 | // trivia: whitespace
|
189 | if (isWhiteSpace(code)) {
|
190 | do {
|
191 | pos++;
|
192 | value += String.fromCharCode(code);
|
193 | code = text.charCodeAt(pos);
|
194 | } while (isWhiteSpace(code));
|
195 | return token = 15 /* Trivia */;
|
196 | }
|
197 | // trivia: newlines
|
198 | if (isLineBreak(code)) {
|
199 | pos++;
|
200 | value += String.fromCharCode(code);
|
201 | if (code === 13 /* carriageReturn */ && text.charCodeAt(pos) === 10 /* lineFeed */) {
|
202 | pos++;
|
203 | value += '\n';
|
204 | }
|
205 | lineNumber++;
|
206 | tokenLineStartOffset = pos;
|
207 | return token = 14 /* LineBreakTrivia */;
|
208 | }
|
209 | switch (code) {
|
210 | // tokens: []{}:,
|
211 | case 123 /* openBrace */:
|
212 | pos++;
|
213 | return token = 1 /* OpenBraceToken */;
|
214 | case 125 /* closeBrace */:
|
215 | pos++;
|
216 | return token = 2 /* CloseBraceToken */;
|
217 | case 91 /* openBracket */:
|
218 | pos++;
|
219 | return token = 3 /* OpenBracketToken */;
|
220 | case 93 /* closeBracket */:
|
221 | pos++;
|
222 | return token = 4 /* CloseBracketToken */;
|
223 | case 58 /* colon */:
|
224 | pos++;
|
225 | return token = 6 /* ColonToken */;
|
226 | case 44 /* comma */:
|
227 | pos++;
|
228 | return token = 5 /* CommaToken */;
|
229 | // strings
|
230 | case 34 /* doubleQuote */:
|
231 | pos++;
|
232 | value = scanString();
|
233 | return token = 10 /* StringLiteral */;
|
234 | // comments
|
235 | case 47 /* slash */:
|
236 | var start = pos - 1;
|
237 | // Single-line comment
|
238 | if (text.charCodeAt(pos + 1) === 47 /* slash */) {
|
239 | pos += 2;
|
240 | while (pos < len) {
|
241 | if (isLineBreak(text.charCodeAt(pos))) {
|
242 | break;
|
243 | }
|
244 | pos++;
|
245 | }
|
246 | value = text.substring(start, pos);
|
247 | return token = 12 /* LineCommentTrivia */;
|
248 | }
|
249 | // Multi-line comment
|
250 | if (text.charCodeAt(pos + 1) === 42 /* asterisk */) {
|
251 | pos += 2;
|
252 | var safeLength = len - 1; // For lookahead.
|
253 | var commentClosed = false;
|
254 | while (pos < safeLength) {
|
255 | var ch = text.charCodeAt(pos);
|
256 | if (ch === 42 /* asterisk */ && text.charCodeAt(pos + 1) === 47 /* slash */) {
|
257 | pos += 2;
|
258 | commentClosed = true;
|
259 | break;
|
260 | }
|
261 | pos++;
|
262 | if (isLineBreak(ch)) {
|
263 | if (ch === 13 /* carriageReturn */ && text.charCodeAt(pos) === 10 /* lineFeed */) {
|
264 | pos++;
|
265 | }
|
266 | lineNumber++;
|
267 | tokenLineStartOffset = pos;
|
268 | }
|
269 | }
|
270 | if (!commentClosed) {
|
271 | pos++;
|
272 | scanError = 1 /* UnexpectedEndOfComment */;
|
273 | }
|
274 | value = text.substring(start, pos);
|
275 | return token = 13 /* BlockCommentTrivia */;
|
276 | }
|
277 | // just a single slash
|
278 | value += String.fromCharCode(code);
|
279 | pos++;
|
280 | return token = 16 /* Unknown */;
|
281 | // numbers
|
282 | case 45 /* minus */:
|
283 | value += String.fromCharCode(code);
|
284 | pos++;
|
285 | if (pos === len || !isDigit(text.charCodeAt(pos))) {
|
286 | return token = 16 /* Unknown */;
|
287 | }
|
288 | // found a minus, followed by a number so
|
289 | // we fall through to proceed with scanning
|
290 | // numbers
|
291 | case 48 /* _0 */:
|
292 | case 49 /* _1 */:
|
293 | case 50 /* _2 */:
|
294 | case 51 /* _3 */:
|
295 | case 52 /* _4 */:
|
296 | case 53 /* _5 */:
|
297 | case 54 /* _6 */:
|
298 | case 55 /* _7 */:
|
299 | case 56 /* _8 */:
|
300 | case 57 /* _9 */:
|
301 | value += scanNumber();
|
302 | return token = 11 /* NumericLiteral */;
|
303 | // literals and unknown symbols
|
304 | default:
|
305 | // is a literal? Read the full word.
|
306 | while (pos < len && isUnknownContentCharacter(code)) {
|
307 | pos++;
|
308 | code = text.charCodeAt(pos);
|
309 | }
|
310 | if (tokenOffset !== pos) {
|
311 | value = text.substring(tokenOffset, pos);
|
312 | // keywords: true, false, null
|
313 | switch (value) {
|
314 | case 'true': return token = 8 /* TrueKeyword */;
|
315 | case 'false': return token = 9 /* FalseKeyword */;
|
316 | case 'null': return token = 7 /* NullKeyword */;
|
317 | }
|
318 | return token = 16 /* Unknown */;
|
319 | }
|
320 | // some
|
321 | value += String.fromCharCode(code);
|
322 | pos++;
|
323 | return token = 16 /* Unknown */;
|
324 | }
|
325 | }
|
326 | function isUnknownContentCharacter(code) {
|
327 | if (isWhiteSpace(code) || isLineBreak(code)) {
|
328 | return false;
|
329 | }
|
330 | switch (code) {
|
331 | case 125 /* closeBrace */:
|
332 | case 93 /* closeBracket */:
|
333 | case 123 /* openBrace */:
|
334 | case 91 /* openBracket */:
|
335 | case 34 /* doubleQuote */:
|
336 | case 58 /* colon */:
|
337 | case 44 /* comma */:
|
338 | case 47 /* slash */:
|
339 | return false;
|
340 | }
|
341 | return true;
|
342 | }
|
343 | function scanNextNonTrivia() {
|
344 | var result;
|
345 | do {
|
346 | result = scanNext();
|
347 | } while (result >= 12 /* LineCommentTrivia */ && result <= 15 /* Trivia */);
|
348 | return result;
|
349 | }
|
350 | return {
|
351 | setPosition: setPosition,
|
352 | getPosition: function () { return pos; },
|
353 | scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
|
354 | getToken: function () { return token; },
|
355 | getTokenValue: function () { return value; },
|
356 | getTokenOffset: function () { return tokenOffset; },
|
357 | getTokenLength: function () { return pos - tokenOffset; },
|
358 | getTokenStartLine: function () { return lineStartOffset; },
|
359 | getTokenStartCharacter: function () { return tokenOffset - prevTokenLineStartOffset; },
|
360 | getTokenError: function () { return scanError; },
|
361 | };
|
362 | }
|
363 | exports.createScanner = createScanner;
|
364 | function isWhiteSpace(ch) {
|
365 | return ch === 32 /* space */ || ch === 9 /* tab */ || ch === 11 /* verticalTab */ || ch === 12 /* formFeed */ ||
|
366 | ch === 160 /* nonBreakingSpace */ || ch === 5760 /* ogham */ || ch >= 8192 /* enQuad */ && ch <= 8203 /* zeroWidthSpace */ ||
|
367 | ch === 8239 /* narrowNoBreakSpace */ || ch === 8287 /* mathematicalSpace */ || ch === 12288 /* ideographicSpace */ || ch === 65279 /* byteOrderMark */;
|
368 | }
|
369 | function isLineBreak(ch) {
|
370 | return ch === 10 /* lineFeed */ || ch === 13 /* carriageReturn */ || ch === 8232 /* lineSeparator */ || ch === 8233 /* paragraphSeparator */;
|
371 | }
|
372 | function isDigit(ch) {
|
373 | return ch >= 48 /* _0 */ && ch <= 57 /* _9 */;
|
374 | }
|
375 | });
|