UNPKG

alm

Version:

The best IDE for TypeScript

357 lines (356 loc) 11.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var ts = require("typescript"); /** * Remove the comments from a json like text. * Comments can be single line comments (starting with # or //) or multiline comments using / * * / * * This method replace comment content by whitespace rather than completely remove them to keep positions in json parsing error reporting accurate. */ function removeComments(jsonText) { var output = ""; var scanner = ts.createScanner(ts.ScriptTarget.ES5, /* skipTrivia */ false, ts.LanguageVariant.Standard, jsonText); var token; while ((token = scanner.scan()) !== ts.SyntaxKind.EndOfFileToken) { switch (token) { case ts.SyntaxKind.SingleLineCommentTrivia: case ts.SyntaxKind.MultiLineCommentTrivia: // replace comments with whitespace to preserve original character positions output += scanner.getTokenText().replace(/\S/g, " "); break; default: output += scanner.getTokenText(); break; } } return output; } /** * Over JSON.parse: * * allows BOM * * allows // /* # comments * * provides a typed error detail on parse error */ function parse(str) { var content = removeComments(stripBOM(str)); try { return { data: json_parse(content) }; } catch (e) { var error = e; var indexToPosition = function (index) { var beforeLines = splitlines(content.substr(0, index)); return { line: Math.max(beforeLines.length - 1, 0), ch: Math.max(beforeLines[beforeLines.length - 1].length - 1, 0) }; }; var fromIndex = Math.max(error.at - 1, 0); var toIndex = Math.min(error.at + 1, content.length); return { error: { message: e.message, from: indexToPosition(fromIndex), to: indexToPosition(toIndex), preview: content.substring(fromIndex, toIndex - 1) } }; } } exports.parse = parse; function stringify(object, eol) { if (eol === void 0) { eol = '\n'; } var cache = []; var value = JSON.stringify(object, // fixup circular reference function (key, value) { if (typeof value === 'object' && value !== null) { if (cache.indexOf(value) !== -1) { // Circular reference found, discard key return; } // Store value in our collection cache.push(value); } return value; }, // indent 2 spaces 2); value = value.split('\n').join(eol) + eol; cache = null; return value; } exports.stringify = stringify; function parseErrorToCodeError(filePath, error, source) { return { source: source, filePath: filePath, from: error.from, to: error.to, message: error.message, preview: error.preview, level: 'error' }; } exports.parseErrorToCodeError = parseErrorToCodeError; function stripBOM(str) { // Catches EFBBBF (UTF-8 BOM) because the buffer-to-string // conversion translates it to FEFF (UTF-16 BOM) if (typeof str === 'string' && str.charCodeAt(0) === 0xFEFF) { return str.slice(1); } return str; } function splitlines(string) { return string.split(/\r\n?|\n/); } ; /** * https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js * AS IT IS. ONLY MODIFIED WITH TYPE ASSERTSIONS / ANNOTATIONS */ var json_parse = (function () { "use strict"; // This is a function that can parse a JSON text, producing a JavaScript // data structure. It is a simple, recursive descent parser. It does not use // eval or regular expressions, so it can be used as a model for implementing // a JSON parser in other languages. // We are defining the function inside of another function to avoid creating // global variables. var at, // The index of the current character ch, // The current character escapee = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' }, text, error = function (m) { // Call error when something is wrong. throw { name: 'SyntaxError', message: m, at: at, text: text }; }, next = function (c) { // If a c parameter is provided, verify that it matches the current character. if (c && c !== ch) { error("Expected '" + c + "' instead of '" + ch + "'"); } // Get the next character. When there are no more characters, // return the empty string. ch = text.charAt(at); at += 1; return ch; }, number = function () { // Parse a number value. var number, string = ''; if (ch === '-') { string = '-'; next('-'); } while (ch >= '0' && ch <= '9') { string += ch; next(); } if (ch === '.') { string += '.'; while (next() && ch >= '0' && ch <= '9') { string += ch; } } if (ch === 'e' || ch === 'E') { string += ch; next(); if (ch === '-' || ch === '+') { string += ch; next(); } while (ch >= '0' && ch <= '9') { string += ch; next(); } } number = +string; if (!isFinite(number)) { error("Bad number"); } else { return number; } }, string = function () { // Parse a string value. var hex, i, string = '', uffff; // When parsing for string values, we must look for " and \ characters. if (ch === '"') { while (next()) { if (ch === '"') { next(); return string; } if (ch === '\\') { next(); if (ch === 'u') { uffff = 0; for (i = 0; i < 4; i += 1) { hex = parseInt(next(), 16); if (!isFinite(hex)) { break; } uffff = uffff * 16 + hex; } string += String.fromCharCode(uffff); } else if (typeof escapee[ch] === 'string') { string += escapee[ch]; } else { break; } } else { string += ch; } } } error("Bad string"); }, white = function () { // Skip whitespace. while (ch && ch <= ' ') { next(); } }, word = function () { // true, false, or null. switch (ch) { case 't': next('t'); next('r'); next('u'); next('e'); return true; case 'f': next('f'); next('a'); next('l'); next('s'); next('e'); return false; case 'n': next('n'); next('u'); next('l'); next('l'); return null; } error("Unexpected '" + ch + "'"); }, value, // Place holder for the value function. array = function () { // Parse an array value. var array = []; if (ch === '[') { next('['); white(); if (ch === ']') { next(']'); return array; // empty array } while (ch) { array.push(value()); white(); if (ch === ']') { next(']'); return array; } next(','); white(); } } error("Bad array"); }, object = function () { // Parse an object value. var key, object = {}; if (ch === '{') { next('{'); white(); if (ch === '}') { next('}'); return object; // empty object } while (ch) { key = string(); white(); next(':'); if (Object.hasOwnProperty.call(object, key)) { error('Duplicate key "' + key + '"'); } object[key] = value(); white(); if (ch === '}') { next('}'); return object; } next(','); white(); } } error("Bad object"); }; value = function () { // Parse a JSON value. It could be an object, an array, a string, a number, // or a word. white(); switch (ch) { case '{': return object(); case '[': return array(); case '"': return string(); case '-': return number(); default: return ch >= '0' && ch <= '9' ? number() : word(); } }; // Return the json_parse function. It will have access to all of the above // functions and variables. return function (source, reviver) { var result; text = source; at = 0; ch = ' '; result = value(); white(); if (ch) { error("Syntax error"); } // If there is a reviver function, we recursively walk the new structure, // passing each name/value pair to the reviver function for possible // transformation, starting with a temporary root object that holds the result // in an empty key. If there is not a reviver function, we simply return the // result. 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; }; }());