js-slang
Version:
Javascript-based implementations of Source, written in Typescript
105 lines • 4.34 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.toSourceError = void 0;
const source_map_1 = require("source-map");
const constants_1 = require("../constants");
const errors_1 = require("../errors/errors");
const astCreator_1 = require("../utils/ast/astCreator");
var BrowserType;
(function (BrowserType) {
BrowserType["Chrome"] = "Chrome";
BrowserType["FireFox"] = "FireFox";
BrowserType["Unsupported"] = "Unsupported";
})(BrowserType || (BrowserType = {}));
const ChromeEvalErrorLocator = {
regex: /eval at.+<anonymous>:(\d+):(\d+)/gm,
browser: BrowserType.Chrome
};
const FireFoxEvalErrorLocator = {
regex: /eval:(\d+):(\d+)/gm,
browser: BrowserType.FireFox
};
const EVAL_LOCATORS = [ChromeEvalErrorLocator, FireFoxEvalErrorLocator];
const UNDEFINED_VARIABLE_MESSAGES = ['is not defined'];
// brute-forced from MDN website for phrasing of errors from different browsers
// FWIW node and chrome uses V8 so they'll have the same error messages
// unable to test on other engines
const ASSIGNMENT_TO_CONST_ERROR_MESSAGES = [
'invalid assignment to const',
'Assignment to constant variable',
'Assignment to const',
'Redeclaration of const'
];
function getBrowserType() {
const userAgent = navigator.userAgent.toLowerCase();
return userAgent.indexOf('chrome') > -1
? BrowserType.Chrome
: userAgent.indexOf('firefox') > -1
? BrowserType.FireFox
: BrowserType.Unsupported;
}
function extractErrorLocation(errorStack, lineOffset, errorLocator) {
const evalErrors = Array.from(errorStack.matchAll(errorLocator.regex));
if (evalErrors.length) {
const baseEvalError = evalErrors[0];
const [lineNumStr, colNumStr] = baseEvalError.slice(1, 3);
return { line: parseInt(lineNumStr) - lineOffset, column: parseInt(colNumStr) };
}
return undefined;
}
function getErrorLocation(error, lineOffset = 0) {
const browser = getBrowserType();
const errorLocator = EVAL_LOCATORS.find(locator => locator.browser === browser);
const errorStack = error.stack;
if (errorStack && errorLocator) {
return extractErrorLocation(errorStack, lineOffset, errorLocator);
}
else if (errorStack) {
// if browser is unsupported try all supported locators until the first success
return EVAL_LOCATORS.map(locator => extractErrorLocation(errorStack, lineOffset, locator)).find(x => x !== undefined);
}
return undefined;
}
/**
* Converts native errors to SourceError
*
* @param error
* @param sourceMap
* @returns
*/
async function toSourceError(error, sourceMap) {
const errorLocation = getErrorLocation(error);
if (!errorLocation) {
return new errors_1.ExceptionError(error, constants_1.UNKNOWN_LOCATION);
}
let { line, column } = errorLocation;
let identifier = 'UNKNOWN';
let source = null;
if (sourceMap && !(line === -1 || column === -1)) {
// Get original lines, column and identifier
const originalPosition = await source_map_1.SourceMapConsumer.with(sourceMap, null, consumer => consumer.originalPositionFor({ line, column }));
line = originalPosition.line ?? -1; // use -1 in place of null
column = originalPosition.column ?? -1;
identifier = originalPosition.name ?? identifier;
source = originalPosition.source ?? null;
}
const errorMessage = error.message;
const errorMessageContains = (possibleMessages) => possibleMessages.some(possibleMessage => errorMessage.includes(possibleMessage));
if (errorMessageContains(ASSIGNMENT_TO_CONST_ERROR_MESSAGES)) {
return new errors_1.ConstAssignment((0, astCreator_1.locationDummyNode)(line, column, source), identifier);
}
else if (errorMessageContains(UNDEFINED_VARIABLE_MESSAGES)) {
return new errors_1.UndefinedVariable(identifier, (0, astCreator_1.locationDummyNode)(line, column, source));
}
else {
const location = line === -1 || column === -1
? constants_1.UNKNOWN_LOCATION
: {
start: { line, column },
end: { line: -1, column: -1 }
};
return new errors_1.ExceptionError(error, location);
}
}
exports.toSourceError = toSourceError;
//# sourceMappingURL=errors.js.map
;