@grimen/mybad
Advanced tools
Comparing version 0.2.7 to 0.3.0
@@ -52,2 +52,3 @@ | ||
// eslint-disable-next-line | ||
for (let dollar of range(42)) { | ||
@@ -60,6 +61,9 @@ amount += '$' | ||
} catch (error) { | ||
process.env.ERROR_VERBOSE = false | ||
process.env.ERROR_COLORS = false | ||
console.log() | ||
console.log('===============================') | ||
console.log('========================================================') | ||
console.log(' error.toString()') | ||
console.log('---------------------------') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
@@ -70,26 +74,51 @@ console.log(error.toString()) | ||
console.log() | ||
console.log('===============================') | ||
console.log(' error.stack') | ||
console.log('---------------------------') | ||
console.log('========================================================') | ||
console.log(' error.toString({verbose: false})') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.stack) | ||
console.log(error.toString({verbose: false})) | ||
console.log() | ||
console.log() | ||
console.log('===============================') | ||
console.log(' error.inspect()') | ||
console.log('---------------------------') | ||
console.log('========================================================') | ||
console.log(' error.toString({verbose: true})') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.inspect(colors = true, verbose = true)) | ||
console.log(error.toString({verbose: true})) | ||
console.log() | ||
console.log() | ||
console.log('===============================') | ||
console.log(' error.json()') | ||
console.log('---------------------------') | ||
console.log('========================================================') | ||
console.log(' error.toString({colors: false})') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.json()) | ||
console.log(error.toString({colors: false})) | ||
console.log() | ||
console.log() | ||
console.log('========================================================') | ||
console.log(' error.toString({colors: true})') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.toString({colors: true})) | ||
console.log() | ||
console.log() | ||
console.log('========================================================') | ||
console.log(' error.toString({verbose: true, colors: true})') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.toString({verbose: true, colors: true})) | ||
console.log() | ||
console.log() | ||
console.log('========================================================') | ||
console.log(' error.toJSON()') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.toJSON()) | ||
console.log() | ||
break | ||
} | ||
} |
{ | ||
"name": "@grimen/mybad", | ||
"version": "0.2.7", | ||
"version": "0.3.0", | ||
"description": "My friendly error base class - for Node/JavaScript.", | ||
@@ -34,3 +34,3 @@ "keywords": [ | ||
"validate": "npx eslint \"**/*.js\"", | ||
"release": "./bin/release", | ||
"release": "npx np --no-publish", | ||
"coverage": "npx codecov" | ||
@@ -44,2 +44,3 @@ }, | ||
"es6-error": "^4.1.1", | ||
"util-deprecate": "^1.0.2", | ||
"util-inspect": "^0.1.8" | ||
@@ -50,4 +51,6 @@ }, | ||
"eslint": "^7.22.0", | ||
"eslint-config-prettier": "^8.1.0", | ||
"jest": "^26.6.3", | ||
"jest-tobetype": "^1.2.3", | ||
"np": "^7.4.0", | ||
"strip-ansi": "^6.0.0" | ||
@@ -58,5 +61,5 @@ }, | ||
"verbose": true, | ||
"testRegex": "test_.*\\.js", | ||
"testRegex": ".*\\.test\\.js", | ||
"testEnvironment": "node" | ||
} | ||
} |
198
README.md
@@ -70,4 +70,29 @@ | ||
} catch (error) { | ||
console.error(error.toString()) | ||
process.env.ERROR_VERBOSE = false | ||
process.env.ERROR_COLORS = false | ||
console.log() | ||
console.log('========================================================') | ||
console.log(' error.toString({verbose: false})') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.toString({verbose: false})) | ||
console.log() | ||
console.log() | ||
console.log('========================================================') | ||
console.log(' error.toString({verbose: true})') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.toString({verbose: true})) | ||
console.log() | ||
console.log() | ||
console.log('========================================================') | ||
console.log(' error.toJSON()') | ||
console.log('-----------------------------------------------------') | ||
console.log() | ||
console.log(error.toString({verbose: true})) | ||
console.log() | ||
throw error | ||
@@ -79,3 +104,3 @@ } | ||
Run this with optional environment variables `COLORS` / `ERROR_COLORS` and/or `VERBOSE` / `ERROR_VERBOSE` set too truthy or falsy values, so see various error info formatting in terminal. | ||
Run this with optional environment variables `COLORS` / `ERROR_COLORS` and/or `VERBOSE` / `ERROR_VERBOSE` set too truthy or falsy values, so see various error info formatting in terminal. Also `(NO_COLOR)[https://no-color.org]` is respected. | ||
@@ -99,108 +124,87 @@ Something like this (imagine some colorized formatting): | ||
=============================== | ||
error.toString() | ||
--------------------------- | ||
Out of money printing ink... - { stash: '$$$$$$$$$$$$$$' } | ||
======================================================== | ||
error.toString({verbose: false}) | ||
----------------------------------------------------- | ||
Out of money printing ink... | ||
=============================== | ||
error.stack | ||
--------------------------- | ||
ToMuchError: Out of money printing ink... | ||
at printMoney (/Users/grimen/Dev/Private/js-mybad/examples/basic.js:29:15) | ||
at Object.<anonymous> (/Users/grimen/Dev/Private/js-mybad/examples/basic.js:56:9) | ||
at Module._compile (module.js:653:30) | ||
at Object.Module._extensions..js (module.js:664:10) | ||
at Module.load (module.js:566:32) | ||
at tryModuleLoad (module.js:506:12) | ||
at Function.Module._load (module.js:498:3) | ||
at Function.Module.runMain (module.js:694:10) | ||
at startup (bootstrap_node.js:204:16) | ||
at bootstrap_node.js:625:3 | ||
======================================================== | ||
error.toString({verbose: true}) | ||
----------------------------------------------------- | ||
Out of money printing ink... { stash: '$$$$$$$$$$$$$$' } | ||
=============================== | ||
error.inspect() | ||
--------------------------- | ||
Out of money printing ink... | ||
======================================================== | ||
error.toJSON() | ||
----------------------------------------------------- | ||
=============================== | ||
error.json() | ||
--------------------------- | ||
{ | ||
"type": "ToMuchError", | ||
"id": 1557522743469, | ||
"code": 400, | ||
"key": "too_much", | ||
"message": "Out of money printing ink...", | ||
"details": { | ||
"stash": "$$$$$$$$$$$$$$" | ||
type: 'ToMuchError', | ||
id: 1618487081556, | ||
code: 400, | ||
key: 'too_much', | ||
message: 'Out of money printing ink...', | ||
details: { stash: '$$$$$$$$$$$$$$' }, | ||
stack: [ | ||
{ | ||
file: '/Users/jonas/Dev/Private/js-mybad/examples/basic.js', | ||
function: 'printMoney', | ||
line: 23, | ||
column: 19, | ||
source: undefined | ||
}, | ||
"stack": [ | ||
{ | ||
"file": "/Users/grimen/Dev/Private/js-mybad/examples/basic.js", | ||
"function": "printMoney", | ||
"line": 29, | ||
"column": 15 | ||
}, | ||
{ | ||
"file": "/Users/grimen/Dev/Private/js-mybad/examples/basic.js", | ||
"function": "Object.<anonymous>", | ||
"line": 56, | ||
"column": 9 | ||
}, | ||
{ | ||
"file": "module.js", | ||
"function": "Module._compile", | ||
"line": 653, | ||
"column": 30 | ||
}, | ||
{ | ||
"file": "module.js", | ||
"function": "Object.Module._extensions..js", | ||
"line": 664, | ||
"column": 10 | ||
}, | ||
{ | ||
"file": "module.js", | ||
"function": "Module.load", | ||
"line": 566, | ||
"column": 32 | ||
}, | ||
{ | ||
"file": "module.js", | ||
"function": "tryModuleLoad", | ||
"line": 506, | ||
"column": 12 | ||
}, | ||
{ | ||
"file": "module.js", | ||
"function": "Function.Module._load", | ||
"line": 498, | ||
"column": 3 | ||
}, | ||
{ | ||
"file": "module.js", | ||
"function": "Function.Module.runMain", | ||
"line": 694, | ||
"column": 10 | ||
}, | ||
{ | ||
"file": "bootstrap_node.js", | ||
"function": "startup", | ||
"line": 204, | ||
"column": 16 | ||
}, | ||
{ | ||
"file": "625", | ||
"function": "bootstrap_node.js", | ||
"line": 3 | ||
} | ||
] | ||
{ | ||
file: '/Users/jonas/Dev/Private/js-mybad/examples/basic.js', | ||
function: 'Object.<anonymous>', | ||
line: 57, | ||
column: 9, | ||
source: undefined | ||
}, | ||
{ | ||
file: 'internal/modules/cjs/loader.js', | ||
function: 'Module._compile', | ||
line: 1063, | ||
column: 30, | ||
source: undefined | ||
}, | ||
{ | ||
file: 'internal/modules/cjs/loader.js', | ||
function: 'Object.Module._extensions..js', | ||
line: 1092, | ||
column: 10, | ||
source: undefined | ||
}, | ||
{ | ||
file: 'internal/modules/cjs/loader.js', | ||
function: 'Module.load', | ||
line: 928, | ||
column: 32, | ||
source: undefined | ||
}, | ||
{ | ||
file: 'internal/modules/cjs/loader.js', | ||
function: 'Function.Module._load', | ||
line: 769, | ||
column: 14, | ||
source: undefined | ||
}, | ||
{ | ||
file: 'internal/modules/run_main.js', | ||
function: 'Function.executeUserEntryPoint [as runMain]', | ||
line: 72, | ||
column: 12, | ||
source: undefined | ||
}, | ||
{ | ||
file: '17', | ||
function: 'internal/main/run_main_module.js', | ||
line: 47, | ||
column: undefined, | ||
source: undefined | ||
} | ||
] | ||
} | ||
``` | ||
@@ -207,0 +211,0 @@ |
@@ -27,3 +27,4 @@ | ||
const TRUTHY_PATTERN = /^true|1$/i | ||
const TRUTHY_PATTERN = /^yes|true|1$/i | ||
const FALSY_PATTERN = /^no|false|0$/i | ||
@@ -81,4 +82,7 @@ | ||
message = message || error.message | ||
details = details || error.details | ||
// TODO: pass any non-reserved option - https://github.com/ramadis/unmiss/blob/master/src/MethodMissingClass.js | ||
} else { | ||
@@ -99,3 +103,3 @@ error = options.error | ||
if (typeof details !== 'object') { | ||
throw TypeError(`Expected argument ${klass}(details = <details>) to be a \`${typeof {}}\`, but was \`${typeof details}\`.`) | ||
throw TypeError(`Expected argument \`${klass}({ details: <details> })\`\` to be a \`${typeof {}}\`, but was \`${typeof details}\`.`) | ||
} | ||
@@ -163,2 +167,10 @@ | ||
get cause () { | ||
return super.cause || this.error | ||
} | ||
set cause (error) { | ||
this.error = error | ||
} | ||
get stack () { | ||
@@ -173,167 +185,192 @@ return super.stack || '' | ||
get stackframes () { | ||
let _stackframes | ||
return this.constructor.getStackFrames(this) | ||
} | ||
if (this.stack) { | ||
_stackframes = this.stack | ||
.split(/\n/) | ||
.slice(1) | ||
.filter((value) => { | ||
return value && !!value.trim().length | ||
}) | ||
.map((value) => { | ||
try { | ||
const stackframeLine = value.trim() | ||
get stackobjects () { | ||
return this.constructor.getStackObjects(this) | ||
} | ||
let stackframeData | ||
get data () { | ||
return this.constructor.toJSON(this) | ||
} | ||
if (stackframeLine.includes('(')) { | ||
stackframeData = stackframeLine.match(/^at ([^()]+)\((.+)(?::(\d+):(\d+)\))/i) | ||
// DEPRECATE: stringify? `util-deprecate` | ||
json (...args) { | ||
return this.constructor.stringify(this, ...args) | ||
} | ||
} else { | ||
stackframeData = stackframeLine.match(/^at (.+)(?::(\d+):(\d+))/i) | ||
} | ||
inspect (...args) { | ||
return this.constructor.inspect(this, ...args) | ||
} | ||
let [ | ||
// eslint-disable-next-line | ||
_, | ||
functionName, | ||
fileName, | ||
lineNumber, | ||
columnNumber, | ||
] = stackframeData || [] | ||
valueOf (...args) { | ||
return this.constructor.valueOf(this, ...args) | ||
} | ||
functionName = functionName && functionName.trim() | ||
lineNumber = lineNumber && parseInt(lineNumber) | ||
columnNumber = columnNumber && parseInt(columnNumber) | ||
toJSON (...args) { | ||
return this.constructor.toJSON(this, ...args) | ||
} | ||
return { | ||
functionName, | ||
fileName, | ||
lineNumber, | ||
columnNumber, | ||
} | ||
toString (...args) { | ||
return this.constructor.toString(this, ...args) | ||
} | ||
} catch (error) { | ||
return error | ||
} | ||
}) | ||
static from (...args) { | ||
return this.cast(...args) | ||
} | ||
} else { | ||
_stackframes = null | ||
} | ||
// legacy | ||
static object (...args) { | ||
return this.toJSON(...args) | ||
} | ||
return _stackframes | ||
static data (...args) { | ||
return this.toJSON(...args) | ||
} | ||
get stackobjects () { | ||
const _stackobjects = (this.stackframes || []) | ||
.map((stackframe) => { | ||
const file = stackframe.fileName | ||
const function_ = stackframe.functionName | ||
const line = stackframe.lineNumber | ||
const column = stackframe.columnNumber | ||
const source = stackframe.source | ||
static stackframes (...args) { | ||
return this.getStackFrames(...args) | ||
} | ||
const stackobject = { | ||
file, | ||
function: function_, | ||
line, | ||
column, | ||
source, | ||
} | ||
static stackobjects (...args) { | ||
return this.getStackObjects(...args) | ||
} | ||
return stackobject | ||
}) | ||
.filter((stackobject) => { | ||
return !!stackobject.file | ||
}) | ||
.filter((stackobject) => { | ||
const isInternalStackFile = stackobject.file.includes(__filename) | ||
const isInternalStackFunction = Object.getOwnPropertyNames(this).includes(stackobject.function) | ||
const isInternalStackObject = isInternalStackFile && isInternalStackFunction | ||
static cast (error) { | ||
if (error instanceof BaseError) { | ||
return error | ||
return !isInternalStackObject | ||
}) | ||
} else { | ||
const castedError = new BaseError(error) | ||
return _stackobjects | ||
} | ||
castedError.stack = error.stack | ||
get data () { | ||
return { | ||
'type': this.constructor.name, | ||
'id': this.id, | ||
'code': this.code, | ||
'key': this.key, | ||
'message': this.message, | ||
'details': this.details, | ||
'stack': this.stackobjects, | ||
return castedError | ||
} | ||
} | ||
json (options = {}) { | ||
let { | ||
indent, | ||
} = options || {} | ||
static inspect (error, options = {}) { | ||
if (typeof error === 'object') { | ||
let { | ||
colors, | ||
verbose, | ||
} = this.getOptions(options) | ||
if (!indent && indent !== false) { | ||
indent = DEFAULT_ERROR_INDENT | ||
} | ||
let message | ||
let details | ||
return JSON.stringify(this.data, null, indent) | ||
} | ||
const indent = DEFAULT_ERROR_INDENT | ||
inspect (options = {}) { | ||
options = options || {} | ||
if (!error.message) { | ||
message = '<none>' | ||
let { | ||
colors, | ||
verbose, | ||
} = options | ||
} else { | ||
message = error.message.split(' - Arguments')[0] | ||
} | ||
let message | ||
let details | ||
if (colors) { | ||
message = color.red(message) | ||
} | ||
const indent = DEFAULT_ERROR_INDENT | ||
if (verbose) { | ||
const depth = null | ||
if (!this.message) { | ||
message = '<none>' | ||
details = inspect(error.details, { | ||
colors, | ||
indent, | ||
depth, | ||
}) | ||
} else { | ||
message = this.message.split(' - Arguments')[0] | ||
if (colors) { | ||
details = color.gray(details) | ||
} | ||
} else { | ||
details = null | ||
} | ||
const hasDetails = (typeof error.details === 'object') && !!Object.keys(error.details).length | ||
message = [ | ||
message, | ||
hasDetails && details, | ||
].filter(Boolean).join(' ') | ||
return message | ||
} | ||
} | ||
if (colors) { | ||
message = color.red(message) | ||
static stringify (error, options = {}) { | ||
if (typeof error === 'object') { | ||
let { | ||
indent, | ||
} = options || {} | ||
if (!indent && indent !== false) { | ||
indent = DEFAULT_ERROR_INDENT | ||
} | ||
return JSON.stringify(error.data, null, indent) | ||
} else if (error) { | ||
if (typeof error.toString === 'function') { | ||
return error.toString() | ||
} | ||
} | ||
if (verbose) { | ||
const depth = null | ||
return '' | ||
} | ||
details = inspect(this.details, { | ||
colors, | ||
indent, | ||
depth, | ||
}) | ||
static valueOf (error) { | ||
if (typeof error === 'object') { | ||
return (typeof error.code === 'number') ? error.code : 0 | ||
} else if (error) { | ||
if (typeof error.valueOf === 'function') { | ||
return error.valueOf() | ||
} | ||
} | ||
return undefined | ||
} | ||
static toJSON (error, attrs = {}) { | ||
if (error) { | ||
const extendedError = BaseError.cast(error) | ||
return { | ||
type: error.constructor.name, | ||
id: extendedError.id, | ||
code: extendedError.code, | ||
key: extendedError.key, | ||
message: extendedError.message, | ||
details: extendedError.details, | ||
stack: extendedError.stackobjects, | ||
...attrs, | ||
} | ||
} else { | ||
details = null | ||
return {} | ||
} | ||
} | ||
const hasDetails = (typeof this.details === 'object') && !!Object.keys(this.details).length | ||
static toString (error, options = {}) { | ||
if (error) { | ||
error = BaseError.cast(error) | ||
message = [ | ||
message, | ||
hasDetails && details, | ||
].filter(Boolean).join(' - ') | ||
const string = this.inspect(error, options) | ||
return message | ||
return string | ||
} | ||
} | ||
toString () { | ||
let colors | ||
let verbose | ||
static getOptions (options = {}) { | ||
options = { | ||
...options, | ||
} | ||
colors = process.env['ERROR_COLORS'] | ||
colors = colors || process.env['COLORS'] | ||
let { colors, verbose } = options | ||
colors = (typeof colors === 'boolean') ? colors : process.env['NO_COLOR'] && FALSY_PATTERN.test(process.env['NO_COLOR']) // no-color.org | ||
colors = (typeof colors === 'boolean') ? colors : process.env['ERROR_COLORS'] | ||
colors = (typeof colors === 'boolean') ? colors : process.env['COLORS'] | ||
if (typeof colors === 'undefined') { | ||
@@ -345,4 +382,4 @@ colors = DEFAULT_ERROR_COLORS | ||
verbose = process.env['ERROR_VERBOSE'] | ||
verbose = verbose || process.env['VERBOSE'] | ||
verbose = (typeof verbose === 'boolean') ? verbose : process.env['ERROR_VERBOSE'] | ||
verbose = (typeof verbose === 'boolean') ? verbose : process.env['VERBOSE'] | ||
@@ -355,42 +392,105 @@ if (typeof verbose === 'undefined') { | ||
const string = this.inspect({ | ||
return { | ||
verbose, | ||
colors, | ||
verbose, | ||
}) | ||
return string | ||
...options, | ||
} | ||
} | ||
static cast (error) { | ||
if (error instanceof BaseError) { | ||
return error | ||
static getStackFrames (error) { | ||
let _stackframes | ||
} else { | ||
const castedError = new BaseError(error) | ||
if ((error instanceof Error) && typeof error.stack === 'string') { | ||
_stackframes = error.stack | ||
.split(/\n/) | ||
.slice(1) | ||
.filter((value) => { | ||
return value && !!value.trim().length | ||
}) | ||
.map((value) => { | ||
try { | ||
const stackframeLine = value.trim() | ||
castedError.stack = error.stack | ||
let stackframeData | ||
return castedError | ||
if (stackframeLine.includes('(')) { | ||
stackframeData = stackframeLine.match(/^at ([^()]+)\((.+)(?::(\d+):(\d+)\))/i) | ||
} else { | ||
stackframeData = stackframeLine.match(/^at (.+)(?::(\d+):(\d+))/i) | ||
} | ||
let [ | ||
// eslint-disable-next-line | ||
_, | ||
functionName, | ||
fileName, | ||
lineNumber, | ||
columnNumber, | ||
] = stackframeData || [] | ||
functionName = functionName && functionName.trim() | ||
lineNumber = lineNumber && parseInt(lineNumber) | ||
columnNumber = columnNumber && parseInt(columnNumber) | ||
return { | ||
functionName, | ||
fileName, | ||
lineNumber, | ||
columnNumber, | ||
} | ||
} catch (error) { | ||
return error | ||
} | ||
}) | ||
} else { | ||
_stackframes = [] | ||
} | ||
} | ||
static from (error) { | ||
return this.cast(error) | ||
return _stackframes | ||
} | ||
static object (error, attrs) { | ||
const extendedError = BaseError.cast(error) | ||
static getStackObjects (error) { | ||
let _stackobjects | ||
return { | ||
type: error.constructor.name, | ||
id: extendedError.id, | ||
code: extendedError.code, | ||
key: extendedError.key, | ||
message: extendedError.message, | ||
details: extendedError.details, | ||
stack: extendedError.stackobjects, | ||
...attrs, | ||
if (error instanceof Error) { | ||
error = BaseError.cast(error) | ||
const _stackobjects = (error.stackframes || []) | ||
.map((stackframe) => { | ||
const file = stackframe.fileName | ||
const function_ = stackframe.functionName | ||
const line = stackframe.lineNumber | ||
const column = stackframe.columnNumber | ||
const source = stackframe.source | ||
const stackobject = { | ||
file, | ||
function: function_, | ||
line, | ||
column, | ||
source, | ||
} | ||
return stackobject | ||
}) | ||
.filter((stackobject) => { | ||
return !!stackobject.file | ||
}) | ||
.filter((stackobject) => { | ||
const isInternalStackFile = stackobject.file.includes(__filename) | ||
const isInternalStackFunction = Object.getOwnPropertyNames(error).includes(stackobject.function) | ||
const isInternalStackObject = isInternalStackFile && isInternalStackFunction | ||
return !isInternalStackObject | ||
}) | ||
return _stackobjects | ||
} else { | ||
_stackobjects = [] | ||
} | ||
return _stackobjects | ||
} | ||
} | ||
@@ -397,0 +497,0 @@ |
Sorry, the diff of this file is not supported yet
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 5 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
46659
885
238
12
4
7
1
+ Addedutil-deprecate@^1.0.2
+ Addedutil-deprecate@1.0.2(transitive)