UNPKG

backtrace-node

Version:
245 lines 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var crypto_1 = require("crypto"); var fs = tslib_1.__importStar(require("fs")); var path = tslib_1.__importStar(require("path")); var source_scan_1 = require("source-scan"); /** * Analyse stack trace generated by exception * Create Stack Frames and find calling library/program informaiton */ var BacktraceStackTrace = /** @class */ (function () { function BacktraceStackTrace(error) { this.error = error; this.fault = true; this.name = 'main'; this.stack = []; this.sourceCodeInformation = {}; this.symbolicationPaths = new Set(); this.callingModulePath = ''; this.stackLineRe = /\s+at (.+) \((.+):(\d+):(\d+)\)/; this.requestedSourceCode = {}; this.tabWidth = 8; this.contextLineCount = 200; } BacktraceStackTrace.prototype.setSourceCodeOptions = function (tabWidth, contextLineCount) { this.tabWidth = tabWidth; this.contextLineCount = contextLineCount; }; /** * Get calling module path */ BacktraceStackTrace.prototype.getCallingModulePath = function () { if (!this.stack || this.stack.length === 0) { return undefined; } // handle a situation when every one stack frame is from node_modules if (!this.callingModulePath) { var sourceCode = this.stack.find(function (n) { return !!n.sourceCode; }); if (!sourceCode) { return undefined; } for (var key in this.requestedSourceCode) { if (this.requestedSourceCode.hasOwnProperty(key)) { if (this.requestedSourceCode[key].id === sourceCode.sourceCode) { this.callingModulePath = key; } } } } return this.callingModulePath; }; /** * Get Json data from Stack trace object */ BacktraceStackTrace.prototype.toJson = function () { return { name: this.name, fault: this.fault, stack: this.stack, }; }; /** * Get source code information */ BacktraceStackTrace.prototype.getSourceCode = function () { return this.sourceCodeInformation; }; /** * Start parsing stack frames */ BacktraceStackTrace.prototype.parseStackFrames = function (includeSymbolication) { return tslib_1.__awaiter(this, void 0, void 0, function () { var stackTrace, appPath, lines, backtracePath; var _this = this; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: stackTrace = this.error.stack; if (!stackTrace) { return [2 /*return*/]; } appPath = process.cwd(); lines = stackTrace.split('\n').slice(1); backtracePath = path.join('node_modules', 'backtrace-node'); lines.forEach(function (line) { var match = line.match(_this.stackLineRe); if (!match || match.length < 4) { return; } var fullSourceCodePath = match[2]; var backtraceLibStackFrame = fullSourceCodePath.indexOf(backtracePath) !== -1; if (backtraceLibStackFrame) { return; } var sourcePath = fullSourceCodePath; if (sourcePath) { sourcePath = path.relative(appPath, sourcePath); } var stackFrame = { funcName: match[1], path: sourcePath, line: parseInt(match[3], 10), column: parseInt(match[4], 10), }; // ignore not existing stack frames if (fs.existsSync(fullSourceCodePath)) { stackFrame.sourceCode = _this.addSourceRequest(stackFrame, fullSourceCodePath); // extend root object with symbolication information if (includeSymbolication) { _this.symbolicationPaths.add(fullSourceCodePath); } if (_this.isCallingModule(fullSourceCodePath)) { _this.callingModulePath = fullSourceCodePath; } } _this.stack.push(stackFrame); }); // read source code information after reading all existing stack frames from stack trace return [4 /*yield*/, this.readSourceCode()]; case 1: // read source code information after reading all existing stack frames from stack trace _a.sent(); if (includeSymbolication) { this.generateSymbolicationMap(); } return [2 /*return*/]; } }); }); }; BacktraceStackTrace.prototype.generateSymbolicationMap = function () { var _this = this; if (this.symbolicationPaths.size === 0) { return; } this.symbolicationMaps = []; this.symbolicationPaths.forEach(function (symbolicationPath) { return tslib_1.__awaiter(_this, void 0, void 0, function () { var file, hash; var _a; return tslib_1.__generator(this, function (_b) { file = fs.readFileSync(symbolicationPath, 'utf8'); hash = crypto_1.createHash('md5').update(file).digest('hex'); (_a = this.symbolicationMaps) === null || _a === void 0 ? void 0 : _a.push({ file: symbolicationPath, uuid: this.convertHexToUuid(hash), }); return [2 /*return*/]; }); }); }); }; BacktraceStackTrace.prototype.convertHexToUuid = function (hex) { return (hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16) + '-' + hex.slice(16, 20) + '-' + hex.slice(20, 32)); }; BacktraceStackTrace.prototype.addSourceRequest = function (stackFrame, fullPath) { // add source code to existing list. Otherwise create empty array if (!this.requestedSourceCode[fullPath]) { this.requestedSourceCode[fullPath] = { data: [], id: crypto_1.randomBytes(20).toString('hex'), }; } this.requestedSourceCode[fullPath].data.push({ line: stackFrame.line, column: stackFrame.column, }); return this.requestedSourceCode[fullPath].id; }; BacktraceStackTrace.prototype.readSourceCode = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var _a, _b, _i, key, element, minLine, maxLine, i, item, parameter, res; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: _a = []; for (_b in this.requestedSourceCode) _a.push(_b); _i = 0; _c.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 4]; key = _a[_i]; if (!this.requestedSourceCode.hasOwnProperty(key)) return [3 /*break*/, 3]; element = this.requestedSourceCode[key]; minLine = element.data[0].line; maxLine = minLine; for (i = 1; i < element.data.length; i += 1) { item = element.data[i]; minLine = Math.min(minLine, item.line); maxLine = Math.max(maxLine, item.line); } parameter = { startLine: Math.max(minLine - this.contextLineCount + 1, 0), endLine: maxLine + this.contextLineCount, filePath: key, }; return [4 /*yield*/, this.getSourceCodeInformation(parameter)]; case 2: res = _c.sent(); this.sourceCodeInformation[element.id] = res; _c.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); }; BacktraceStackTrace.prototype.getSourceCodeInformation = function (parameter) { return tslib_1.__awaiter(this, void 0, void 0, function () { var _this = this; return tslib_1.__generator(this, function (_a) { return [2 /*return*/, new Promise(function (res, rej) { source_scan_1.scanFile(parameter, function (err, buff) { if (err) { rej(err); return; } res({ startLine: parameter.startLine + 1, startColumn: 1, text: buff.toString('utf8'), tabWidth: _this.tabWidth, }); }); })]; }); }); }; BacktraceStackTrace.prototype.isCallingModule = function (sourcePath) { return !!sourcePath && !this.callingModulePath && !sourcePath.includes('node_modules'); }; return BacktraceStackTrace; }()); exports.BacktraceStackTrace = BacktraceStackTrace; //# sourceMappingURL=backtraceStackTrace.js.map