UNPKG

big-json-viewer

Version:

JavaScript Library to view big JSON structures.

465 lines 16.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var utils_1 = require("../helpers/utils"); var BRACE_START = '{'.charCodeAt(0); var BRACE_END = '}'.charCodeAt(0); var BRACKET_START = '['.charCodeAt(0); var BRACKET_END = ']'.charCodeAt(0); var COLON = ':'.charCodeAt(0); var COMMA = ','.charCodeAt(0); var DOUBLE_QUOTE = '"'.charCodeAt(0); var SINGLE_QUOTE = "'".charCodeAt(0); var SPACE = ' '.charCodeAt(0); var TAB = '\t'.charCodeAt(0); var NEWLINE = '\n'.charCodeAt(0); var BACKSPACE = '\b'.charCodeAt(0); var CARRIAGE_RETURN = '\r'.charCodeAt(0); var FORM_FEED = '\f'.charCodeAt(0); var BACK_SLASH = '\\'.charCodeAt(0); var FORWARD_SLASH = '/'.charCodeAt(0); var MINUS = '-'.charCodeAt(0); var PLUS = '+'.charCodeAt(0); var DOT = '.'.charCodeAt(0); var CHAR_E_LOW = 'e'.charCodeAt(0); var CHAR_E_HIGH = 'E'.charCodeAt(0); var DIGIT_0 = '0'.charCodeAt(0); var DIGIT_9 = '9'.charCodeAt(0); var IGNORED = [SPACE, TAB, NEWLINE, CARRIAGE_RETURN]; var NULL = 'null'.split('').map(function (d) { return d.charCodeAt(0); }); var TRUE = 'true'.split('').map(function (d) { return d.charCodeAt(0); }); var FALSE = 'false'.split('').map(function (d) { return d.charCodeAt(0); }); var BufferJsonNodeInfo = /** @class */ (function () { function BufferJsonNodeInfo(parser, index, path) { this.path = []; this.parser = parser; this.index = index; this.path = path; } /** * Returns the list of keys in case of an object for the defined range * @param {number} start * @param {number} limit */ BufferJsonNodeInfo.prototype.getObjectKeys = function (start, limit) { if (start === void 0) { start = 0; } if (this.type !== 'object') { throw new Error("Unsupported method on non-object " + this.type); } utils_1.assertStartLimit(start, limit); var ctx = { path: this.path, objectKeys: [], start: start, limit: limit }; this.parser.parseObject(this.index, ctx); return ctx.objectKeys; }; /** * Return the NodeInfo at the defined position. * Use the index from getObjectKeys * @param index */ BufferJsonNodeInfo.prototype.getByIndex = function (index) { if (this.type === 'object') { var nodes = this.getObjectNodes(index, 1); if (nodes.length) { return nodes[0]; } } if (this.type === 'array') { var nodes = this.getArrayNodes(index, 1); if (nodes.length) { return nodes[0]; } } return undefined; }; /** * Return the NodeInfo for the specified key * Use the index from getObjectKeys * @param key */ BufferJsonNodeInfo.prototype.getByKey = function (key) { if (this.type === 'object') { var ctx = { path: this.path, objectKey: key }; this.parser.parseObject(this.index, ctx); return ctx.objectNodes ? ctx.objectNodes[0] : undefined; } if (this.type === 'array') { return this.getByIndex(parseInt(key)); } return undefined; }; /** * Find the information for a given path * @param {string[]} path */ BufferJsonNodeInfo.prototype.getByPath = function (path) { if (!path) { return undefined; } if (!path.length) { return this; } var p = path.slice(); var key; var node = this; while ((key = p.shift()) !== undefined && node) { node = node.getByKey(key); } return node; }; /** * Returns a list with the NodeInfo objects for the defined range * @param {number} start * @param {number} limit */ BufferJsonNodeInfo.prototype.getObjectNodes = function (start, limit) { if (start === void 0) { start = 0; } if (this.type !== 'object') { throw new Error("Unsupported method on non-object " + this.type); } utils_1.assertStartLimit(start, limit); var ctx = { path: this.path, objectNodes: [], start: start, limit: limit }; this.parser.parseObject(this.index, ctx); return ctx.objectNodes; }; /** * Returns a list of NodeInfo for the defined range * @param {number} start * @param {number} limit */ BufferJsonNodeInfo.prototype.getArrayNodes = function (start, limit) { if (start === void 0) { start = 0; } if (this.type !== 'array') { throw new Error("Unsupported method on non-array " + this.type); } utils_1.assertStartLimit(start, limit); var ctx = { path: this.path, arrayNodes: [], start: start, limit: limit }; this.parser.parseArray(this.index, ctx); return ctx.arrayNodes; }; /** * Get the natively parsed value */ BufferJsonNodeInfo.prototype.getValue = function () { return this.parser.parseNative(this.index, this.index + this.chars); }; return BufferJsonNodeInfo; }()); exports.BufferJsonNodeInfo = BufferJsonNodeInfo; /** * Parses meta data about a JSON structure in an ArrayBuffer. */ var BufferJsonParser = /** @class */ (function () { function BufferJsonParser(data) { if (data instanceof ArrayBuffer) { this.data = new Uint16Array(data); } else if (typeof data === 'string' && typeof TextEncoder !== 'undefined') { this.data = new TextEncoder().encode(data); } else if (typeof data === 'string') { this.data = new Uint16Array(new ArrayBuffer(data.length * 2)); for (var i = 0; i < data.length; i++) { this.data[i] = data.charCodeAt(i); } } } BufferJsonParser.prototype.getRootNodeInfo = function () { var start = this.skipIgnored(0); var ctx = { path: [], nodeInfo: new BufferJsonNodeInfo(this, start, []) }; var end = this.parseValue(start, ctx, false); if (start === end) { return null; } return ctx.nodeInfo; }; BufferJsonParser.prototype.parseValue = function (start, ctx, throwUnknown) { if (throwUnknown === void 0) { throwUnknown = true; } var char = this.data[start]; if (isString(char)) { return this.parseString(start, ctx); } if (isNumber(char)) { return this.parseNumber(start, ctx); } if (char === BRACE_START) { return this.parseObject(start, ctx); } if (char === BRACKET_START) { return this.parseArray(start, ctx); } if (char === TRUE[0]) { return this.parseToken(start, TRUE, ctx); } if (char === FALSE[0]) { return this.parseToken(start, FALSE, ctx); } if (char === NULL[0]) { return this.parseToken(start, NULL, ctx); } if (throwUnknown) { throw new Error("parse value unknown token " + bufToString(char) + " at " + start); } function isString(char) { return char === DOUBLE_QUOTE || char === SINGLE_QUOTE; } function isNumber(char) { return char === MINUS || (char >= DIGIT_0 && char <= DIGIT_9); } }; BufferJsonParser.prototype.parseObject = function (start, ctx) { var index = start + 1; // skip the start brace var length = 0; var keys = []; var nodes = []; while (index <= this.data.length) { if (index === this.data.length) { throw new Error("parse object incomplete at end"); } index = this.skipIgnored(index); if (this.data[index] === BRACE_END) { index++; break; } var keyCtx = getKeyContext(length); index = this.parseString(index, keyCtx); if (keyCtx && ctx && ctx.objectKeys) { keys.push(keyCtx.value); } index = this.skipIgnored(index); if (this.data[index] !== COLON) { throw new Error("parse object unexpected token " + bufToString(this.data[index]) + " at " + index + ". Expected :"); } else { index++; } index = this.skipIgnored(index); var valueCtx = null; if (keyCtx && ctx && (ctx.objectNodes || keyCtx.value === ctx.objectKey)) { valueCtx = { path: ctx.path, nodeInfo: new BufferJsonNodeInfo(this, index, ctx.path.concat([ keyCtx.value ])) }; } index = this.parseValue(index, valueCtx); index = this.skipIgnored(index); if (valueCtx && ctx.objectNodes) { nodes.push(valueCtx.nodeInfo); } else if (valueCtx && ctx.objectKey !== undefined) { ctx.objectNodes = [valueCtx.nodeInfo]; return; } length++; if (this.data[index] === COMMA) { index++; } else if (this.data[index] !== BRACE_END) { throw new Error("parse object unexpected token " + bufToString(this.data[index]) + " at " + index + ". Expected , or }"); } } if (ctx && ctx.nodeInfo) { ctx.nodeInfo.type = 'object'; ctx.nodeInfo.length = length; ctx.nodeInfo.chars = index - start; } if (ctx && ctx.objectKeys) { ctx.objectKeys = keys; } if (ctx && ctx.objectNodes) { ctx.objectNodes = nodes; } function getKeyContext(keyIndex) { if (!ctx || (ctx.start && keyIndex < ctx.start) || (ctx.limit && keyIndex >= ctx.start + ctx.limit)) { return null; } if (ctx && (ctx.objectKeys || ctx.objectNodes || ctx.objectKey !== undefined)) { return { path: ctx.path, value: null }; } return null; } return index; }; BufferJsonParser.prototype.parseArray = function (start, ctx) { var index = start + 1; // skip the start bracket var length = 0; while (index <= this.data.length) { if (index === this.data.length) { throw new Error("parse array incomplete at end"); } index = this.skipIgnored(index); if (this.data[index] === BRACKET_END) { index++; break; } var valueCtx = null; if (isInRange(length) && ctx.arrayNodes) { valueCtx = { path: ctx.path, nodeInfo: new BufferJsonNodeInfo(this, index, ctx.path.concat([ length.toString() ])) }; } index = this.parseValue(index, valueCtx); if (valueCtx) { ctx.arrayNodes.push(valueCtx.nodeInfo); } index = this.skipIgnored(index); length++; if (this.data[index] === COMMA) { index++; } else if (this.data[index] !== BRACKET_END) { throw new Error("parse array unexpected token " + bufToString(this.data[index]) + " at " + index + ". Expected , or ]"); } } if (ctx && ctx.nodeInfo) { ctx.nodeInfo.type = 'array'; ctx.nodeInfo.length = length; ctx.nodeInfo.chars = index - start; } function isInRange(keyIndex) { return !(!ctx || (ctx.start && keyIndex < ctx.start) || (ctx.limit && keyIndex >= ctx.start + ctx.limit)); } return index; }; BufferJsonParser.prototype.parseString = function (start, ctx) { var index = start; var expect = this.data[index] === DOUBLE_QUOTE ? DOUBLE_QUOTE : SINGLE_QUOTE; var esc = false, length = 0; for (index++; index <= this.data.length; index++) { if (index === this.data.length) { throw new Error("parse string incomplete at end"); } if (!esc && this.data[index] === expect) { index++; break; } if (this.data[index] === BACK_SLASH) { esc = !esc; } else { esc = false; } if (!esc) { length++; } } if (ctx && ctx.nodeInfo) { ctx.nodeInfo.type = 'string'; ctx.nodeInfo.length = length; ctx.nodeInfo.chars = index - start; } if (ctx && ctx.value !== undefined) { ctx.value = JSON.parse(bufToString(this.data.subarray(start, index))); } return index; }; BufferJsonParser.prototype.parseNumber = function (start, ctx) { var i = start; if (this.data[i] === MINUS) { i++; } i = this.parseDigits(i); if (this.data[i] === DOT) { i++; i = this.parseDigits(i); } if (this.data[i] === CHAR_E_HIGH || this.data[i] === CHAR_E_LOW) { i++; if (this.data[i] === PLUS || this.data[i] === MINUS) { i++; } i = this.parseDigits(i); } if (ctx && ctx.nodeInfo) { ctx.nodeInfo.type = 'number'; ctx.nodeInfo.chars = i - start; } if (ctx && ctx.value !== undefined) { ctx.value = JSON.parse(bufToString(this.data.subarray(start, i))); } return i; }; BufferJsonParser.prototype.parseDigits = function (start) { while (this.data[start] >= DIGIT_0 && this.data[start] <= DIGIT_9) { start++; } return start; }; BufferJsonParser.prototype.parseToken = function (start, chars, ctx) { var index = start; for (var i = 0; i < chars.length; i++) { if (this.data[index] !== chars[i]) { throw new Error("Unexpected token " + bufToString(this.data[index]) + " at " + index + ". Expected " + bufToString(chars)); } index++; } var token = bufToString(this.data.subarray(start, index)); if (ctx && ctx.nodeInfo) { if (token === 'null') { ctx.nodeInfo.type = 'null'; } else { ctx.nodeInfo.type = 'boolean'; } ctx.nodeInfo.chars = index - start; } if (ctx && ctx.value !== undefined) { ctx.value = JSON.parse(token); } return index; }; BufferJsonParser.prototype.parseNative = function (start, end) { return JSON.parse(bufToString(this.data.subarray(start, end))); }; BufferJsonParser.prototype.skipIgnored = function (start) { for (var i = start; i < this.data.length; i++) { if (IGNORED.indexOf(this.data[i]) !== -1) { continue; } return i; } }; return BufferJsonParser; }()); exports.BufferJsonParser = BufferJsonParser; function bufToString(buf) { if (typeof buf === 'number') { buf = [buf]; } return String.fromCharCode.apply(null, buf); } //# sourceMappingURL=buffer-json-parser.js.map