Skip to content

Instantly share code, notes, and snippets.

@isaacs
Last active April 28, 2023 17:01
Show Gist options
  • Save isaacs/ba57fca9ec16152256cba4b9b544750c to your computer and use it in GitHub Desktop.
Save isaacs/ba57fca9ec16152256cba4b9b544750c to your computer and use it in GitHub Desktop.
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mkdirp_1 = require("mkdirp");
const node_fs_1 = require("node:fs");
mkdirp_1.mkdirp;
const node_module_1 = require("node:module");
const node_path_1 = require("node:path");
const node_url_1 = require("node:url");
const rel = (p) => (0, node_path_1.relative)(process.cwd(), p);
const getLines = (f) => (0, node_fs_1.readFileSync)(f, 'utf8').split('\n');
const highlight = (lines, l, c) => {
const line = lines[l - 1];
const before = line.slice(0, c - 1);
const after = line.slice(c);
return l + ':' + c + ' | ' + before + ' >' + line.charAt(c - 1) + '< ' + after;
};
const fn = () => {
bar();
};
const bar = () => {
baz();
};
const baz = () => {
const e = new Error('trace');
Error.prepareStackTrace = (e, c) => {
return c.map((c) => {
const res = {};
const fileName = res.fileName = c.getFileName();
const lineNumber = res.lineNumber = c.getLineNumber();
const columnNumber = res.columnNumber = c.getColumnNumber();
if (fileName && lineNumber !== null && columnNumber !== null) {
const sm = (0, node_module_1.findSourceMap)(fileName, e);
if (sm) {
const payload = sm.findEntry(lineNumber, columnNumber);
if (payload) {
Object.assign(res, payload);
res.originalSource = (0, node_url_1.fileURLToPath)(res.originalSource);
const lines = getLines(res.fileName);
res.fromError = highlight(lines, res.lineNumber, res.columnNumber);
res.generated = highlight(lines, res.generatedLine, res.generatedColumn);
const oglines = getLines(res.originalSource);
res.origin = highlight(oglines, res.originalLine, res.originalColumn);
res.originalSource = rel(res.originalSource);
res.fileName = rel(res.fileName);
}
}
}
return res;
});
};
Error.captureStackTrace(e);
//@ts-ignore
console.log(e.stack.filter(c => c.originalSource));
};
fn();
//# sourceMappingURL=node-source-map-example.js.map
{"version":3,"file":"node-source-map-example.js","sourceRoot":"","sources":["node-source-map-example.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirp } from 'mkdirp'\nimport {readFileSync} from 'node:fs'\nmkdirp\nimport { findSourceMap } from 'node:module'\nimport {relative} from 'node:path'\nimport {fileURLToPath} from 'node:url'\n\nconst rel = (p: string) => relative(process.cwd(), p)\n\nconst getLines = (f: string) =>\n readFileSync(f, 'utf8').split('\\n')\n\nconst highlight = (lines: string[], l: number, c: number) => {\n const line = lines[l - 1]\n const before = line.slice(0, c - 1)\n const after = line.slice(c)\n return l + ':' + c + ' | ' + before + ' >' + line.charAt(c - 1) + '< ' + after\n}\n\n// just some stuff to be filtered out so line numbers are off more\nexport interface Something {\n foo: {\n bar: true\n baz: number\n }\n}\n\nconst fn = () => {\n bar()\n}\n\nconst bar = () => {\n baz()\n}\n\nconst baz = () => {\n const e = new Error('trace')\n Error.prepareStackTrace = (e: Error, c: NodeJS.CallSite[]) => {\n return c.map((c):Record<string, any> => {\n const res: Record<string, any> = {}\n const fileName = res.fileName = c.getFileName()\n const lineNumber = res.lineNumber = c.getLineNumber()\n const columnNumber = res.columnNumber = c.getColumnNumber()\n if (fileName && lineNumber !== null && columnNumber !== null) {\n const sm = findSourceMap(fileName, e)\n if (sm) {\n const payload = sm.findEntry(lineNumber, columnNumber)\n if (payload) {\n Object.assign(res, payload)\n res.originalSource = fileURLToPath(res.originalSource)\n const lines = getLines(res.fileName)\n res.fromError = highlight(lines, res.lineNumber, res.columnNumber)\n res.generated = highlight(lines, res.generatedLine, res.generatedColumn)\n const oglines = getLines(res.originalSource)\n res.origin = highlight(oglines, res.originalLine, res.originalColumn)\n res.originalSource = rel(res.originalSource)\n res.fileName = rel(res.fileName)\n }\n }\n }\n return res\n })\n }\n Error.captureStackTrace(e)\n //@ts-ignore\n console.log(e.stack.filter(c => c.originalSource))\n}\n\nfn()\n"]}
import { mkdirp } from 'mkdirp'
import {readFileSync} from 'node:fs'
mkdirp
import { findSourceMap } from 'node:module'
import {relative} from 'node:path'
import {fileURLToPath} from 'node:url'
const rel = (p: string) => relative(process.cwd(), p)
const getLines = (f: string) =>
readFileSync(f, 'utf8').split('\n')
const highlight = (lines: string[], l: number, c: number) => {
const line = lines[l - 1]
const before = line.slice(0, c - 1)
const after = line.slice(c)
return l + ':' + c + ' | ' + before + ' >' + line.charAt(c - 1) + '< ' + after
}
// just some stuff to be filtered out so line numbers are off more
export interface Something {
foo: {
bar: true
baz: number
}
}
const fn = () => {
bar()
}
const bar = () => {
baz()
}
const baz = () => {
const e = new Error('trace')
Error.prepareStackTrace = (e: Error, c: NodeJS.CallSite[]) => {
return c.map((c):Record<string, any> => {
const res: Record<string, any> = {}
const fileName = res.fileName = c.getFileName()
const lineNumber = res.lineNumber = c.getLineNumber()
const columnNumber = res.columnNumber = c.getColumnNumber()
if (fileName && lineNumber !== null && columnNumber !== null) {
const sm = findSourceMap(fileName, e)
if (sm) {
const payload = sm.findEntry(lineNumber, columnNumber)
if (payload) {
Object.assign(res, payload)
res.originalSource = fileURLToPath(res.originalSource)
const lines = getLines(res.fileName)
res.fromError = highlight(lines, res.lineNumber, res.columnNumber)
res.generated = highlight(lines, res.generatedLine, res.generatedColumn)
const oglines = getLines(res.originalSource)
res.origin = highlight(oglines, res.originalLine, res.originalColumn)
res.originalSource = rel(res.originalSource)
res.fileName = rel(res.fileName)
}
}
}
return res
})
}
Error.captureStackTrace(e)
//@ts-ignore
console.log(e.stack.filter(c => c.originalSource))
}
fn()
@isaacs
Copy link
Author

isaacs commented Apr 28, 2023

Output:

$ node --enable-source-maps node-source-map-example.js
[
  {
    fileName: 'node-source-map-example.js',
    lineNumber: 51,
    columnNumber: 11,
    generatedLine: 51,
    generatedColumn: 4,
    originalSource: 'node-source-map-example.ts',
    originalLine: 64,
    originalColumn: 2,
    name: undefined,
    fromError: '51:11 |     Error. >c< aptureStackTrace(e);',
    generated: '51:4 |     > < Error.captureStackTrace(e);',
    origin: '64:2 |   > < Error.captureStackTrace(e)'
  },
  {
    fileName: 'node-source-map-example.js',
    lineNumber: 21,
    columnNumber: 5,
    generatedLine: 21,
    generatedColumn: 2,
    originalSource: 'node-source-map-example.ts',
    originalLine: 33,
    originalColumn: 1,
    name: undefined,
    fromError: '21:5 |      >b< az();',
    generated: '21:2 |   > <   baz();',
    origin: '33:1 |  > <  baz()'
  },
  {
    fileName: 'node-source-map-example.js',
    lineNumber: 18,
    columnNumber: 5,
    generatedLine: 18,
    generatedColumn: 2,
    originalSource: 'node-source-map-example.ts',
    originalLine: 29,
    originalColumn: 1,
    name: undefined,
    fromError: '18:5 |      >b< ar();',
    generated: '18:2 |   > <   bar();',
    origin: '29:1 |  > <  bar()'
  },
  {
    fileName: 'node-source-map-example.js',
    lineNumber: 55,
    columnNumber: 1,
    generatedLine: 54,
    generatedColumn: 5,
    originalSource: 'node-source-map-example.ts',
    originalLine: 68,
    originalColumn: 4,
    name: undefined,
    fromError: '55:1 |  >f< n();',
    generated: '54:5 | }; >< ',
    origin: '68:4 |  >< '
  }
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment