85 lines
2.2 KiB
JavaScript
85 lines
2.2 KiB
JavaScript
'use strict'
|
|
|
|
const { SourceMapConsumer } = require('source-map')
|
|
|
|
module.exports = function stackTraceMapper (stack, map) {
|
|
if (!(map instanceof SourceMapConsumer)) {
|
|
throw new Error('map is not a consumer')
|
|
}
|
|
|
|
const setups = [
|
|
{
|
|
// settings for Chrome, Edge and IE (Plus?)
|
|
regex: /\s+at(?:\s+([^\s]+))?\s\(?([/a-z0-9:.-]+):([0-9]+):([0-9]+)/,
|
|
// regex: /\s+at(?:\s+([^)]+))?\s\(?([/a-z0-9:.-]+):([0-9]+):([0-9]+)/,
|
|
skip: 1,
|
|
split: /\n?(?= at )/,
|
|
},
|
|
|
|
{
|
|
// settings for Firefox and Safari
|
|
regex: /([a-zA-Z0-9]*)@(.*):([0-9]+):([0-9]+)/,
|
|
skip: 0,
|
|
split: /\s+/,
|
|
},
|
|
]
|
|
|
|
const setup = setups.find((setup) => {
|
|
return setup.regex.test(stack)
|
|
})
|
|
|
|
if (!setup) {
|
|
throw new Error('Stack trace is not recognised')
|
|
}
|
|
|
|
const split = stack.trim().split(setup.split)
|
|
// TODO whether the error name and similar preludes the stack varies between browsers perhaps we should create one
|
|
const pre = split.slice(0, setup.skip)
|
|
console.log('split', split)
|
|
console.log('pre', pre)
|
|
|
|
const lines = split.slice(setup.skip).map((source) => {
|
|
// TODO handle lines that have not matched
|
|
const match = source.match(setup.regex)
|
|
|
|
if (!match) {
|
|
return { source }
|
|
}
|
|
|
|
const [ , fnc, file, line, column ] = match
|
|
|
|
return { fnc, file, line: parseInt(line), column: parseInt(column), source }
|
|
})
|
|
|
|
const originalLines = lines.map((obj) => {
|
|
if (obj.line) {
|
|
return map.originalPositionFor({ line: obj.line, column: obj.column })
|
|
}
|
|
|
|
return obj
|
|
})
|
|
|
|
// need to do research as to why, but the original line objects returned
|
|
// contain the function call names are shifted one line compared with
|
|
// the sourcemapped stack printed in chrome dev tools
|
|
const adjustedLines = originalLines.map((obj, index, arr) => {
|
|
if (obj.line) {
|
|
const prev = arr[index + 1]
|
|
|
|
obj.name = (prev && prev.name) || undefined
|
|
}
|
|
|
|
return obj
|
|
})
|
|
|
|
return pre.concat(adjustedLines.map(formatLine))
|
|
}
|
|
|
|
function formatLine ({ source, line, column, name = '(unknown)' }) {
|
|
if (!line || !column) {
|
|
return ` ${source}`
|
|
}
|
|
|
|
return ` at ${name} (${source}:${line}:${column})`
|
|
}
|