UNPKG

snowpack

Version:

The ESM-powered frontend build tool. Fast, lightweight, unbundled.

75 lines (74 loc) 2.88 kB
import path from 'path'; import { SourceMapConsumer } from 'source-map'; function get_sourcemap_url(contents) { const reversed = contents.split('\n').reverse().join('\n'); const match = /\/[/*]#[ \t]+sourceMappingURL=([^\s'"]+?)(?:[ \t]+|$)/gm.exec(reversed); if (match) return match[1]; return undefined; } async function replace_async(str, regex, asyncFn) { const promises = []; str.replace(regex, (match, ...args) => { const promise = asyncFn(match, ...args); promises.push(promise); }); const data = await Promise.all(promises); return str.replace(regex, () => data.shift()); } // TODO does Snowpack compose sourcemaps, or will this only undo // the last in a series of transformations? export async function sourcemap_stacktrace(stack, load_contents) { const replace = (line) => replace_async(line, /^ {4}at (?:(.+?)\s+\()?(?:(.+?):(\d+)(?::(\d+))?)\)?/, async (input, var_name, address, line, column) => { if (!address) return input; const contents = await load_contents(address); if (!contents) return input; const sourcemap_url = get_sourcemap_url(contents); if (!sourcemap_url) return input; let dir = path.dirname(address); let sourcemap_data; if (/^data:application\/json[^,]+base64,/.test(sourcemap_url)) { const raw_data = sourcemap_url.slice(sourcemap_url.indexOf(',') + 1); try { sourcemap_data = Buffer.from(raw_data, 'base64').toString(); } catch (_a) { return input; } } else { const sourcemap_path = path.resolve(dir, sourcemap_url); const data = await load_contents(sourcemap_path); if (!data) return input; sourcemap_data = data; dir = path.dirname(sourcemap_path); } let raw_sourcemap; try { raw_sourcemap = JSON.parse(sourcemap_data); } catch (_b) { return input; } // TODO: according to typings, this code cannot work; // the constructor returns a promise that needs to be awaited const consumer = await new SourceMapConsumer(raw_sourcemap); const pos = consumer.originalPositionFor({ line: Number(line), column: Number(column), bias: SourceMapConsumer.LEAST_UPPER_BOUND, }); if (!pos.source) return input; const source_path = path.resolve(dir, pos.source); const source = `${source_path}:${pos.line || 0}:${pos.column || 0}`; if (!var_name) return ` at ${source}`; return ` at ${var_name} (${source})`; }); return (await Promise.all(stack.split('\n').map(replace))).join('\n'); }