New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

stacktracey

Package Overview
Dependencies
Maintainers
2
Versions
141
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stacktracey - npm Package Compare versions

Comparing version 1.2.127 to 2.0.1

4

package.json
{
"name": "stacktracey",
"version": "1.2.127",
"version": "2.0.1",
"description": "Parses call stacks. Reads sources. Clean & filtered output. Sourcemaps. Node & browsers.",

@@ -87,4 +87,4 @@ "main": "stacktracey",

"as-table": "^1.0.36",
"get-source": "^1.0.42"
"get-source": "^2.0.8"
}
}

@@ -33,3 +33,3 @@ # StackTracey

```javascript
StackTracey = require ('stacktracey')
import StackTracey from 'stacktracey'
```

@@ -46,12 +46,11 @@

```javascript
stack = new StackTracey (error) // parses error.stack
stack = new StackTracey (error.stack) // raw string
stack = new StackTracey (error)
stack = new StackTracey (error.stack) // ...or from raw string
```
It is an array instance:
Stores parsed data in `.items`:
```javascript
stack instanceof Array // returns true
stack.length // num entries
stack[0] // top
stack.items.length // num entries
stack.items[0] // top
```

@@ -84,4 +83,4 @@

```javascript
stack = stack.withSources // will return a copy of stack with all items supplied with sources
top = stack[0] // top item
stack = stack.withSources () // returns a copy of stack with all items supplied with sources
top = stack.items[0] // top item
```

@@ -92,3 +91,3 @@

```javascript
top = stack.withSource (0) // supplies source for an individiual item
top = stack.withSourceAt (0) // supplies source for an individiual item (by index)
```

@@ -99,6 +98,6 @@

```javascript
top = StackTracey.withSource (stack[0]) // supplies source for an individiual item
top = stack.withSource (stack.items[0]) // supplies source for an individiual item
```
It will return an item supplied with the source code info (already mapped through sourcemaps):
The returned items contain the following additional fields (already mapped through sourcemaps):

@@ -121,24 +120,35 @@ ```javascript

```javascript
stack = stack.withSources.clean
stack = stack.clean ()
```
1. Excludes locations marked with the `isThirdParty` flag (library calls)
2. Excludes locations marked with a `// @hide` comment (user defined exclusion)
3. Merges repeated lines (via the `.mergeRepeatedLines`)
It does the following:
You can augment the global `isThirdParty` predicate with new rules:
1. Reads sources (if available)
2. Excludes locations marked with the `isThirdParty` flag (library calls)
3. Excludes locations marked with a `// @hide` comment (user defined exclusion)
4. Merges repeated lines (via the `.mergeRepeatedLines`)
```javascript
StackTracey.isThirdParty.include (path => path.includes ('my-lib')) // paths including 'my-lib' will be marked as thirdParty
## Custom `isThirdParty` Predicate
You can override the `isThirdParty` behavior by subclassing `StackTracey`:
```
```javascript
StackTracey.isThirdParty.except (path => path.includes ('jquery')) // jquery paths won't be marked as thirdParty
class MyStackTracey extends StackTracey {
isThirdParty (path) {
return (super.isThirdParty (path) // include default behavior
|| path.includes ('my-lib')) // paths including 'my-lib' will be marked as thirdParty
&& !path.includes ('jquery') // jquery paths won't be marked as thirdParty
}
}
...
const stack = new MyStackTracey (error).withSources ()
```
P.S. It is better to call `.clean` on stacks supplied with sources (i.e. after the `.withSources`), to make the `// @hide` magic work, and to make third-party recognition work by reading proper file names in case if your source is compiled from other sources (and has a sourcemap attached).
## Pretty Printing
```javascript
const prettyPrintedString = new StackTracey (error).pretty
const prettyPrintedString = new StackTracey (error).asTable ()
```

@@ -149,3 +159,3 @@

```javascript
const prettyPrintedString = new StackTracey (error).clean.pretty
const prettyPrintedString = new StackTracey (error).clean ().asTable ()
```

@@ -168,2 +178,14 @@

If you find your pretty printed tables undesirably trimmed (or maybe too long to fit in the line), you can provide custom column widths when calling `asTable` (...or, alternatively, by overriding `maxColumnWidths ()` method):
```javascript
stack.asTable ({
callee: 30,
file: 60,
sourceLine: 80
})
```
## Using As Custom Exception Printer In Node
You can even replace the default NodeJS exception printer with this! This is how you can do it:

@@ -185,15 +207,2 @@

<img width="1066" alt="screen shot 2018-05-11 at 19 51 03" src="https://user-images.githubusercontent.com/1707/39936393-ffd529c2-5554-11e8-80f8-eff1229017c4.png">
### Overriding Max Column Widths in Pretty Printed Tables
If you get your pretty printed tables undesirably trimmed, you can try changing these numbers:
```javascript
StackTracey.maxColumnWidths = {
callee: 30,
file: 40,
sourceLine: 80
}
```

@@ -223,23 +232,10 @@ ## Parsing `SyntaxError` instances

All StackTracey instances expose `map`, `filter`, `concat`, `reverse` and `slice` methods. These methods will return mapped, filtered, joined, reversed and sliced stacks, respectively:
All StackTracey instances expose `map`, `filter`, `concat` and `slice` methods. These methods will return mapped, filtered, joined, reversed and sliced `StackTracey` instances, respectively:
```javascript
s = new StackTracey ().slice (1).filter (x => !x.isThirdParty) // current stack shifted by 1 and cleaned from library calls
s = new StackTracey ().slice (1).filter (x => !x.thirdParty) // current stack shifted by 1 and cleaned from library calls
s instanceof StackTracey // true
s instanceof Array // true
```
Other methods of the `Array` are supported too, but they will return `Array` instances, not StackTracey instances. You can convert from array via this:
```javascript
stack = new StackTracey (array)
```
..and to array via this (but generally this is not needed — you can pass around StackTracey instances as if they were real Arrays):
```javascript
Array.from (stack)
```
## Extra Stuff

@@ -253,3 +249,3 @@

Resetting source cache (calls `getSource.resetCache ()` from [get-source](https://github.com/xpl/get-source)):
To force-reload the sources, you can invalidate the global source cache (calls `getSource.resetCache ()` from [get-source](https://github.com/xpl/get-source)):

@@ -256,0 +252,0 @@ ```javascript

@@ -17,3 +17,3 @@ "use strict";

class StackTracey extends Array {
class StackTracey {

@@ -24,10 +24,3 @@ constructor (input, offset) {

, isParseableSyntaxError = input && (input instanceof SyntaxError && !isBrowser)
super ()
/* Fixes for Safari */
this.constructor = StackTracey
this.__proto__ = StackTracey.prototype
/* new StackTracey () */

@@ -43,3 +36,3 @@

if (input instanceof Error) {
input = input[StackTracey.stack] || input.stack || ''
input = input.stack || ''
}

@@ -50,3 +43,3 @@

if (typeof input === 'string') {
input = StackTracey.rawParse (input).slice (offset).map (StackTracey.extractEntryMetadata)
input = this.rawParse (input).slice (offset).map (x => this.extractEntryMetadata (x))
}

@@ -60,3 +53,3 @@

const rawLines = module.require ('util').inspect (originalInput).split ('\n')
const rawLines = module.require ('util').inspect (originalInput).split ('\n')
, fileLine = rawLines[0].split (':')

@@ -78,10 +71,12 @@ , line = fileLine.pop ()

this.length = input.length
input.forEach ((x, i) => this[i] = x)
this.items = input
} else {
this.items = []
}
}
static extractEntryMetadata (e) {
extractEntryMetadata (e) {
const fileRelative = StackTracey.relativePath (e.file || '')
const fileRelative = this.relativePath (e.file || '')

@@ -92,9 +87,9 @@ return O.assign (e, {

fileRelative: fileRelative,
fileShort: StackTracey.shortenPath (fileRelative),
fileShort: this.shortenPath (fileRelative),
fileName: lastOf ((e.file || '').split ('/')),
thirdParty: StackTracey.isThirdParty (fileRelative) && !e.index
thirdParty: this.isThirdParty (fileRelative) && !e.index
})
}
static shortenPath (relativePath) {
shortenPath (relativePath) {
return relativePath.replace (/^node_modules\//, '')

@@ -104,7 +99,7 @@ .replace (/^webpack\/bootstrap\//, '')

static relativePath (fullPath) {
relativePath (fullPath) {
return nixSlashes (pathToRelative (pathRoot, fullPath)).replace (/^.*\:\/\/?\/?/, '')
}
static isThirdParty (relativePath) {
isThirdParty (relativePath) {
return (relativePath[0] === '~') || // webpack-specific heuristic

@@ -116,3 +111,3 @@ (relativePath[0] === '/') || // external source

static rawParse (str) {
rawParse (str) {

@@ -165,7 +160,7 @@ const lines = (str || '').split ('\n')

withSource (i) {
return this[i] && StackTracey.withSource (this[i])
withSourceAt (i) {
return this.items[i] && this.withSource (this.items[i])
}
static withSource (loc) {
withSource (loc) {

@@ -185,3 +180,3 @@ if (loc.sourceFile || (loc.file && loc.file.indexOf ('<') >= 0)) { // skip things like <anonymous> and stuff that was already fetched

resolved.file = nixSlashes (resolved.sourceFile.path)
resolved = StackTracey.extractEntryMetadata (resolved)
resolved = this.extractEntryMetadata (resolved)
}

@@ -204,9 +199,9 @@

get withSources () {
return new StackTracey (this.map (StackTracey.withSource))
withSources () {
return this.map (x => this.withSource (x))
}
get mergeRepeatedLines () {
mergeRepeatedLines () {
return new StackTracey (
partition (this, e => e.file + e.line).map (
partition (this.items, e => e.file + e.line).map (
group => {

@@ -216,3 +211,4 @@ return group.items.slice (1).reduce ((memo, entry) => {

memo.calleeShort = (memo.calleeShort || '<anonymous>') + ' → ' + (entry.calleeShort || '<anonymous>')
return memo }, O.assign ({}, group.items[0]))
return memo
}, O.assign ({}, group.items[0]))
}

@@ -223,4 +219,6 @@ )

get clean () {
return this.withSources.mergeRepeatedLines.filter ((e, i) => (i === 0) || !(e.thirdParty || e.hide || e.native))
clean () {
return this.withSources ()
.mergeRepeatedLines ()
.filter ((e, i) => (i === 0) || !(e.thirdParty || e.hide || e.native))
}

@@ -239,81 +237,53 @@

}, this[i])
}, this.items[i])
}
static locationsEqual (a, b) {
return (a.file === b.file) &&
(a.line === b.line) &&
(a.column === b.column)
}
asTable (opts) {
const maxColumnWidths = (opts && opts.maxColumnWidths) || this.maxColumnWidths ()
get pretty () {
const trimEnd = (s, n) => s && ((s.length > n) ? (s.slice (0, n-1) + '…') : s)
const trimStart = (s, n) => s && ((s.length > n) ? ('…' + s.slice (-(n-1))) : s)
return asTable (this.withSources.map (
e => [
('at ' + trimEnd (e.calleeShort, StackTracey.maxColumnWidths.callee)),
trimStart ((e.fileShort && (e.fileShort + ':' + e.line)) || '', StackTracey.maxColumnWidths.file),
trimEnd (((e.sourceLine || '').trim () || ''), StackTracey.maxColumnWidths.sourceLine)
]))
const trimmed = this.withSources ().map (
e => [
('at ' + trimEnd (e.calleeShort, maxColumnWidths.callee)),
trimStart ((e.fileShort && (e.fileShort + ':' + e.line)) || '', maxColumnWidths.file),
trimEnd (((e.sourceLine || '').trim () || ''), maxColumnWidths.sourceLine)
]
)
return asTable (trimmed.items)
}
maxColumnWidths () {
return {
callee: 30,
file: 60,
sourceLine: 80
}
}
static resetCache () {
getSource.resetCache ()
getSource.async.resetCache ()
}
}
/* Some default configuration options
------------------------------------------------------------------------ */
StackTracey.maxColumnWidths = {
callee: 30,
file: 60,
sourceLine: 80
static locationsEqual (a, b) {
return (a.file === b.file) &&
(a.line === b.line) &&
(a.column === b.column)
}
}
/* Chaining helper for .isThirdParty
------------------------------------------------------------------------ */
;(() => {
const methods = {
include (pred) {
const f = StackTracey.isThirdParty
O.assign (StackTracey.isThirdParty = (path => f (path) || pred (path)), methods)
},
except (pred) {
const f = StackTracey.isThirdParty
O.assign (StackTracey.isThirdParty = (path => f (path) && !pred (path)), methods)
},
}
O.assign (StackTracey.isThirdParty, methods)
}) ()
/* Array methods
------------------------------------------------------------------------ */
;['map', 'filter', 'slice', 'concat', 'reverse'].forEach (name => {
;['map', 'filter', 'slice', 'concat'].forEach (method => {
StackTracey.prototype[name] = function (/*...args */) { // no support for ...args in Node v4 :(
const arr = Array.from (this)
return new StackTracey (arr[name].apply (arr, arguments))
StackTracey.prototype[method] = function (/*...args */) { // no support for ...args in Node v4 :(
return new StackTracey (this.items[method].apply (this.items, arguments))
}
})
/* A private field that an Error instance can expose
------------------------------------------------------------------------ */
StackTracey.stack = /* istanbul ignore next */ (typeof Symbol !== 'undefined') ? Symbol.for ('StackTracey') : '__StackTracey'
/* ------------------------------------------------------------------------ */

@@ -323,3 +293,1 @@

/* ------------------------------------------------------------------------ */

@@ -38,5 +38,5 @@ "use strict";

stack.should.be.an.instanceof (Array)
stack.should.be.an.instanceof (StackTracey)
stack[0].should.deep.equal ({
stack.items[0].should.deep.equal ({
beforeParse: 'at shouldBeVisibleInStackTrace (' + path.join (process.cwd (), 'test.js') + ':32:47)',

@@ -59,16 +59,16 @@ callee: 'shouldBeVisibleInStackTrace',

const stack = shouldBeVisibleInStackTrace ().withSources // @hide
const stack = shouldBeVisibleInStackTrace ().withSources () // @hide
stack.should.be.an.instanceof (StackTracey)
stack[0].beforeParse.should.not.be.undefined // should preserve previous fields
stack[0].sourceLine.should.equal (' const shouldBeVisibleInStackTrace = () => new StackTracey () ')
stack[0].hide.should.equal (true) // reads // @hide marker
stack[1].hide.should.equal (true) // reads // @hide marker
stack.should.be.an.instanceof (StackTracey)
stack.items[0].beforeParse.should.not.be.undefined // should preserve previous fields
stack.items[0].sourceLine.should.equal (' const shouldBeVisibleInStackTrace = () => new StackTracey () ')
stack.items[0].hide.should.equal (true) // reads // @hide marker
stack.items[1].hide.should.equal (true) // reads // @hide marker
const cleanStack = stack.clean
const cleanStack = stack.clean ()
cleanStack.should.be.an.instanceof (StackTracey)
StackTracey.locationsEqual (cleanStack[0], stack[0]).should.equal (true) // should not clean top element
StackTracey.locationsEqual (cleanStack[1], stack[1]).should.equal (false) // should clean second element (due to // @hide)
StackTracey.locationsEqual (cleanStack.items[0], stack.items[0]).should.equal (true) // should not clean top element
StackTracey.locationsEqual (cleanStack.items[1], stack.items[1]).should.equal (false) // should clean second element (due to // @hide)
})

@@ -85,3 +85,3 @@

const clean = stack.clean.map (x => Object.assign ({
const clean = stack.clean ().map (x => Object.assign ({
file: x.file,

@@ -94,3 +94,3 @@ line: x.line,

Array.from (clean).should.deep.equal ([ // .should does not recognize StackTracey as normal array...
clean.items.should.deep.equal ([ // .should does not recognize StackTracey as normal array...

@@ -106,5 +106,5 @@ { file: 'yo.js', line: 11, callee: 'a.funkktion', calleeShort: 'a' },

const stack = shouldBeVisibleInStackTrace ()
stack[0].file = '^___^'
stack.withSources[0].sourceLine.should.equal ('')
stack.withSources[0].error.should.be.an.instanceof (Error)
stack.items[0].file = '^___^'
stack.withSources ().items[0].sourceLine.should.equal ('')
stack.withSourceAt (0).error.should.be.an.instanceof (Error)
})

@@ -116,3 +116,3 @@

const sliced = stack.slice (1)
const deltaLength = (stack.length - sliced.length)
const deltaLength = (stack.items.length - sliced.items.length)

@@ -136,6 +136,5 @@ deltaLength.should.equal (1)

const top = new StackTracey (e).withSources[0]
const top = new StackTracey (e).withSourceAt (0)
top.line .should.equal (4)
//top.column .should.equal (23)
top.sourceLine .should.equal ('\t\t\t\t\tthrow new Error (\'mkay\') }')

@@ -151,3 +150,3 @@

const pretty = new StackTracey ().clean.pretty
const pretty = new StackTracey ().clean ().asTable ()

@@ -168,3 +167,3 @@ console.log ('')

stack.pretty.split ('\n')[0].should.equal ('at dadasdasdasdasdasdasdasdasdas… …asdadadadasdasdasdasdasddasdsadadasdassdasdaddadasdas.js:11 ')
stack.asTable ().split ('\n')[0].should.equal ('at dadasdasdasdasdasdasdasdasdas… …asdadadadasdasdasdasdasddasdsadadasdassdasdaddadasdas.js:11 ')
})

@@ -181,12 +180,9 @@

mapped.should.deep.equal ([ { file: 'foo', i: 0 }, { file: 'bar', i: 1 } ])
mapped.should.be.an.instanceof (Array)
mapped.items.should.deep.equal ([ { file: 'foo', i: 0 }, { file: 'bar', i: 1 } ])
mapped.should.be.an.instanceof (StackTracey)
stack.reduce ((memo, x) => memo + x.file, '').should.equal ('foobar')
const filtered = stack.filter (x => x.file === 'bar')
filtered.length.should.equal (1)
filtered[0].should.deep.equal ({ file: 'bar', i: 1 })
filtered.items.length.should.equal (1)
filtered.items[0].should.deep.equal ({ file: 'bar', i: 1 })
})

@@ -196,7 +192,7 @@

StackTracey.relativePath ('webpack:///~/jquery/dist/jquery.js')
.should.equal ( '~/jquery/dist/jquery.js')
StackTracey.prototype.relativePath ('webpack:///~/jquery/dist/jquery.js')
.should.equal ( '~/jquery/dist/jquery.js')
StackTracey.relativePath ('webpack:/webpack/bootstrap')
.should.equal ( 'webpack/bootstrap')
StackTracey.prototype.relativePath ('webpack:/webpack/bootstrap')
.should.equal ( 'webpack/bootstrap')
})

@@ -206,7 +202,7 @@

StackTracey.shortenPath ('webpack/bootstrap/jquery/dist/jquery.js')
.should.equal ('jquery/dist/jquery.js')
StackTracey.prototype.shortenPath ('webpack/bootstrap/jquery/dist/jquery.js')
.should.equal ('jquery/dist/jquery.js')
StackTracey.shortenPath ('node_modules/jquery/dist/jquery.js')
.should.equal ('jquery/dist/jquery.js')
StackTracey.prototype.shortenPath ('node_modules/jquery/dist/jquery.js')
.should.equal ('jquery/dist/jquery.js')
})

@@ -221,9 +217,9 @@

const stack = new StackTracey (e).clean
const stack = new StackTracey (e).clean ()
console.log ('')
console.log (stack.pretty, '\n')
console.log (stack.asTable (), '\n')
stack[0].syntaxError.should.equal (true)
stack[0].column.should.equal (5)
stack.items[0].syntaxError.should.equal (true)
stack.items[0].column.should.equal (5)

@@ -233,3 +229,3 @@ const spaces = nodeVersion > 8 ? ' ' : ' '

stack.pretty.split ('\n')[0].should.equal ('at (syntax error)' + spaces + 'test_files/syntax_error.js:2' + spaces2 + 'foo->bar () ')
stack.asTable ().split ('\n')[0].should.equal ('at (syntax error)' + spaces + 'test_files/syntax_error.js:2' + spaces2 + 'foo->bar () ')
}

@@ -239,17 +235,25 @@ })

it ('implements StackTracey.isThirdParty', () => {
it ('allows to override isThirdParty()', () => {
StackTracey.isThirdParty.include (path => path === 'test.js')
class MyStackTracey extends StackTracey {
isThirdParty (path) {
return super.isThirdParty (path) || (path === 'test.js')
}
}
new StackTracey ()[0].thirdParty.should.equal (true)
new MyStackTracey ().items[0].thirdParty.should.equal (true)
StackTracey.isThirdParty.except (path => path === 'test.js')
class MyStackTracey2 extends MyStackTracey {
isThirdParty (path) {
return super.isThirdParty (path) && (path !== 'test.js')
}
}
new StackTracey ()[0].thirdParty.should.equal (false)
new MyStackTracey2 ().items[0].thirdParty.should.equal (false)
})
it ('.withSource', () => {
it ('.withSourceAt', () => {
const line = new StackTracey ().withSource (0).sourceLine.trim ()
line.should.equal ('const line = new StackTracey ().withSource (0).sourceLine.trim ()')
const line = new StackTracey ().withSourceAt (0).sourceLine.trim ()
line.should.equal ('const line = new StackTracey ().withSourceAt (0).sourceLine.trim ()')
})

@@ -267,3 +271,3 @@

stack[1].native.should.equal (true)
stack.items[1].native.should.equal (true)
})

@@ -284,3 +288,3 @@

const stack = new StackTracey (windowsStack)
const pretty = stack.pretty
const pretty = stack.asTable ()
const lines = pretty.split ('\n')

@@ -291,3 +295,3 @@

lines[0].should.equal ('at it test.js:38 stack.should.be.an.instanceof (Array)')
lines[0].should.equal ('at it test.js:38 stack.should.be.an.instanceof (StackTracey)')
lines[1].indexOf ('at callFn mocha/lib/runnable.js:354').should.equal (0)

@@ -294,0 +298,0 @@ })

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc