UNPKG

15.8 kBJavaScriptView Raw
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 'use strict';
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});