UNPKG

@soinlabs/hawk

Version:

Package to better manage errors, logs, and its notifications

192 lines (172 loc) 5.68 kB
const cleanStack = require('clean-stack') const os = require('os') const STEP_INIT_INDEX = 7 const KEYWORDS_FOR_EXCLUDING_STEPS = ['ErrorBuilder', 'node_modules'] class StepGetter { /** * It build a new stack-trace with customized format from error stack trace * @param {Error - StandardError - LoggedError} error */ constructor(error) { this.error = error this.customizedStack = [] this.stepTrace = [] this._buildCustomizeStack() this._fillStepTrace() } /** * It returns the first object from stepTrace (first excecution point) * the object contains two properties: file path and excecuted method * @return {JSON} */ getOriginStep() { const stepTrace = this.getStepTrace() let originStep = null if (stepTrace[0]) { originStep = stepTrace[0] } return originStep } /** * It returns the last object from stepTrace (last excecution point) * the object contains two properties: file path and excecuted method * @return {JSON} */ getFinalStep() { const stepTrace = this.getStepTrace() const stepTraceLength = stepTrace.length let finalStep = null if (stepTraceLength > 0) { finalStep = stepTrace[stepTraceLength - 1] } return finalStep } /** * It returns the stack trace without internal modules, the stack is cleaned * and formated into a list of objects {calledFuction:string, path:string} * @return {[JSON]} */ getStepTrace() { return this.stepTrace } /** * It returns an list of all previous called functions * that invocate an error creation * @return {[String]} */ getTracedFuctions() { const getCalledFunctions = this._getElementsFromStepTrace('calledFunction') return getCalledFunctions() } /** * It returns an list of all previous path-files * that invocate an error creation * @return {[String]} */ getTracedPaths() { const getPaths = this._getElementsFromStepTrace('path') return getPaths() } /** * It returns a list of requested properties (calledFunction or path) * from stepTrace * @param {String} requestedPropertie */ _getElementsFromStepTrace(requestedPropertie) { return () => { let elementsFromStepTrace = [] for (const element of this.stepTrace) { elementsFromStepTrace.push(element[requestedPropertie]) } return elementsFromStepTrace } } /** * It fill a list using stack trace from error, the list * contains each line (separated with \n) from error.stack * remove home directory of each line */ _buildCustomizeStack() { if (this.error && this.error.stack) { let homeDir = typeof os.homedir === 'undefined' ? '' : os.homedir() homeDir = homeDir.split('\\').join('/') // it is equivalent to homeDir.replaceAll('\\','/')... new homeDir as User/.../... let stack = cleanStack(this.error.stack) stack = stack.split(homeDir).join('~') // it is equivalent to stack.replace(/homeDir/g, '~') this._fillCustomizeStack(stack) } } /** * It takes a error.stack and obtain only usefull steps * calledFunction <space> path and put each line into a list */ _fillCustomizeStack(stack) { let linesFromStack = [] linesFromStack = stack.split('\n') for (const line of linesFromStack) { this.customizedStack.push(line.substr(STEP_INIT_INDEX)) } this.customizedStack.shift() } /** * Using filled customizedStack, it fills a list * with JSON {calledFunction, path} */ _fillStepTrace() { for (const step of this.customizedStack) { if (!this._excludeStep(step)) { this.stepTrace.push({ calledFunction: this._getFunctionFromStep(step), path: this._getPathFromStep(step), }) } } } /** * Because each line (step) from customizedStack * has the format calledFunction <space> path, then * this method split the step and get only calledFunction * if step doesn't have a path, then the function is the step * @return {String} * */ _getFunctionFromStep(step) { let functionIntoStep = null const initOfPath = step.indexOf('~') //path inits with ~ if (initOfPath > 1) { functionIntoStep = step.substr(0, initOfPath - 2) //remove 'space' and '(' } else { //if step doesn't have a path functionIntoStep = step } return functionIntoStep } /** * Because each line (step) from customizedStack * has the format calledFunction <space> path, then * this method split the step and get only path * Note: the path-file could contain spaces, thus the path could be chunked * in many parts... In this case, method join each chunck (without spaces) in only one part * @return {String} * */ _getPathFromStep(step) { //it checks if step have a path (path inits with ~) let pathIntoStep = null if (step.indexOf('~') > 0) { const stepParts = step.split(' ') // it is for divide called functions and paths (they are spletted by space) stepParts.shift() // remove first, because at the first position is the fuction //in case that the path was chunked in many parts, we join them again for (let index = 0; index < stepParts.length - 1; ++index) { stepParts[index + 1] = stepParts[index] + stepParts[index + 1] stepParts.shift() } pathIntoStep = stepParts.shift() // get first one (and only one) } return pathIntoStep } _excludeStep(step) { for (const keyWord of KEYWORDS_FOR_EXCLUDING_STEPS) { if (step.includes(keyWord)) return true } return false } } module.exports = StepGetter