alm
Version:
The best IDE for TypeScript
357 lines (356 loc) • 11.3 kB
JavaScript
;
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;
};
}());