backtracker
Advanced tools
Comparing version 3.2.1 to 3.3.0
@@ -32,1 +32,2 @@ "use strict"; | ||
module.exports = Frame; | ||
//# sourceMappingURL=Frame.js.map |
@@ -7,11 +7,2 @@ import Frame from "./Frame"; | ||
static get stack(): Stack; | ||
/** | ||
* Process an Array of strings from an Error stack. The strings must be trimmed as the regular expressions specify string start and end. | ||
* You can easily get what's required for this by doing the example provided. | ||
* | ||
* The slice is necessary because the Error name and message is included in the first line of the stack | ||
* @param withParentReferences If each stack frame should have references to the previous frame added to itself | ||
* @example BackTracker.process(new Error().stack.split("\n").slice(1).map(i => i.trim())) | ||
*/ | ||
static process(frames: Array<string>, withParentReferences?: boolean): Stack; | ||
} | ||
@@ -18,0 +9,0 @@ declare const _default: { |
@@ -7,8 +7,2 @@ "use strict"; | ||
const Stack_1 = __importDefault(require("./Stack")); | ||
const [evalreg, anonymousreg, pallreg, scopereg] = [ | ||
/^at eval \(eval a?t? ?([\w_\.<>]+)? ?\((?:file\:\/\/\/)?([^*"\)]+):(\d+):(\d+)\),? ?([\w_\.<>]+)?:\d+:\d+\)$/, | ||
/^at ([\w_\.<>]+)? ?\(?(<anonymous>)\)?$/, | ||
/^at (?:async)? ?Promise.all \(index (\d+)\)$/, | ||
/^at (async)? ?((?!\bfile\b|[A-Z]:)[\w_\.<> ]+)? ?(?:\[as ([\w_\.<> ]+)\])? ?\(?(?:file\:\/\/\/)?([^*"]+):(\d+):(\d+)\)?$/, // expression for named and unnamed scopes including functions that were renamed as well as getters | ||
]; | ||
class BackTracker { | ||
@@ -20,51 +14,33 @@ parent; | ||
static get stack() { | ||
const stack = new Error().stack; | ||
if (!stack) { | ||
const stackframes = new Stack_1.default(); | ||
stackframes.push(new Frame_1.default({ path: __dirname || "backtracker:internal/index", async: false, scope: "stack", line: 22, column: 7, anonymous: false })); | ||
return stackframes; | ||
} | ||
const split = stack.split("\n"); | ||
const frames = split.slice(3).map(item => item.trim()); // slice out the first 3 lines which is the Error message, BackTracker's frame, and the current frame which leaves you with the previous as the current is known | ||
return BackTracker.process(frames); | ||
} | ||
/** | ||
* Process an Array of strings from an Error stack. The strings must be trimmed as the regular expressions specify string start and end. | ||
* You can easily get what's required for this by doing the example provided. | ||
* | ||
* The slice is necessary because the Error name and message is included in the first line of the stack | ||
* @param withParentReferences If each stack frame should have references to the previous frame added to itself | ||
* @example BackTracker.process(new Error().stack.split("\n").slice(1).map(i => i.trim())) | ||
*/ | ||
static process(frames, withParentReferences = true) { | ||
const stackframes = new Stack_1.default(); | ||
for (const frame of frames) { | ||
const test1 = evalreg.exec(frame); | ||
if (test1 && test1.length) { | ||
stackframes.push(new Frame_1.default({ path: test1[2], async: false, scope: test1[1], line: Number(test1[3]), column: Number(test1[4]), anonymous: (!!test1[5] && test1[5].includes("<anonymous>")) })); | ||
const _ = Error.prepareStackTrace; | ||
Error.prepareStackTrace = (_, stack) => stack; | ||
const { stack } = new Error(); | ||
Error.prepareStackTrace = _; | ||
const es = stack || []; | ||
const s = new Stack_1.default(); | ||
let isFirst = true; | ||
for (const c of es) { | ||
if (isFirst) { // Ignore BackTracker's stack frame | ||
isFirst = false; | ||
continue; | ||
} | ||
const test2 = anonymousreg.exec(frame); | ||
if (test2 && test2.length) { | ||
stackframes.push(new Frame_1.default({ path: test2[2], async: false, scope: test2[1], line: 0, column: 0, anonymous: true })); | ||
continue; | ||
} | ||
const test3 = pallreg.exec(frame); | ||
if (test3 && test3.length) { | ||
stackframes.push(new Frame_1.default({ path: "node:v8/promise-all", async: true, scope: `Promise.all index ${test3[1] || 0}`, line: 0, column: 0, anonymous: false })); | ||
continue; | ||
} | ||
const test4 = scopereg.exec(frame); | ||
if (test4 && test4.length) { | ||
stackframes.push(new Frame_1.default({ path: test4[4], async: !!test4[1], scope: test4[2] ? `${test4[2].trim()}${test4[3] ? `as ${test4[3]}` : ""}` : "unknown", line: Number(test4[5]), column: Number(test4[6]), anonymous: (!!test4[2] && test4[2].includes("<anonymous>")) })); | ||
continue; | ||
} | ||
const scope = c.isPromiseAll() | ||
? "Promise.all" | ||
: c.getFunctionName() || null; | ||
const filename = c.getFileName(); | ||
const frame = new Frame_1.default({ | ||
path: c.getEvalOrigin() || filename || "<anonymous>", | ||
async: c.isAsync(), | ||
scope: scope || "<anonymous>", | ||
line: c.getLineNumber() || 0, | ||
column: c.getColumnNumber() || 0, | ||
anonymous: !filename || !scope | ||
}); | ||
s.push(frame); | ||
} | ||
if (withParentReferences) { | ||
for (const f of stackframes) { | ||
const index = stackframes.indexOf(f); | ||
f.parent = stackframes[index + 1] || null; | ||
} | ||
for (const f of s) { | ||
const index = s.indexOf(f); | ||
f.parent = s[index + 1] || null; | ||
} | ||
return stackframes; | ||
return s; | ||
} | ||
@@ -77,1 +53,2 @@ } | ||
}; | ||
//# sourceMappingURL=index.js.map |
@@ -22,1 +22,2 @@ "use strict"; | ||
module.exports = Stack; | ||
//# sourceMappingURL=Stack.js.map |
{ | ||
"name": "backtracker", | ||
"version": "3.2.1", | ||
"version": "3.3.0", | ||
"description": "Back track in JS code execution and find where a function was called", | ||
@@ -5,0 +5,0 @@ "main": "dist/index", |
104
README.md
@@ -7,7 +7,3 @@ # BackTracker | ||
# How it works | ||
In JavaScript, you can make use of Error stacks to peek back into code execution. This project makes use of Error stacks and analyses individual stack frames and tries it's best to pick apart the scope, absolute path of file, line and column of each frame via regular expressions so that this info is available in code rather than requiring a user to analyse the stack. | ||
# Contributing | ||
If you would like to contribute and modify the regular expressions, please open a Pull Request and I will test code changes against a dataset of stack frames I have and including stack frames which you might want to add support for. | ||
In JavaScript, you can make use of Error stacks to peek back into code execution. This project abuses Error stacks and Error formatting. Previous versions used ugly and long regular expressions which were not infallible. | ||
# Examples | ||
@@ -44,29 +40,89 @@ | ||
Frame { | ||
path: 'C:\\Users\\papi\\Documents\\GitHub\\BackTracker\\example\\index.js', | ||
dir: 'C:\\Users\\papi\\Documents\\GitHub\\BackTracker\\example', | ||
filename: 'index.js', | ||
path: 'A:\\Windows\\Documents\\GitHub\\BackTracker\\example\\test.js', | ||
dir: 'A:\\Windows\\Documents\\GitHub\\BackTracker\\example', | ||
filename: 'test.js', | ||
async: false, | ||
scope: 'notEpic', | ||
scope: 'epic', | ||
line: 5, | ||
column: 2, | ||
column: 50, | ||
anonymous: false, | ||
parent: Frame { | ||
path: 'C:\\Users\\papi\\Documents\\GitHub\\BackTracker\\example\\index.js', | ||
dir: 'C:\\Users\\papi\\Documents\\GitHub\\BackTracker\\example', | ||
path: 'A:\\Windows\\Documents\\GitHub\\BackTracker\\example\\index.js', | ||
dir: 'A:\\Windows\\Documents\\GitHub\\BackTracker\\example', | ||
filename: 'index.js', | ||
async: false, | ||
scope: 'Object.<anonymous>', | ||
line: 8, | ||
column: 1, | ||
anonymous: true, | ||
scope: 'notEpic', | ||
line: 5, | ||
column: 2, | ||
anonymous: false, | ||
parent: Frame { | ||
path: 'node:internal/modules/cjs/loader', | ||
dir: 'node:internal/modules/cjs', | ||
filename: 'loader', | ||
path: 'A:\\Windows\\Documents\\GitHub\\BackTracker\\example\\index.js', | ||
dir: 'A:\\Windows\\Documents\\GitHub\\BackTracker\\example', | ||
filename: 'index.js', | ||
async: false, | ||
scope: 'Module._compile', | ||
line: 1095, | ||
column: 14, | ||
anonymous: false, | ||
parent: [Frame] | ||
scope: '<anonymous>', | ||
line: 8, | ||
column: 1, | ||
anonymous: true, | ||
parent: Frame { | ||
path: 'node:internal/modules/cjs/loader', | ||
dir: 'node:internal/modules/cjs', | ||
filename: 'loader', | ||
async: false, | ||
scope: 'Module._compile', | ||
line: 1120, | ||
column: 14, | ||
anonymous: false, | ||
parent: Frame { | ||
path: 'node:internal/modules/cjs/loader', | ||
dir: 'node:internal/modules/cjs', | ||
filename: 'loader', | ||
async: false, | ||
scope: 'Module._extensions..js', | ||
line: 1174, | ||
column: 10, | ||
anonymous: false, | ||
parent: Frame { | ||
path: 'node:internal/modules/cjs/loader', | ||
dir: 'node:internal/modules/cjs', | ||
filename: 'loader', | ||
async: false, | ||
scope: 'Module.load', | ||
line: 998, | ||
column: 32, | ||
anonymous: false, | ||
parent: Frame { | ||
path: 'node:internal/modules/cjs/loader', | ||
dir: 'node:internal/modules/cjs', | ||
filename: 'loader', | ||
async: false, | ||
scope: 'Module._load', | ||
line: 839, | ||
column: 12, | ||
anonymous: false, | ||
parent: Frame { | ||
path: 'node:internal/modules/run_main', | ||
dir: 'node:internal/modules', | ||
filename: 'run_main', | ||
async: false, | ||
scope: 'executeUserEntryPoint', | ||
line: 81, | ||
column: 12, | ||
anonymous: false, | ||
parent: Frame { | ||
path: 'node:internal/main/run_main_module', | ||
dir: 'node:internal/main', | ||
filename: 'run_main_module', | ||
async: false, | ||
scope: '<anonymous>', | ||
line: 17, | ||
column: 47, | ||
anonymous: true, | ||
parent: null | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -73,0 +129,0 @@ } |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
34576
14
130
196