error-to-json
Version:
Returns a JSON representation of an error (handles nested errors and calls nested toJSONs)
72 lines (62 loc) • 1.65 kB
text/typescript
import stringify from 'fast-safe-stringify'
export default errToJSON
const nonEnumerablePropsToCopy = ['code', 'errno', 'syscall']
function errToJSON<T extends {}>(err: Error): T {
let json
// @ts-ignore
if (typeof err.toJSON === 'function') {
// @ts-ignore
json = err.toJSON()
} else {
// stub error tojson
let stubbed = 'toJSON' in Error.prototype
// @ts-ignore
const errToJSON = Error.prototype.toJSON
// @ts-ignore
const toJSON = function (this: Error) {
const json = {
// Add all enumerable properties
...this,
// normal props
name: this.name,
message: this.message,
stack: this.stack,
}
nonEnumerablePropsToCopy.forEach((key) => {
// @ts-ignore
if (key in this) json[key] = this[key]
})
return JSON.parse(stringify(json))
}
try {
// @ts-ignore
Error.prototype.toJSON = toJSON
} catch (e) {
stubbed = false
}
// get error json
// @ts-ignore
if (stubbed && typeof err.toJSON === 'function') {
// @ts-ignore
json = err.toJSON()
} else {
stubbed = false
json = toJSON.call(err)
}
// unstub error tojson
// @ts-ignore
if (stubbed) Error.prototype.toJSON = errToJSON
}
// return error json
return json
}
export function parse(json: { message: string }) {
const err = new Error(json.message)
const stack = err.stack || ''
Object.assign(err, json)
if (err.stack === stack) {
// remove stacktrace generated by error constructor above
err.stack = stack.slice(0, stack.indexOf('\n'))
}
return err
}