export class SurveyJSON5 { public static positionName = "pos" ; private static escapee = { "'" : "'" , '"' : '"' , "\\" : "\\" , "/" : "/" , "\n" : "" , b : "\b" , f : "\f" , n : "\n" , r : "\r" , t : "\t" } ; private static ws = [ " " , "\t" , "\r" , "\n" , "\v" , "\f" , "\xA0" , "\uFEFF" ] ; private endAt : number ; private at : number ; private ch : any ; private text : string ; private parseType : number ; constructor ( parseType = 0 ) { this . parseType = parseType ; } public parse ( source , reviver = null , startFrom = 0 , endAt = - 1 ) { var result ; this . text = String ( source ) ; this . at = startFrom ; this . endAt = endAt ; this . ch = " " ; result = this . value ( ) ; this . white ( ) ; if ( this . ch ) { this . error ( "Syntax error" ) ; } return typeof reviver === "function" ? ( function walk ( holder , key ) { var k , v , value = holder [ key ] ; if ( value && typeof value === "object" ) { for ( k in value ) { if ( Object . prototype . hasOwnProperty . call ( value , k ) ) { v = walk ( value , k ) ; if ( v !== undefined ) { value [ k ] = v ; } else { delete value [ k ] ; } } } } return reviver . call ( holder , key , value ) ; } ) ( { "" : result } , "" ) : result ; } private error ( m ) { var error = new SyntaxError ( ) ; error . message = m ; error [ "at" ] = this . at ; throw error ; } private next ( c = null ) { if ( c && c !== this . ch ) { this . error ( "Expected '" + c + "' instead of '" + this . ch + "'" ) ; } this . ch = this . chartAt ( ) ; this . at += 1 ; return this . ch ; } private peek ( ) { return this . chartAt ( ) ; } private chartAt ( ) { if ( this . endAt > - 1 && this . at >= this . endAt ) return "" ; return this . text . charAt ( this . at ) ; } private identifier ( ) { var key = this . ch ; if ( this . ch !== "_" && this . ch !== "$" && ( this . ch < "a" || this . ch > "z" ) && ( this . ch < "A" || this . ch > "Z" ) ) { this . error ( "Bad identifier" ) ; } while ( this . next ( ) && ( this . ch === "_" || this . ch === "$" || ( this . ch >= "a" && this . ch <= "z" ) || ( this . ch >= "A" && this . ch <= "Z" ) || ( this . ch >= "0" && this . ch <= "9" ) ) ) { key += this . ch ; } return key ; } private number ( ) { var number , sign = "" , string = "" , base = 10 ; if ( this . ch === "-" || this . ch === "+" ) { sign = this . ch ; this . next ( this . ch ) ; } if ( this . ch === "I" ) { number = this . word ( ) ; if ( typeof number !== "number" || isNaN ( number ) ) { this . error ( "Unexpected word for number" ) ; } return sign === "-" ? - number : number ; } if ( this . ch === "N" ) { number = this . word ( ) ; if ( ! isNaN ( number ) ) { this . error ( "expected word to be NaN" ) ; } return number ; } if ( this . ch === "0" ) { string += this . ch ; this . next ( ) ; if ( this . ch === "x" || this . ch === "X" ) { string += this . ch ; this . next ( ) ; base = 16 ; } else if ( this . ch >= "0" && this . ch <= "9" ) { this . error ( "Octal literal" ) ; } } switch ( base ) { case 10 : while ( this . ch >= "0" && this . ch <= "9" ) { string += this . ch ; this . next ( ) ; } if ( this . ch === "." ) { string += "." ; while ( this . next ( ) && this . ch >= "0" && this . ch <= "9" ) { string += this . ch ; } } if ( this . ch === "e" || this . ch === "E" ) { string += this . ch ; this . next ( ) ; if ( this . ch === "-" || this . ch === "+" ) { string += this . ch ; this . next ( ) ; } while ( this . ch >= "0" && this . ch <= "9" ) { string += this . ch ; this . next ( ) ; } } break ; case 16 : while ( ( this . ch >= "0" && this . ch <= "9" ) || ( this . ch >= "A" && this . ch <= "F" ) || ( this . ch >= "a" && this . ch <= "f" ) ) { string += this . ch ; this . next ( ) ; } break ; } if ( sign === "-" ) { number = - string ; } else { number = + string ; } if ( ! isFinite ( number ) ) { this . error ( "Bad number" ) ; } else { return number ; } } private string ( ) { var hex , i , string = "" , delim , uffff ; if ( this . ch === '"' || this . ch === "'" ) { delim = this . ch ; while ( this . next ( ) ) { if ( this . ch === delim ) { this . next ( ) ; return string ; } else if ( this . ch === "\\" ) { this . next ( ) ; if ( this . ch === "u" ) { uffff = 0 ; for ( i = 0 ; i < 4 ; i += 1 ) { hex = parseInt ( this . next ( ) , 16 ) ; if ( ! isFinite ( hex ) ) { break ; } uffff = uffff * 16 + hex ; } string += String . fromCharCode ( uffff ) ; } else if ( this . ch === "\r" ) { if ( this . peek ( ) === "\n" ) { this . next ( ) ; } } else if ( typeof SurveyJSON5 . escapee [ this . ch ] === "string" ) { string += SurveyJSON5 . escapee [ this . ch ] ; } else { break ; } } else if ( this . ch === "\n" ) { break ; } else { string += this . ch ; } } } this . error ( "Bad string" ) ; } private inlineComment ( ) { if ( this . ch !== "/" ) { this . error ( "Not an inline comment" ) ; } do { this . next ( ) ; if ( this . ch === "\n" || this . ch === "\r" ) { this . next ( ) ; return ; } } while ( this . ch ) ; } private blockComment ( ) { if ( this . ch !== "*" ) { this . error ( "Not a block comment" ) ; } do { this . next ( ) ; while ( this . ch === "*" ) { this . next ( "*" ) ; if ( this . ch === "/" ) { this . next ( "/" ) ; return ; } } } while ( this . ch ) ; this . error ( "Unterminated block comment" ) ; } private comment ( ) { if ( this . ch !== "/" ) { this . error ( "Not a comment" ) ; } this . next ( "/" ) ; if ( this . ch === "/" ) { this . inlineComment ( ) ; } else if ( this . ch === "*" ) { this . blockComment ( ) ; } else { this . error ( "Unrecognized comment" ) ; } } private white ( ) { while ( this . ch ) { if ( this . ch === "/" ) { this . comment ( ) ; } else if ( SurveyJSON5 . ws . indexOf ( this . ch ) >= 0 ) { this . next ( ) ; } else { return ; } } } private word ( ) { switch ( this . ch ) { case "t" : this . next ( "t" ) ; this . next ( "r" ) ; this . next ( "u" ) ; this . next ( "e" ) ; return true ; case "f" : this . next ( "f" ) ; this . next ( "a" ) ; this . next ( "l" ) ; this . next ( "s" ) ; this . next ( "e" ) ; return false ; case "n" : this . next ( "n" ) ; this . next ( "u" ) ; this . next ( "l" ) ; this . next ( "l" ) ; return null ; case "I" : this . next ( "I" ) ; this . next ( "n" ) ; this . next ( "f" ) ; this . next ( "i" ) ; this . next ( "n" ) ; this . next ( "i" ) ; this . next ( "t" ) ; this . next ( "y" ) ; return Infinity ; case "N" : this . next ( "N" ) ; this . next ( "a" ) ; this . next ( "N" ) ; return NaN ; } this . error ( "Unexpected '" + this . ch + "'" ) ; } private array ( ) { var array = [ ] ; if ( this . ch === "[" ) { this . next ( "[" ) ; this . white ( ) ; while ( this . ch ) { if ( this . ch === "]" ) { this . next ( "]" ) ; return array ; } if ( this . ch === "," ) { this . error ( "Missing array element" ) ; } else { array . push ( this . value ( ) ) ; } this . white ( ) ; if ( this . ch !== "," ) { this . next ( "]" ) ; return array ; } this . next ( "," ) ; this . white ( ) ; } } this . error ( "Bad array" ) ; } private object ( ) { var key , start , isFirstProperty = true , object = { } ; if ( this . parseType > 0 ) { object [ SurveyJSON5 . positionName ] = { start : this . at - 1 } ; } if ( this . ch === "{" ) { this . next ( "{" ) ; this . white ( ) ; start = this . at - 1 ; while ( this . ch ) { if ( this . ch === "}" ) { if ( this . parseType > 0 ) { object [ SurveyJSON5 . positionName ] . end = start ; } this . next ( "}" ) ; return object ; } if ( this . ch === '"' || this . ch === "'" ) { key = this . string ( ) ; } else { key = this . identifier ( ) ; } this . white ( ) ; if ( this . parseType > 1 ) { object [ SurveyJSON5 . positionName ] [ key ] = { start : start , valueStart : this . at } ; } this . next ( ":" ) ; object [ key ] = this . value ( ) ; if ( this . parseType > 1 ) { start = this . at - 1 ; object [ SurveyJSON5 . positionName ] [ key ] . valueEnd = start ; object [ SurveyJSON5 . positionName ] [ key ] . end = start ; } this . white ( ) ; if ( this . ch !== "," ) { if ( this . parseType > 1 ) { object [ SurveyJSON5 . positionName ] [ key ] . valueEnd -- ; object [ SurveyJSON5 . positionName ] [ key ] . end -- ; } if ( this . parseType > 0 ) { object [ SurveyJSON5 . positionName ] . end = this . at - 1 ; } this . next ( "}" ) ; return object ; } if ( this . parseType > 1 ) { object [ SurveyJSON5 . positionName ] [ key ] . valueEnd -- ; if ( ! isFirstProperty ) { object [ SurveyJSON5 . positionName ] [ key ] . end -- ; } } this . next ( "," ) ; this . white ( ) ; isFirstProperty = false ; } } this . error ( "Bad object" ) ; } private value ( ) { this . white ( ) ; switch ( this . ch ) { case "{" : return this . object ( ) ; case "[" : return this . array ( ) ; case '"' : case "'" : return this . string ( ) ; case "-" : case "+" : case "." : return this . number ( ) ; default : return this . ch >= "0" && this . ch <= "9" ? this . number ( ) : this . word ( ) ; } } private replacer : any ; private indentStr : string ; private objStack ; public stringify ( obj , replacer = null , space = null ) { if ( replacer && ( typeof replacer !== "function" && ! this . isArray ( replacer ) ) ) { throw new Error ( "Replacer must be a function or an array" ) ; } this . replacer = replacer ; this . indentStr = this . getIndent ( space ) ; this . objStack = [ ] ; var topLevelHolder = { "" : obj } ; if ( obj === undefined ) { return this . getReplacedValueOrUndefined ( topLevelHolder , "" , true ) ; } return this . internalStringify ( topLevelHolder , "" , true ) ; } private getIndent ( space ) { if ( space ) { if ( typeof space === "string" ) { return space ; } else if ( typeof space === "number" && space >= 0 ) { return this . makeIndent ( " " , space , true ) ; } } return "" ; } private getReplacedValueOrUndefined ( holder , key , isTopLevel ) { var value = holder [ key ] ; if ( value && value . toJSON && typeof value . toJSON === "function" ) { value = value . toJSON ( ) ; } if ( typeof this . replacer === "function" ) { return this . replacer . call ( holder , key , value ) ; } else if ( this . replacer ) { if ( isTopLevel || this . isArray ( holder ) || this . replacer . indexOf ( key ) >= 0 ) { return value ; } else { return undefined ; } } else { return value ; } } private isWordChar ( char ) { return ( ( char >= "a" && char <= "z" ) || ( char >= "A" && char <= "Z" ) || ( char >= "0" && char <= "9" ) || char === "_" || char === "$" ) ; } private isWordStart ( char ) { return ( ( char >= "a" && char <= "z" ) || ( char >= "A" && char <= "Z" ) || char === "_" || char === "$" ) ; } private isWord ( key ) { if ( typeof key !== "string" ) { return false ; } if ( ! this . isWordStart ( key [ 0 ] ) ) { return false ; } var i = 1 , length = key . length ; while ( i < length ) { if ( ! this . isWordChar ( key [ i ] ) ) { return false ; } i ++ ; } return true ; } private isArray ( obj ) { if ( Array . isArray ) { return Array . isArray ( obj ) ; } else { return Object . prototype . toString . call ( obj ) === "[object Array]" ; } } private isDate ( obj ) { return Object . prototype . toString . call ( obj ) === "[object Date]" ; } private isNaN ( val ) { return typeof val === "number" && val !== val ; } private checkForCircular ( obj ) { for ( var i = 0 ; i < this . objStack . length ; i ++ ) { if ( this . objStack [ i ] === obj ) { throw new TypeError ( "Converting circular structure to JSON" ) ; } } } private makeIndent ( str , num , noNewLine = false ) { if ( ! str ) { return "" ; } if ( str . length > 10 ) { str = str . substring ( 0 , 10 ) ; } var indent = noNewLine ? "" : "\n" ; for ( var i = 0 ; i < num ; i ++ ) { indent += str ; } return indent ; } private static cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g ; private static escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g ; private static meta = { "\b" : "\\b" , "\t" : "\\t" , "\n" : "\\n" , "\f" : "\\f" , "\r" : "\\r" , '"' : '\\"' , "\\" : "\\\\" } ; private escapeString ( str ) { SurveyJSON5 . escapable . lastIndex = 0 ; return SurveyJSON5 . escapable . test ( str ) ? '"' + str . replace ( SurveyJSON5 . escapable , function ( a ) { var c = SurveyJSON5 . meta [ a ] ; return typeof c === "string" ? c : "\\u" + ( "0000" + a . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 4 ) ; } ) + '"' : '"' + str + '"' ; } private internalStringify ( holder , key , isTopLevel ) { var buffer , res ; var obj_part = this . getReplacedValueOrUndefined ( holder , key , isTopLevel ) ; if ( obj_part && ! this . isDate ( obj_part ) ) { obj_part = obj_part . valueOf ( ) ; } switch ( typeof obj_part ) { case "boolean" : return obj_part . toString ( ) ; case "number" : if ( isNaN ( obj_part ) || ! isFinite ( obj_part ) ) { return "null" ; } return obj_part . toString ( ) ; case "string" : return this . escapeString ( obj_part . toString ( ) ) ; case "object" : if ( obj_part === null ) { return "null" ; } else if ( this . isArray ( obj_part ) ) { this . checkForCircular ( obj_part ) ; buffer = "[" ; this . objStack . push ( obj_part ) ; for ( var i = 0 ; i < obj_part . length ; i ++ ) { res = this . internalStringify ( obj_part , i , false ) ; buffer += this . makeIndent ( this . indentStr , this . objStack . length ) ; if ( res === null || typeof res === "undefined" ) { buffer += "null" ; } else { buffer += res ; } if ( i < obj_part . length - 1 ) { buffer += "," ; } else if ( this . indentStr ) { buffer += "\n" ; } } this . objStack . pop ( ) ; buffer += this . makeIndent ( this . indentStr , this . objStack . length , true ) + "]" ; } else { this . checkForCircular ( obj_part ) ; buffer = "{" ; var nonEmpty = false ; this . objStack . push ( obj_part ) ; for ( var prop in obj_part ) { if ( obj_part . hasOwnProperty ( prop ) ) { var value = this . internalStringify ( obj_part , prop , false ) ; isTopLevel = false ; if ( typeof value !== "undefined" && value !== null ) { buffer += this . makeIndent ( this . indentStr , this . objStack . length ) ; nonEmpty = true ; var propKey = this . isWord ( prop ) ? prop : this . escapeString ( prop ) ; buffer += propKey + ":" + ( this . indentStr ? " " : "" ) + value + "," ; } } } this . objStack . pop ( ) ; if ( nonEmpty ) { buffer = buffer . substring ( 0 , buffer . length - 1 ) + this . makeIndent ( this . indentStr , this . objStack . length ) + "}" ; } else { buffer = "{}" ; } } return buffer ; default : return undefined ; } } }