Comparing version 1.2.7 to 2.0.0
401
index.js
@@ -5,5 +5,6 @@ 'use strict' | ||
var path = require('path') | ||
var semver = require('semver') | ||
var callsites = require('error-callsites') | ||
var afterAll = require('after-all') | ||
var asyncCache = require('async-cache') | ||
var afterAll = require('after-all-results') | ||
var errorCallsites = require('error-callsites') | ||
var loadSourceMap = require('load-source-map') | ||
var debug = require('debug')('stackman') | ||
@@ -13,181 +14,291 @@ | ||
var syncCache = require('lru-cache')({ max: 500 }) | ||
var asyncCache = require('async-cache')({ | ||
max: 500, | ||
load: function (file, cb) { | ||
debug('reading ' + file) | ||
fs.readFile(file, READ_FILE_OPTS, cb) | ||
} | ||
}) | ||
var LINES_OF_CONTEXT = 7 | ||
var READ_FILE_OPTS = semver.lt(process.version, '0.9.11') ? 'utf8' : { encoding: 'utf8' } | ||
var ESCAPED_REGEX_PATH_SEP = path.sep === '/' ? '/' : '\\\\' | ||
var MODULE_FOLDER_REGEX = new RegExp('.*node_modules' + ESCAPED_REGEX_PATH_SEP + '([^' + ESCAPED_REGEX_PATH_SEP + ']*)') | ||
module.exports = function (opts) { | ||
if (opts instanceof Error) throw new Error('Stackman not initialized yet. Please do so first and parse the error to the returned function instead') | ||
module.exports = function stackman (opts) { | ||
if (!opts) opts = {} | ||
var linesOfContext = opts.context || LINES_OF_CONTEXT | ||
var sync = opts.sync | ||
var stackFilter | ||
if (opts.filter === undefined) { | ||
// noop | ||
} else if (typeof opts.filter === 'string') { | ||
stackFilter = function (callsite) { | ||
var filename = callsite.getFileName() | ||
return filename ? filename.indexOf(opts.filter) === -1 : true | ||
var fileCache = asyncCache({ | ||
max: opts.fileCacheMax || 500, | ||
load: function (file, cb) { | ||
debug('reading %s', file) | ||
fs.readFile(file, {encoding: 'utf8'}, cb) | ||
} | ||
} else if (Array.isArray(opts.filter)) { | ||
stackFilter = function (callsite) { | ||
var path = callsite.getFileName() | ||
return !opts.filter.some(function (segment) { | ||
return path.indexOf(segment) !== -1 | ||
}) | ||
var sourceMapCache = asyncCache({ | ||
max: opts.sourceMapCacheMax || 100, | ||
load: function (file, cb) { | ||
debug('loading source map for %s', file) | ||
loadSourceMap(file, cb) | ||
} | ||
}) | ||
return { | ||
callsites: callsites, | ||
properties: properties, | ||
sourceContexts: sourceContexts | ||
} | ||
function callsites (err, opts, cb) { | ||
if (typeof opts === 'function') return callsites(err, null, opts) | ||
var _callsites = errorCallsites(err) | ||
if (!validStack(_callsites)) { | ||
process.nextTick(function () { | ||
cb(new Error('Could not process callsites')) | ||
}) | ||
} else if (!opts || opts.sourcemap !== false) { | ||
sourcemapify(_callsites, function (err) { | ||
if (err) return cb(err) | ||
_callsites.forEach(extendCallsite) | ||
cb(null, _callsites) | ||
}) | ||
} else { | ||
_callsites.forEach(extendCallsite) | ||
process.nextTick(function () { | ||
cb(null, _callsites) | ||
}) | ||
} | ||
} | ||
var parseLines = function (lines, callsite) { | ||
var lineno = callsite.getLineNumber() | ||
return { | ||
pre: lines.slice(Math.max(0, lineno - (linesOfContext + 1)), lineno - 1), | ||
line: lines[lineno - 1], | ||
post: lines.slice(lineno, lineno + linesOfContext) | ||
function properties (err) { | ||
var properties = {} | ||
Object.keys(err).forEach(function (key) { | ||
if (key === 'stack') return // 'stack' seems to be enumerable in Node 0.11 | ||
var val = err[key] | ||
if (val === null) return // null is typeof object and well break the switch below | ||
switch (typeof val) { | ||
case 'function': | ||
return | ||
case 'object': | ||
// ignore all objects except Dates | ||
if (typeof val.toISOString !== 'function') return | ||
val = val.toISOString() | ||
} | ||
properties[key] = val | ||
}) | ||
return properties | ||
} | ||
function sourceContexts (callsites, opts, cb) { | ||
if (typeof opts === 'function') return sourceContexts(callsites, null, opts) | ||
if (!opts) opts = {} | ||
var next = afterAll(cb) | ||
callsites.forEach(function (callsite) { | ||
if (callsite.isNode()) { | ||
next()(null, null) | ||
} else { | ||
callsite.sourceContext(opts, next()) | ||
} | ||
}) | ||
} | ||
function validStack (callsites) { | ||
return Array.isArray(callsites) && | ||
typeof callsites[0] === 'object' && | ||
typeof callsites[0].getFileName === 'function' | ||
} | ||
function getRelativeFileName () { | ||
var filename = this.getFileName() | ||
if (!filename) return | ||
var root = process.cwd() | ||
if (root[root.length - 1] !== path.sep) root += path.sep | ||
return !~filename.indexOf(root) ? filename : filename.substr(root.length) | ||
} | ||
function getTypeNameSafely () { | ||
try { | ||
return this.getTypeName() | ||
} catch (e) { | ||
// This seems to happen sometimes when using 'use strict', | ||
// stemming from `getTypeName`. | ||
// [TypeError: Cannot read property 'constructor' of undefined] | ||
return null | ||
} | ||
} | ||
return function (err, cb) { | ||
var stack = callsites(err) | ||
function getFunctionNameSanitized () { | ||
var fnName = this.getFunctionName() | ||
if (fnName) return fnName | ||
var typeName = this.getTypeNameSafely() | ||
if (typeName) return typeName + '.' + (this.getMethodName() || '<anonymous>') | ||
return '<anonymous>' | ||
} | ||
if (stackFilter && Array.isArray(stack)) stack = stack.filter(stackFilter) | ||
function getModuleName () { | ||
var filename = this.getFileName() || '' | ||
var match = filename.match(MODULE_FOLDER_REGEX) | ||
return match ? match[1] : null | ||
} | ||
var result = { | ||
properties: getProperties(err), | ||
frames: stack | ||
function isApp () { | ||
return !this.isNode() && !~(this.getFileName() || '').indexOf('node_modules' + path.sep) | ||
} | ||
function isModule () { | ||
return !!~(this.getFileName() || '').indexOf('node_modules' + path.sep) | ||
} | ||
function isNode () { | ||
if (this.isNative()) return true | ||
var filename = this.getFileName() || '' | ||
return (!isAbsolute(filename) && filename[0] !== '.') | ||
} | ||
function sourceContext (opts, cb) { | ||
if (typeof opts === 'function') { | ||
cb = opts | ||
opts = {} | ||
} | ||
if (!sync) { | ||
var next = afterAll(function () { | ||
cb(result) | ||
if (this.isNode()) { | ||
process.nextTick(function () { | ||
cb(new Error('Can\'t get source context of a Node core callsite')) | ||
}) | ||
return | ||
} | ||
if (!validStack(stack)) return sync ? result : undefined | ||
var callsite = this | ||
var filename = this.getFileName() || '' | ||
var source = this.sourcemap | ||
? this.sourcemap.sourceContentFor(filename, true) | ||
: null | ||
stack.forEach(function (callsite) { | ||
callsite.getRelativeFileName = getRelativeFileName.bind(callsite) | ||
callsite.getTypeNameSafely = getTypeNameSafely.bind(callsite) | ||
callsite.getFunctionNameSanitized = getFunctionNameSanitized.bind(callsite) | ||
callsite.getModuleName = getModuleName.bind(callsite) | ||
callsite.isApp = isApp.bind(callsite) | ||
callsite.isModule = isModule.bind(callsite) | ||
callsite.isNode = isNode.bind(callsite) | ||
if (source) { | ||
process.nextTick(function () { | ||
cb(null, parseSource(source, callsite, opts)) | ||
}) | ||
} else { | ||
fileCache.get(filename, function (err, source) { | ||
if (err) { | ||
debug('error reading %s: %s', filename, err.message) | ||
cb(err) | ||
} else { | ||
cb(null, parseSource(source, callsite, opts)) | ||
} | ||
}) | ||
} | ||
} | ||
if (callsite.isNode()) return // internal Node files are not full path names. Ignore them. | ||
function parseSource (source, callsite, opts) { | ||
var lines = source.split(/\r?\n/) | ||
var linesOfContext = opts.lines || LINES_OF_CONTEXT | ||
var lineno = callsite.getLineNumber() | ||
return { | ||
pre: lines.slice(Math.max(0, lineno - (linesOfContext + 1)), lineno - 1), | ||
line: lines[lineno - 1], | ||
post: lines.slice(lineno, lineno + linesOfContext) | ||
} | ||
} | ||
var filename = callsite.getFileName() || '' | ||
function sourcemapify (callsites, cb) { | ||
var next = afterAll(function (err, consumers) { | ||
if (err) return cb(err) | ||
if (!sync) { | ||
var done = next() | ||
asyncCache.get(filename, function (err, data) { | ||
if (err) { | ||
debug('error reading ' + filename + ': ' + err.message) | ||
} else { | ||
data = data.split(/\r?\n/) | ||
callsite.context = parseLines(data, callsite) | ||
} | ||
done() | ||
consumers.forEach(function (consumer, index) { | ||
if (!consumer) return | ||
Object.defineProperty(callsites[index], 'sourcemap', { | ||
writable: true, | ||
value: consumer | ||
}) | ||
} else if (syncCache.has(filename)) { | ||
callsite.context = parseLines(syncCache.get(filename), callsite) | ||
} else { | ||
debug('reading ' + filename) | ||
try { | ||
var data = fs.readFileSync(filename, READ_FILE_OPTS) | ||
} catch (e) { | ||
debug('error reading ' + filename + ': ' + e.message) | ||
return | ||
} | ||
data = data.split(/\r?\n/) | ||
syncCache.set(filename, data) | ||
callsite.context = parseLines(data, callsite) | ||
} | ||
}) | ||
cb() | ||
}) | ||
return sync ? result : undefined | ||
callsites.forEach(function (callsite) { | ||
getSourceMapConsumer(callsite, next()) | ||
}) | ||
} | ||
} | ||
var validStack = function (stack) { | ||
return Array.isArray(stack) && | ||
typeof stack[0] === 'object' && | ||
typeof stack[0].getFileName === 'function' | ||
} | ||
var getRelativeFileName = function () { | ||
var filename = this.getFileName() | ||
if (!filename) return | ||
var root = process.cwd() | ||
if (root[root.length - 1] !== path.sep) root += path.sep | ||
return !~filename.indexOf(root) ? filename : filename.substr(root.length) | ||
} | ||
var getTypeNameSafely = function () { | ||
try { | ||
return this.getTypeName() | ||
} catch (e) { | ||
// This seems to happen sometimes when using 'use strict', | ||
// stemming from `getTypeName`. | ||
// [TypeError: Cannot read property 'constructor' of undefined] | ||
return null | ||
function getSourceMapConsumer (callsite, cb) { | ||
if (isNode.call(callsite)) return process.nextTick(cb) | ||
var filename = callsite.getFileName() | ||
sourceMapCache.get(filename, cb) | ||
} | ||
} | ||
var getFunctionNameSanitized = function () { | ||
var fnName = this.getFunctionName() | ||
if (fnName) return fnName | ||
var typeName = this.getTypeNameSafely() | ||
if (typeName) return typeName + '.' + (this.getMethodName() || '<anonymous>') | ||
return '<anonymous>' | ||
} | ||
function extendCallsite (callsite) { | ||
var getLineNumber = callsite.getLineNumber | ||
var getColumnNumber = callsite.getColumnNumber | ||
var getFileName = callsite.getFileName | ||
var position = null | ||
var properties = { | ||
getRelativeFileName: { | ||
writable: true, | ||
value: getRelativeFileName | ||
}, | ||
getTypeNameSafely: { | ||
writable: true, | ||
value: getTypeNameSafely | ||
}, | ||
getFunctionNameSanitized: { | ||
writable: true, | ||
value: getFunctionNameSanitized | ||
}, | ||
getModuleName: { | ||
writable: true, | ||
value: getModuleName | ||
}, | ||
isApp: { | ||
writable: true, | ||
value: isApp | ||
}, | ||
isModule: { | ||
writable: true, | ||
value: isModule | ||
}, | ||
isNode: { | ||
writable: true, | ||
value: isNode | ||
}, | ||
sourceContext: { | ||
writable: true, | ||
value: sourceContext | ||
} | ||
} | ||
var getModuleName = function () { | ||
var filename = this.getFileName() || '' | ||
var match = filename.match(MODULE_FOLDER_REGEX) | ||
if (match) return match[1] | ||
} | ||
if (callsite.sourcemap) { | ||
properties.getFileName = { | ||
writable: true, | ||
value: function () { | ||
var filename = getFileName.call(callsite) | ||
var sourceFile = getPosition().source | ||
if (!sourceFile) return filename | ||
var sourceDir = path.dirname(filename) | ||
return path.resolve(path.join(sourceDir, sourceFile)) | ||
} | ||
} | ||
properties.getLineNumber = { | ||
writable: true, | ||
value: function () { | ||
return getPosition().line || getLineNumber.call(callsite) | ||
} | ||
} | ||
properties.getColumnNumber = { | ||
writable: true, | ||
value: function () { | ||
return getPosition().column || getColumnNumber.call(callsite) | ||
} | ||
} | ||
} | ||
var isApp = function () { | ||
return !this.isNode() && !~(this.getFileName() || '').indexOf('node_modules' + path.sep) | ||
} | ||
Object.defineProperties(callsite, properties) | ||
var isModule = function () { | ||
return !!~(this.getFileName() || '').indexOf('node_modules' + path.sep) | ||
} | ||
function getPosition () { | ||
if (!position) { | ||
position = callsite.sourcemap.originalPositionFor({ | ||
line: getLineNumber.call(callsite), | ||
column: getColumnNumber.call(callsite) | ||
}) | ||
} | ||
var isNode = function () { | ||
if (this.isNative()) return true | ||
var filename = this.getFileName() || '' | ||
return (!isAbsolute(filename) && filename[0] !== '.') | ||
} | ||
var getProperties = function (err) { | ||
var properties = {} | ||
Object.keys(err).forEach(function (key) { | ||
if (key === 'stack') return // 'stack' seems to be enumerable in Node 0.11 | ||
var val = err[key] | ||
if (val === null) return // null is typeof object and well break the switch below | ||
switch (typeof val) { | ||
case 'function': | ||
return | ||
case 'object': | ||
// ignore all objects except Dates | ||
if (typeof val.toISOString !== 'function') return | ||
val = val.toISOString() | ||
return position | ||
} | ||
properties[key] = val | ||
}) | ||
return properties | ||
} | ||
} |
{ | ||
"name": "stackman", | ||
"version": "1.2.7", | ||
"version": "2.0.0", | ||
"description": "Enhance an error stacktrace with code excerpts and other goodies", | ||
"main": "index.js", | ||
"dependencies": { | ||
"after-all": "^2.0.2", | ||
"after-all-results": "^2.0.0", | ||
"async-cache": "^1.1.0", | ||
"debug": "^2.2.0", | ||
"error-callsites": "^1.0.1", | ||
"lru-cache": "^4.0.1", | ||
"path-is-absolute": "^1.0.1", | ||
"semver": "^5.3.0" | ||
"load-source-map": "^1.0.0", | ||
"path-is-absolute": "^1.0.1" | ||
}, | ||
"devDependencies": { | ||
"longjohn": "=0.2.9", | ||
"standard": "^8.5.0", | ||
"semver": "^5.3.0", | ||
"standard": "^9.0.2", | ||
"tape": "^4.6.2" | ||
}, | ||
"scripts": { | ||
"test": "standard && tape test/test.js && tape test/longjohn.js" | ||
"test": "standard && node test/strict.js && node test/non-strict.js && node test/longjohn.js && node test/sourcemap.js" | ||
}, | ||
@@ -34,2 +34,4 @@ "repository": { | ||
"callsites", | ||
"frame", | ||
"source", | ||
"debug", | ||
@@ -47,5 +49,10 @@ "log", | ||
"coordinates": [ | ||
55.6809887, | ||
12.5643973 | ||
] | ||
55.6809959, | ||
12.5644639 | ||
], | ||
"standard": { | ||
"ignore": [ | ||
"/test/fixtures/" | ||
] | ||
} | ||
} |
331
README.md
@@ -13,2 +13,3 @@ # Stackman | ||
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard) | ||
[![sponsor](https://img.shields.io/badge/sponsored%20by-Opbeat-3360A3.svg)](https://opbeat.com) | ||
@@ -24,15 +25,15 @@ ## Install | ||
```javascript | ||
var stackman = require('stackman')(); | ||
var stackman = require('stackman')() | ||
var err = new Error('Oops!'); | ||
var err = new Error('Oops!') | ||
stackman(err, function (stack) { | ||
stack.frames.forEach(function (frame) { | ||
// output: <example.js:3> var err = new Error('Oops!'); | ||
console.log('<%s:%s> %s', | ||
frame.getFileName(), | ||
frame.getLineNumber(), | ||
frame.context.line); | ||
}); | ||
}); | ||
stackman.callsites(err, function (err, callsites) { | ||
if (err) throw err | ||
callsites.forEach(function (callsite) { | ||
console.log('Error occured in at %s line %d', | ||
callsite.getFileName(), | ||
callsite.getLineNumber()) | ||
}) | ||
}) | ||
``` | ||
@@ -44,120 +45,244 @@ | ||
This works because V8 (the JavaScript engine behind Node.js) allows us | ||
to hook into the stack trace generator function before that stack trace | ||
is generated. It's triggered by accessing the `.stack` property on the | ||
Error object, so please don't do that before parsing the error to | ||
stackman, else this will not work! | ||
This module works because V8 (the JavaScript engine behind Node.js) | ||
allows us to hook into the stack trace generator function before that | ||
stack trace is generated. It's triggered by accessing the `.stack` | ||
property on the Error object, so please don't do that before parsing the | ||
error to stackman, else this will not work! | ||
If you want to output the regular stack trace, just do so after parsing | ||
it to stackman: | ||
the callsites: | ||
```javascript | ||
// first call stackman with the error | ||
stackman(err, ...); | ||
// first call stackman.callsites with the error | ||
stackman.callsites(err, function () {...}) | ||
// then you can print out the stack trace | ||
console.log(err.stack); | ||
console.log(err.stack) | ||
``` | ||
## API | ||
## Stackman API | ||
### Module | ||
### `var stackman = Stackman([options])` | ||
Parse options to the main stackman function to customize the default | ||
behavior: | ||
This module exposes a single function which you must call to get a | ||
`stackman` object. | ||
```javascript | ||
var options = { | ||
context: 5, | ||
filter: '/node_modules/my-module/' | ||
} | ||
var stackman = require('stackman')(options) | ||
``` | ||
The function takes an optional options object as its only argument. | ||
These are the available options: | ||
- `fileCacheMax` - When source files are read from disk, they are kept | ||
in memory in an LRU cache to speed up processing of future errors. You | ||
can change the max number of files kept in the LRU cache using this | ||
property (default: 500) | ||
- `sourceMapCacheMax` - When source maps are read from disk, the | ||
processed source maps are kept in memory in an LRU cache to speed up | ||
processing of future errors. You can change the max number of source | ||
maps kept in the LRU cache using this property (default: 100) | ||
### `stackman.callsites(err[, options], callback)` | ||
Given an error object, this function will call the `callback` with an | ||
optional error as the first argument and an array of | ||
[CallSite](#callsite-api) objects as the 2nd (a call site is a frame in | ||
the stack trace). | ||
Options: | ||
- `context` - Number of lines of context to be loaded on each side of | ||
the callsite line (default: `7`) | ||
- `filter` - Accepts a single path segment or an array of path segments. | ||
Will filter out any stack frames that matches the given path segments. | ||
- `sync` - Set to `true` if you want stackman to behave synchronously. | ||
If set, the result will be returned and the callback will be ignored | ||
(default: `false`) | ||
- `sourcemap` - A boolean specifying if Stackman should look for an | ||
process source maps (default: `true`) | ||
The `stackman` function takes two arguments: | ||
### `var properties = stackman.properties(err)` | ||
- `err` - the error to be parsed | ||
- `callback` - a callback which will be called with the a stack object | ||
when the parsing is completed | ||
Given an error object, this function will return an object containing | ||
all the custom properties from the original error object (beside date | ||
objects, properties of type `object` and `function` are not included in | ||
this object). | ||
#### The `stack` object: | ||
### `stackman.sourceContexts(callsites[, options], callback)` | ||
The callback given to the `stackman` function is called with a stack | ||
object when the parsing is completed. The `stack` object have two | ||
important properties: | ||
Convenience function to get the source context for all call sites in the | ||
`callsites` argument in one go (instead of iterating over the call sites | ||
and calling | ||
[`callsite.sourceContext()`](#callsitesourcecontextoptions-callback) for | ||
each of them). | ||
- `properties` - An object containing all the custom properties from the | ||
original error object (properties of type `object` and `function` are | ||
not included in this object) | ||
- `frames` - An array of stack-frames, also called callsite objects | ||
Calls the `callback` with an optional error object as the first argument | ||
and an array of [source context objects](#source-context) as the 2nd. | ||
Each element in the context array matches a call site in the `callsites` | ||
array. The optional `options` object will be passed on to | ||
[`callsite.sourceContext()`](#callsitesourcecontextoptions-callback). | ||
### Callsite | ||
All node core call sites will have the context value `null`. | ||
#### Custom properties | ||
## CallSite API | ||
- `callsite.context.pre` - The lines before the main callsite line | ||
- `callsite.context.line` - The main callsite line | ||
- `callsite.context.post` - The lines after the main callsite line | ||
A CallSite object is an object provided by the [V8 stack trace | ||
API](https://github.com/v8/v8/wiki/Stack-Trace-API) representing a frame | ||
in the stack trace. Stackman will decorate each CallSite object with | ||
custom functions and behavior. | ||
#### Custom methods | ||
### `callsite.sourcemap` | ||
- `callsite.getTypeNameSafely()` - A safer version of | ||
`callsite.getTypeName()` as this safely handles an exception that | ||
sometimes is thrown when using `"use strict"`. Otherwise it returns | ||
the type of this as a string. This is the name of the function stored | ||
in the constructor field of this, if available, otherwise the object's | ||
[[Class]] internal property | ||
- `callsite.getRelativeFileName()` - Returns a filename realtive to `process.cwd()` | ||
- `callsite.getFunctionNameSanitized()` - Guaranteed to always return | ||
the most meaningful function name. If none can be determined, the | ||
string `<anonymous>` will be returned | ||
- `callsite.getModuleName()` - Returns the name of the module if | ||
`isModule()` is true | ||
- `callsite.isApp()` - Is this inside the app? (i.e. not native, not | ||
node code and not a module inside the node_modules directory) | ||
- `callsite.isModule()` - Is this inside the node_modules directory? | ||
- `callsite.isNode()` - Is this inside node core? | ||
If source map support is enabled and a source map have been found for | ||
the CallSite, this property will be a reference to a | ||
[`SourceMapConsumer`](https://github.com/mozilla/source-map#sourcemapconsumer) | ||
object representing the given CallSite. | ||
#### Methods inherited from V8 | ||
If set, all functions on the CallSite object will be source map aware. | ||
I.e. their return values will be related to the original source code and | ||
not the transpiled source code. | ||
The follwoing methods are inherited from the [V8 stack trace | ||
API](https://code.google.com/p/v8-wiki/wiki/JavaScriptStackTraceApi). | ||
### `var val = callsite.getThis()` | ||
- `callsite.getThis()` - returns the value of this | ||
- `callsite.getTypeName()` - returns the type of this as a string. This | ||
is the name of the function stored in the constructor field of this, | ||
if available, otherwise the object's [[Class]] internal property. | ||
- `callsite.getFunction()` - returns the current function | ||
- `callsite.getFunctionName()` - returns the name of the current | ||
function, typically its name property. If a name property is not | ||
available an attempt will be made to try to infer a name from the | ||
function's context. | ||
- `callsite.getMethodName()` - returns the name of the property of this | ||
or one of its prototypes that holds the current function | ||
- `callsite.getFileName()` - if this function was defined in a script | ||
returns the name of the script | ||
- `callsite.getLineNumber()` - if this function was defined in a script | ||
returns the current line number | ||
- `callsite.getColumnNumber()` - if this function was defined in a | ||
script returns the current column number | ||
- `callsite.getEvalOrigin()` - if this function was created using a call | ||
to eval returns a CallSite object representing the location where eval | ||
was called | ||
- `callsite.isToplevel()` - is this a toplevel invocation, that is, is | ||
this the global object? | ||
- `callsite.isEval()` - does this call take place in code defined by a | ||
call to eval? | ||
- `callsite.isNative()` - is this call in native V8 code? | ||
- `callsite.isConstructor()` - is this a constructor call? | ||
_Inherited from V8_ | ||
Returns the value of `this`. | ||
To maintain restrictions imposed on strict mode functions, frames that | ||
have a strict mode function and all frames below (its caller etc.) are | ||
not allow to access their receiver and function objects. For those | ||
frames, `getThis()` will return `undefined`. | ||
### `var str = callsite.getTypeName()` | ||
_Inherited from V8_ | ||
Returns the type of `this` as a string. This is the name of the function | ||
stored in the constructor field of `this`, if available, otherwise the | ||
object's `[[Class]]` internal property. | ||
### `var str = callsite.getTypeNameSafely()` | ||
A safer version of | ||
[`callsite.getTypeName()`](#var-str--callsitegettypename) that safely | ||
handles an exception that sometimes is thrown when using `"use strict"` | ||
in which case `null` is returned. | ||
### `var fn = callsite.getFunction()` | ||
_Inherited from V8_ | ||
Returns the current function. | ||
To maintain restrictions imposed on strict mode functions, frames that | ||
have a strict mode function and all frames below (its caller etc.) are | ||
not allow to access their receiver and function objects. For those | ||
frames, `getFunction()` will return `undefined`. | ||
### `var str = callsite.getFunctionName()` | ||
_Inherited from V8_ | ||
Returns the name of the current function, typically its name property. | ||
If a name property is not available an attempt will be made to try to | ||
infer a name from the function's context. | ||
### `var str = callsite.getFunctionNameSanitized()` | ||
Guaranteed to always return the most meaningful function name. If none | ||
can be determined, the string `<anonymous>` will be returned. | ||
### `var str = callsite.getMethodName()` | ||
_Inherited from V8_ | ||
Returns the name of the property of this or one of its prototypes that | ||
holds the current function. | ||
### `var str = callsite.getFileName()` | ||
_Inherited from V8 if `callsite.sourcemap` is `undefined`_ | ||
If this function was defined in a script returns the name of the script. | ||
### `var str = callsite.getRelativeFileName()` | ||
Returns a filename realtive to `process.cwd()`. | ||
### `var num = callsite.getLineNumber()` | ||
_Inherited from V8 if `callsite.sourcemap` is `undefined`_ | ||
If this function was defined in a script returns the current line | ||
number. | ||
### `var num = callsite.getColumnNumber()` | ||
_Inherited from V8 if `callsite.sourcemap` is `undefined`_ | ||
If this function was defined in a script returns the current column | ||
number. | ||
### `var str = callsite.getEvalOrigin()` | ||
_Inherited from V8_ | ||
If this function was created using a call to eval returns a CallSite | ||
object representing the location where eval was called. | ||
### `var str = callsite.getModuleName()` | ||
Returns the name of the module if `isModule()` is `true`. Otherwise | ||
returns `null`. | ||
### `var bool = callsite.isToplevel()` | ||
_Inherited from V8_ | ||
Is this a toplevel invocation, that is, is this the global object? | ||
### `var bool = callsite.isEval()` | ||
_Inherited from V8_ | ||
Does this call take place in code defined by a call to eval? | ||
### `var bool = callsite.isNative()` | ||
_Inherited from V8_ | ||
Is this call in native V8 code? | ||
### `var bool = callsite.isConstructor()` | ||
_Inherited from V8_ | ||
Is this a constructor call? | ||
### `var bool = callsite.isApp()` | ||
Is this inside the app? (i.e. not native, not node code and not a module | ||
inside the `node_modules` directory) | ||
### `var bool = callsite.isModule()` | ||
Is this inside the `node_modules` directory? | ||
### `var bool = callsite.isNode()` | ||
Is this inside node core? | ||
### `callsite.sourceContext([options, ]callback)` | ||
Calls the `callback` with an optional error object as the first argument | ||
and a [source context object](#source-context) as the 2nd. | ||
If the `callsite` is a node core call site, the `callback` will be | ||
called with an error. | ||
Options: | ||
- `lines` - Number of lines of soruce context to be loaded on each side | ||
of the call site line (default: `7`) | ||
## Source Context | ||
The source context objects provided by | ||
[`callsite.sourceContext`](#callsitesourcecontextoptions-callback) | ||
contains the following properties: | ||
- `pre` - The lines before the main callsite line | ||
- `line` - The main callsite line | ||
- `post` - The lines after the main callsite line | ||
## Troubleshooting | ||
@@ -167,4 +292,8 @@ | ||
## Acknowledgements | ||
This project was kindly sponsored by [Opbeat](https://opbeat.com). | ||
## License | ||
MIT |
@@ -5,8 +5,9 @@ 'use strict' | ||
var test = require('tape') | ||
var Stackman = require('../') | ||
var stackman = require('../')() | ||
test('longjohn, regular error', function (t) { | ||
var err = new Error('foo') | ||
Stackman()(err, function (stack) { | ||
t.ok(stack.frames.length > 0, 'should have stack frames') | ||
stackman.callsites(err, function (err, callsites) { | ||
t.error(err) | ||
t.ok(callsites.length > 0, 'should have stack frames') | ||
t.end() | ||
@@ -20,4 +21,5 @@ }) | ||
} catch (err) { | ||
Stackman()(err, function (stack) { | ||
t.ok(stack.frames.length > 0, 'should have stack frames') | ||
stackman.callsites(err, function (err, callsites) { | ||
t.error(err) | ||
t.ok(callsites.length > 0, 'should have stack frames') | ||
t.end() | ||
@@ -24,0 +26,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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
35251
6
12
708
296
4
1
+ Addedafter-all-results@^2.0.0
+ Addedload-source-map@^1.0.0
+ Addedafter-all-results@2.0.0(transitive)
+ Addedin-publish@2.0.1(transitive)
+ Addedload-source-map@1.0.0(transitive)
+ Addedsource-map@0.5.7(transitive)
- Removedafter-all@^2.0.2
- Removedlru-cache@^4.0.1
- Removedsemver@^5.3.0
- Removedafter-all@2.0.2(transitive)
- Removedonce@1.4.0(transitive)
- Removedwrappy@1.0.2(transitive)