]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/read-package-json/node_modules/json-parse-helpfulerror/node_modules/jju/lib/parse.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / node_modules / read-package-json / node_modules / json-parse-helpfulerror / node_modules / jju / lib / parse.js
1 /*
2  * Author: Alex Kocharin <alex@kocharin.ru>
3  * GIT: https://github.com/rlidwka/jju
4  * License: WTFPL, grab your copy here: http://www.wtfpl.net/txt/copying/
5  */
6
7 // RTFM: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
8
9 var Uni = require('./unicode')
10
11 function isHexDigit(x) {
12   return (x >= '0' && x <= '9')
13       || (x >= 'A' && x <= 'F')
14       || (x >= 'a' && x <= 'f')
15 }
16
17 function isOctDigit(x) {
18   return x >= '0' && x <= '7'
19 }
20
21 function isDecDigit(x) {
22   return x >= '0' && x <= '9'
23 }
24
25 var unescapeMap = {
26   '\'': '\'',
27   '"' : '"',
28   '\\': '\\',
29   'b' : '\b',
30   'f' : '\f',
31   'n' : '\n',
32   'r' : '\r',
33   't' : '\t',
34   'v' : '\v',
35   '/' : '/',
36 }
37
38 function formatError(input, msg, position, lineno, column, json5) {
39   var result = msg + ' at ' + (lineno + 1) + ':' + (column + 1)
40     , tmppos = position - column - 1
41     , srcline = ''
42     , underline = ''
43
44   var isLineTerminator = json5 ? Uni.isLineTerminator : Uni.isLineTerminatorJSON
45
46   // output no more than 70 characters before the wrong ones
47   if (tmppos < position - 70) {
48     tmppos = position - 70
49   }
50
51   while (1) {
52     var chr = input[++tmppos]
53
54     if (isLineTerminator(chr) || tmppos === input.length) {
55       if (position >= tmppos) {
56         // ending line error, so show it after the last char
57         underline += '^'
58       }
59       break
60     }
61     srcline += chr
62
63     if (position === tmppos) {
64       underline += '^'
65     } else if (position > tmppos) {
66       underline += input[tmppos] === '\t' ? '\t' : ' '
67     }
68
69     // output no more than 78 characters on the string
70     if (srcline.length > 78) break
71   }
72
73   return result + '\n' + srcline + '\n' + underline
74 }
75
76 function parse(input, options) {
77   // parse as a standard JSON mode
78   var json5 = false;
79   var cjson = false;
80
81   if (options.legacy || options.mode === 'json') {
82     // use json
83   } else if (options.mode === 'cjson') {
84     cjson = true;
85   } else if (options.mode === 'json5') {
86     json5 = true;
87   } else {
88     // use it by default
89     json5 = true;
90   }
91
92   var isLineTerminator = json5 ? Uni.isLineTerminator : Uni.isLineTerminatorJSON
93   var isWhiteSpace     = json5 ? Uni.isWhiteSpace     : Uni.isWhiteSpaceJSON
94
95   var length = input.length
96     , lineno = 0
97     , linestart = 0
98     , position = 0
99     , stack = []
100
101   var tokenStart = function() {}
102   var tokenEnd = function(v) {return v}
103
104   /* tokenize({
105        raw: '...',
106        type: 'whitespace'|'comment'|'key'|'literal'|'separator'|'newline',
107        value: 'number'|'string'|'whatever',
108        path: [...],
109      })
110   */
111   if (options._tokenize) {
112     ;(function() {
113       var start = null
114       tokenStart = function() {
115         if (start !== null) throw Error('internal error, token overlap')
116         start = position
117       }
118
119       tokenEnd = function(v, type) {
120         if (start != position) {
121           var hash = {
122             raw: input.substr(start, position-start),
123             type: type,
124             stack: stack.slice(0),
125           }
126           if (v !== undefined) hash.value = v
127           options._tokenize.call(null, hash)
128         }
129         start = null
130         return v
131       }
132     })()
133   }
134
135   function fail(msg) {
136     var column = position - linestart
137
138     if (!msg) {
139       if (position < length) {
140         var token = '\'' +
141           JSON
142             .stringify(input[position])
143             .replace(/^"|"$/g, '')
144             .replace(/'/g, "\\'")
145             .replace(/\\"/g, '"')
146           + '\''
147
148         if (!msg) msg = 'Unexpected token ' + token
149       } else {
150         if (!msg) msg = 'Unexpected end of input'
151       }
152     }
153
154     var error = SyntaxError(formatError(input, msg, position, lineno, column, json5))
155     error.row = lineno + 1
156     error.column = column + 1
157     throw error
158   }
159
160   function newline(chr) {
161     // account for <cr><lf>
162     if (chr === '\r' && input[position] === '\n') position++
163     linestart = position
164     lineno++
165   }
166
167   function parseGeneric() {
168     var result
169
170     while (position < length) {
171       tokenStart()
172       var chr = input[position++]
173
174       if (chr === '"' || (chr === '\'' && json5)) {
175         return tokenEnd(parseString(chr), 'literal')
176
177       } else if (chr === '{') {
178         tokenEnd(undefined, 'separator')
179         return parseObject()
180
181       } else if (chr === '[') {
182         tokenEnd(undefined, 'separator')
183         return parseArray()
184
185       } else if (chr === '-'
186              ||  chr === '.'
187              ||  isDecDigit(chr)
188                  //           + number       Infinity          NaN
189              ||  (json5 && (chr === '+' || chr === 'I' || chr === 'N'))
190       ) {
191         return tokenEnd(parseNumber(), 'literal')
192
193       } else if (chr === 'n') {
194         parseKeyword('null')
195         return tokenEnd(null, 'literal')
196
197       } else if (chr === 't') {
198         parseKeyword('true')
199         return tokenEnd(true, 'literal')
200
201       } else if (chr === 'f') {
202         parseKeyword('false')
203         return tokenEnd(false, 'literal')
204
205       } else {
206         position--
207         return tokenEnd(undefined)
208       }
209     }
210   }
211
212   function parseKey() {
213     var result
214
215     while (position < length) {
216       tokenStart()
217       var chr = input[position++]
218
219       if (chr === '"' || (chr === '\'' && json5)) {
220         return tokenEnd(parseString(chr), 'key')
221
222       } else if (chr === '{') {
223         tokenEnd(undefined, 'separator')
224         return parseObject()
225
226       } else if (chr === '[') {
227         tokenEnd(undefined, 'separator')
228         return parseArray()
229
230       } else if (chr === '.'
231              ||  isDecDigit(chr)
232       ) {
233         return tokenEnd(parseNumber(true), 'key')
234
235       } else if (json5
236              &&  Uni.isIdentifierStart(chr) || (chr === '\\' && input[position] === 'u')) {
237         // unicode char or a unicode sequence
238         var rollback = position - 1
239         var result = parseIdentifier()
240
241         if (result === undefined) {
242           position = rollback
243           return tokenEnd(undefined)
244         } else {
245           return tokenEnd(result, 'key')
246         }
247
248       } else {
249         position--
250         return tokenEnd(undefined)
251       }
252     }
253   }
254
255   function skipWhiteSpace() {
256     tokenStart()
257     while (position < length) {
258       var chr = input[position++]
259
260       if (isLineTerminator(chr)) {
261         position--
262         tokenEnd(undefined, 'whitespace')
263         tokenStart()
264         position++
265         newline(chr)
266         tokenEnd(undefined, 'newline')
267         tokenStart()
268
269       } else if (isWhiteSpace(chr)) {
270         // nothing
271
272       } else if (chr === '/'
273              && (json5 || cjson)
274              && (input[position] === '/' || input[position] === '*')
275       ) {
276         position--
277         tokenEnd(undefined, 'whitespace')
278         tokenStart()
279         position++
280         skipComment(input[position++] === '*')
281         tokenEnd(undefined, 'comment')
282         tokenStart()
283
284       } else {
285         position--
286         break
287       }
288     }
289     return tokenEnd(undefined, 'whitespace')
290   }
291
292   function skipComment(multi) {
293     while (position < length) {
294       var chr = input[position++]
295
296       if (isLineTerminator(chr)) {
297         // LineTerminator is an end of singleline comment
298         if (!multi) {
299           // let parent function deal with newline
300           position--
301           return
302         }
303
304         newline(chr)
305
306       } else if (chr === '*' && multi) {
307         // end of multiline comment
308         if (input[position] === '/') {
309           position++
310           return
311         }
312
313       } else {
314         // nothing
315       }
316     }
317
318     if (multi) {
319       fail('Unclosed multiline comment')
320     }
321   }
322
323   function parseKeyword(keyword) {
324     // keyword[0] is not checked because it should've checked earlier
325     var _pos = position
326     var len = keyword.length
327     for (var i=1; i<len; i++) {
328       if (position >= length || keyword[i] != input[position]) {
329         position = _pos-1
330         fail()
331       }
332       position++
333     }
334   }
335
336   function parseObject() {
337     var result = options.null_prototype ? Object.create(null) : {}
338       , empty_object = {}
339       , is_non_empty = false
340
341     while (position < length) {
342       skipWhiteSpace()
343       var item1 = parseKey()
344       skipWhiteSpace()
345       tokenStart()
346       var chr = input[position++]
347       tokenEnd(undefined, 'separator')
348
349       if (chr === '}' && item1 === undefined) {
350         if (!json5 && is_non_empty) {
351           position--
352           fail('Trailing comma in object')
353         }
354         return result
355
356       } else if (chr === ':' && item1 !== undefined) {
357         skipWhiteSpace()
358         stack.push(item1)
359         var item2 = parseGeneric()
360         stack.pop()
361
362         if (item2 === undefined) fail('No value found for key ' + item1)
363         if (typeof(item1) !== 'string') {
364           if (!json5 || typeof(item1) !== 'number') {
365             fail('Wrong key type: ' + item1)
366           }
367         }
368
369         if ((item1 in empty_object || empty_object[item1] != null) && options.reserved_keys !== 'replace') {
370           if (options.reserved_keys === 'throw') {
371             fail('Reserved key: ' + item1)
372           } else {
373             // silently ignore it
374           }
375         } else {
376           if (typeof(options.reviver) === 'function') {
377             item2 = options.reviver.call(null, item1, item2)
378           }
379
380           if (item2 !== undefined) {
381             is_non_empty = true
382             Object.defineProperty(result, item1, {
383               value: item2,
384               enumerable: true,
385               configurable: true,
386               writable: true,
387             })
388           }
389         }
390
391         skipWhiteSpace()
392
393         tokenStart()
394         var chr = input[position++]
395         tokenEnd(undefined, 'separator')
396
397         if (chr === ',') {
398           continue
399
400         } else if (chr === '}') {
401           return result
402
403         } else {
404           fail()
405         }
406
407       } else {
408         position--
409         fail()
410       }
411     }
412
413     fail()
414   }
415
416   function parseArray() {
417     var result = []
418
419     while (position < length) {
420       skipWhiteSpace()
421       stack.push(result.length)
422       var item = parseGeneric()
423       stack.pop()
424       skipWhiteSpace()
425       tokenStart()
426       var chr = input[position++]
427       tokenEnd(undefined, 'separator')
428
429       if (item !== undefined) {
430         if (typeof(options.reviver) === 'function') {
431           item = options.reviver.call(null, String(result.length), item)
432         }
433         if (item === undefined) {
434           result.length++
435           item = true // hack for check below, not included into result
436         } else {
437           result.push(item)
438         }
439       }
440
441       if (chr === ',') {
442         if (item === undefined) {
443           fail('Elisions are not supported')
444         }
445
446       } else if (chr === ']') {
447         if (!json5 && item === undefined && result.length) {
448           position--
449           fail('Trailing comma in array')
450         }
451         return result
452
453       } else {
454         position--
455         fail()
456       }
457     }
458   }
459
460   function parseNumber() {
461     // rewind because we don't know first char
462     position--
463
464     var start = position
465       , chr = input[position++]
466       , t
467
468     var to_num = function(is_octal) {
469       var str = input.substr(start, position - start)
470
471       if (is_octal) {
472         var result = parseInt(str.replace(/^0o?/, ''), 8)
473       } else {
474         var result = Number(str)
475       }
476
477       if (Number.isNaN(result)) {
478         position--
479         fail('Bad numeric literal - "' + input.substr(start, position - start + 1) + '"')
480       } else if (!json5 && !str.match(/^-?(0|[1-9][0-9]*)(\.[0-9]+)?(e[+-]?[0-9]+)?$/i)) {
481         // additional restrictions imposed by json
482         position--
483         fail('Non-json numeric literal - "' + input.substr(start, position - start + 1) + '"')
484       } else {
485         return result
486       }
487     }
488
489     // ex: -5982475.249875e+29384
490     //     ^ skipping this
491     if (chr === '-' || (chr === '+' && json5)) chr = input[position++]
492
493     if (chr === 'N' && json5) {
494       parseKeyword('NaN')
495       return NaN
496     }
497
498     if (chr === 'I' && json5) {
499       parseKeyword('Infinity')
500
501       // returning +inf or -inf
502       return to_num()
503     }
504
505     if (chr >= '1' && chr <= '9') {
506       // ex: -5982475.249875e+29384
507       //        ^^^ skipping these
508       while (position < length && isDecDigit(input[position])) position++
509       chr = input[position++]
510     }
511
512     // special case for leading zero: 0.123456
513     if (chr === '0') {
514       chr = input[position++]
515
516       //             new syntax, "0o777"           old syntax, "0777"
517       var is_octal = chr === 'o' || chr === 'O' || isOctDigit(chr)
518       var is_hex = chr === 'x' || chr === 'X'
519
520       if (json5 && (is_octal || is_hex)) {
521         while (position < length
522            &&  (is_hex ? isHexDigit : isOctDigit)( input[position] )
523         ) position++
524
525         var sign = 1
526         if (input[start] === '-') {
527           sign = -1
528           start++
529         } else if (input[start] === '+') {
530           start++
531         }
532
533         return sign * to_num(is_octal)
534       }
535     }
536
537     if (chr === '.') {
538       // ex: -5982475.249875e+29384
539       //                ^^^ skipping these
540       while (position < length && isDecDigit(input[position])) position++
541       chr = input[position++]
542     }
543
544     if (chr === 'e' || chr === 'E') {
545       chr = input[position++]
546       if (chr === '-' || chr === '+') position++
547       // ex: -5982475.249875e+29384
548       //                       ^^^ skipping these
549       while (position < length && isDecDigit(input[position])) position++
550       chr = input[position++]
551     }
552
553     // we have char in the buffer, so count for it
554     position--
555     return to_num()
556   }
557
558   function parseIdentifier() {
559     // rewind because we don't know first char
560     position--
561
562     var result = ''
563
564     while (position < length) {
565       var chr = input[position++]
566
567       if (chr === '\\'
568       &&  input[position] === 'u'
569       &&  isHexDigit(input[position+1])
570       &&  isHexDigit(input[position+2])
571       &&  isHexDigit(input[position+3])
572       &&  isHexDigit(input[position+4])
573       ) {
574         // UnicodeEscapeSequence
575         chr = String.fromCharCode(parseInt(input.substr(position+1, 4), 16))
576         position += 5
577       }
578
579       if (result.length) {
580         // identifier started
581         if (Uni.isIdentifierPart(chr)) {
582           result += chr
583         } else {
584           position--
585           return result
586         }
587
588       } else {
589         if (Uni.isIdentifierStart(chr)) {
590           result += chr
591         } else {
592           return undefined
593         }
594       }
595     }
596
597     fail()
598   }
599
600   function parseString(endChar) {
601     // 7.8.4 of ES262 spec
602     var result = ''
603
604     while (position < length) {
605       var chr = input[position++]
606
607       if (chr === endChar) {
608         return result
609
610       } else if (chr === '\\') {
611         if (position >= length) fail()
612         chr = input[position++]
613
614         if (unescapeMap[chr] && (json5 || (chr != 'v' && chr != "'"))) {
615           result += unescapeMap[chr]
616
617         } else if (json5 && isLineTerminator(chr)) {
618           // line continuation
619           newline(chr)
620
621         } else if (chr === 'u' || (chr === 'x' && json5)) {
622           // unicode/character escape sequence
623           var off = chr === 'u' ? 4 : 2
624
625           // validation for \uXXXX
626           for (var i=0; i<off; i++) {
627             if (position >= length) fail()
628             if (!isHexDigit(input[position])) fail('Bad escape sequence')
629             position++
630           }
631
632           result += String.fromCharCode(parseInt(input.substr(position-off, off), 16))
633         } else if (json5 && isOctDigit(chr)) {
634           if (chr < '4' && isOctDigit(input[position]) && isOctDigit(input[position+1])) {
635             // three-digit octal
636             var digits = 3
637           } else if (isOctDigit(input[position])) {
638             // two-digit octal
639             var digits = 2
640           } else {
641             var digits = 1
642           }
643           position += digits - 1
644           result += String.fromCharCode(parseInt(input.substr(position-digits, digits), 8))
645           /*if (!isOctDigit(input[position])) {
646             // \0 is allowed still
647             result += '\0'
648           } else {
649             fail('Octal literals are not supported')
650           }*/
651
652         } else if (json5) {
653           // \X -> x
654           result += chr
655
656         } else {
657           position--
658           fail()
659         }
660
661       } else if (isLineTerminator(chr)) {
662         fail()
663
664       } else {
665         if (!json5 && chr.charCodeAt(0) < 32) {
666           position--
667           fail('Unexpected control character')
668         }
669
670         // SourceCharacter but not one of " or \ or LineTerminator
671         result += chr
672       }
673     }
674
675     fail()
676   }
677
678   skipWhiteSpace()
679   var return_value = parseGeneric()
680   if (return_value !== undefined || position < length) {
681     skipWhiteSpace()
682
683     if (position >= length) {
684       if (typeof(options.reviver) === 'function') {
685         return_value = options.reviver.call(null, '', return_value)
686       }
687       return return_value
688     } else {
689       fail()
690     }
691
692   } else {
693     if (position) {
694       fail('No data, only a whitespace')
695     } else {
696       fail('No data, empty input')
697     }
698   }
699 }
700
701 /*
702  * parse(text, options)
703  * or
704  * parse(text, reviver)
705  *
706  * where:
707  * text - string
708  * options - object
709  * reviver - function
710  */
711 module.exports.parse = function parseJSON(input, options) {
712   // support legacy functions
713   if (typeof(options) === 'function') {
714     options = {
715       reviver: options
716     }
717   }
718
719   if (input === undefined) {
720     // parse(stringify(x)) should be equal x
721     // with JSON functions it is not 'cause of undefined
722     // so we're fixing it
723     return undefined
724   }
725
726   // JSON.parse compat
727   if (typeof(input) !== 'string') input = String(input)
728   if (options == null) options = {}
729   if (options.reserved_keys == null) options.reserved_keys = 'ignore'
730
731   if (options.reserved_keys === 'throw' || options.reserved_keys === 'ignore') {
732     if (options.null_prototype == null) {
733       options.null_prototype = true
734     }
735   }
736
737   try {
738     return parse(input, options)
739   } catch(err) {
740     // jju is a recursive parser, so JSON.parse("{{{{{{{") could blow up the stack
741     //
742     // this catch is used to skip all those internal calls
743     if (err instanceof SyntaxError && err.row != null && err.column != null) {
744       var old_err = err
745       err = SyntaxError(old_err.message)
746       err.column = old_err.column
747       err.row = old_err.row
748     }
749     throw err
750   }
751 }
752
753 module.exports.tokenize = function tokenizeJSON(input, options) {
754   if (options == null) options = {}
755
756   options._tokenize = function(smth) {
757     if (options._addstack) smth.stack.unshift.apply(smth.stack, options._addstack)
758     tokens.push(smth)
759   }
760
761   var tokens = []
762   tokens.data = module.exports.parse(input, options)
763   return tokens
764 }
765