'use strict'; var escapedChars = { 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', '"': '"', '/': '/', '\\': '\\' }; var A_CODE = 'a'.charCodeAt(); exports.parse = function (source, _, options) { var pointers = {}; var line = 0; var column = 0; var pos = 0; var bigint = options && options.bigint && typeof BigInt != 'undefined'; return { data: _parse('', true), pointers: pointers }; function _parse(ptr, topLevel) { whitespace(); var data; map(ptr, 'value'); var char = getChar(); switch (char) { case 't': read('rue'); data = true; break; case 'f': read('alse'); data = false; break; case 'n': read('ull'); data = null; break; case '"': data = parseString(); break; case '[': data = parseArray(ptr); break; case '{': data = parseObject(ptr); break; default: backChar(); if ('-0123456789'.indexOf(char) >= 0) data = parseNumber(); else unexpectedToken(); } map(ptr, 'valueEnd'); whitespace(); if (topLevel && pos < source.length) unexpectedToken(); return data; } function whitespace() { loop: while (pos < source.length) { switch (source[pos]) { case ' ': column++; break; case '\t': column += 4; break; case '\r': column = 0; break; case '\n': column = 0; line++; break; default: break loop; } pos++; } } function parseString() { var str = ''; var char; while (true) { char = getChar(); if (char == '"') { break; } else if (char == '\\') { char = getChar(); if (char in escapedChars) str += escapedChars[char]; else if (char == 'u') str += getCharCode(); else wasUnexpectedToken(); } else { str += char; } } return str; } function parseNumber() { var numStr = ''; var integer = true; if (source[pos] == '-') numStr += getChar(); numStr += source[pos] == '0' ? getChar() : getDigits(); if (source[pos] == '.') { numStr += getChar() + getDigits(); integer = false; } if (source[pos] == 'e' || source[pos] == 'E') { numStr += getChar(); if (source[pos] == '+' || source[pos] == '-') numStr += getChar(); numStr += getDigits(); integer = false; } var result = +numStr; return bigint && integer && (result > Number.MAX_SAFE_INTEGER || result < Number.MIN_SAFE_INTEGER) ? BigInt(numStr) : result; } function parseArray(ptr) { whitespace(); var arr = []; var i = 0; if (getChar() == ']') return arr; backChar(); while (true) { var itemPtr = ptr + '/' + i; arr.push(_parse(itemPtr)); whitespace(); var char = getChar(); if (char == ']') break; if (char != ',') wasUnexpectedToken(); whitespace(); i++; } return arr; } function parseObject(ptr) { whitespace(); var obj = {}; if (getChar() == '}') return obj; backChar(); while (true) { var loc = getLoc(); if (getChar() != '"') wasUnexpectedToken(); var key = parseString(); var propPtr = ptr + '/' + escapeJsonPointer(key); mapLoc(propPtr, 'key', loc); map(propPtr, 'keyEnd'); whitespace(); if (getChar() != ':') wasUnexpectedToken(); whitespace(); obj[key] = _parse(propPtr); whitespace(); var char = getChar(); if (char == '}') break; if (char != ',') wasUnexpectedToken(); whitespace(); } return obj; } function read(str) { for (var i=0; i= 'a' && char <= 'f') code += char.charCodeAt() - A_CODE + 10; else if (char >= '0' && char <= '9') code += +char; else wasUnexpectedToken(); } return String.fromCharCode(code); } function getDigits() { var digits = ''; while (source[pos] >= '0' && source[pos] <= '9') digits += getChar(); if (digits.length) return digits; checkUnexpectedEnd(); unexpectedToken(); } function map(ptr, prop) { mapLoc(ptr, prop, getLoc()); } function mapLoc(ptr, prop, loc) { pointers[ptr] = pointers[ptr] || {}; pointers[ptr][prop] = loc; } function getLoc() { return { line: line, column: column, pos: pos }; } function unexpectedToken() { throw new SyntaxError('Unexpected token ' + source[pos] + ' in JSON at position ' + pos); } function wasUnexpectedToken() { backChar(); unexpectedToken(); } function checkUnexpectedEnd() { if (pos >= source.length) throw new SyntaxError('Unexpected end of JSON input'); } }; exports.stringify = function (data, _, options) { if (!validType(data)) return; var wsLine = 0; var wsPos, wsColumn; var whitespace = typeof options == 'object' ? options.space : options; switch (typeof whitespace) { case 'number': var len = whitespace > 10 ? 10 : whitespace < 0 ? 0 : Math.floor(whitespace); whitespace = len && repeat(len, ' '); wsPos = len; wsColumn = len; break; case 'string': whitespace = whitespace.slice(0, 10); wsPos = 0; wsColumn = 0; for (var j=0; j= 0; } var ESC_QUOTE = /"|\\/g; var ESC_B = /[\b]/g; var ESC_F = /\f/g; var ESC_N = /\n/g; var ESC_R = /\r/g; var ESC_T = /\t/g; function quoted(str) { str = str.replace(ESC_QUOTE, '\\$&') .replace(ESC_F, '\\f') .replace(ESC_B, '\\b') .replace(ESC_N, '\\n') .replace(ESC_R, '\\r') .replace(ESC_T, '\\t'); return '"' + str + '"'; } var ESC_0 = /~/g; var ESC_1 = /\//g; function escapeJsonPointer(str) { return str.replace(ESC_0, '~0') .replace(ESC_1, '~1'); }