You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
core/src/parse-stacktrace.js

112 lines
2.4 KiB
JavaScript

"use strict";
// FIXME: Move this into its own package!
const execall = require("execall");
const defaultValue = require("default-value");
// I'm so, so sorry...
let lineRegex = /\s+at\s+(?:(?:((?:[^\[\n])+)\[as ([^\]]+)\] |((?:[^\(\n])+))\(([^\)\n]+)\)|([^\n]+))(?:\n|$)/gm;
let geckoLineRegex = /^([^@\n]*)@(.+)/gm;
let positionRegex = /(.+):(\d+):(\d+)/;
function maybeTrim(value) {
if (value != null) {
let trimmed = value.trim();
if (trimmed.length > 0) {
return trimmed;
} else {
return null;
}
} else {
return value;
}
}
function parseLocation(locationString) {
if (locationString === "<anonymous>") {
return { anonymous: true };
} else {
let match = positionRegex.exec(locationString);
if (match != null) {
return {
path: match[1],
line: parseInt(match[2]),
column: parseInt(match[3])
};
} else {
throw new Error(`Could not parse location from string: ${locationString}`);
}
}
}
function extractFramesV8(stack) {
let matches = execall(lineRegex, stack);
if (matches.length > 0) {
return matches.map((match) => {
let groups = match.subMatches;
return {
functionName: maybeTrim(defaultValue(groups[0], groups[2])),
alias: groups[1],
location: parseLocation(defaultValue(groups[3], groups[4]))
};
});
} else {
return null;
}
}
function extractFramesGecko(stack) {
let matches = execall(geckoLineRegex, stack);
if (matches.length > 0) {
return matches.map((match) => {
let groups = match.subMatches;
return {
functionName: maybeTrim(groups[0]),
location: parseLocation(groups[1])
};
});
} else {
return null;
}
}
function extractFrames(stack) {
// TODO: Maybe make this code even more cautious, and match each stacktrace line individually, aborting as soon as any one line cannot be parsed?
return defaultValue(
extractFramesV8(stack),
extractFramesGecko(stack)
);
}
module.exports = function parseStackTrace(error) {
let stack = error.stack;
let lines = stack.split("\n");
let firstStackLine = lines
.map((line) => line.trim())
.findIndex((line) => positionRegex.test(line));
if (firstStackLine !== -1) {
let cleanStack = lines
.slice(firstStackLine)
.join("\n");
let extracted = extractFrames(cleanStack);
if (extracted != null) {
return extracted;
} else {
throw new Error(`Could not extract stacktrace frames`);
}
} else {
throw new Error(`Could not find a stacktrace frame`);
}
};