Skip to content

Commit

Permalink
feat: add raw property to the parsed error
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Nov 6, 2024
1 parent b910afb commit aac8286
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 22 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
},
"prettier": "@adonisjs/prettier-config",
"dependencies": {
"@poppinss/exception": "^1.1.0",
"error-stack-parser-es": "^0.1.5"
}
}
12 changes: 9 additions & 3 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* file that was distributed with this source code.
*/

import { inspect } from 'node:util'
import { Exception } from '@poppinss/exception'
import { parse, StackFrame as ESFrame } from 'error-stack-parser-es'

import debug from './debug.js'
Expand Down Expand Up @@ -64,7 +66,10 @@ export class ErrorParser {
return source as Error
}

return new Error(JSON.stringify(source), { cause: source })
const error = new Exception(JSON.stringify(source))
error.help =
'To get as much information as possible from your errors, make sure to throw Error objects. See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error</a> for more information.'
return error
}

/**
Expand Down Expand Up @@ -290,10 +295,11 @@ export class ErrorParser {
name: error.name,
metadata: [],
frames: await this.#enhanceFrames(esFrames),
hint: 'hint' in error ? (error.hint as string) : undefined,
code: 'code' in error ? (error.code as string) : undefined,
hint: 'hint' in error ? String(error.hint) : 'help' in error ? String(error.help) : undefined,
code: 'code' in error ? String(error.code) : undefined,
cause: error.cause,
stack: error.stack,
raw: inspect(error),
} satisfies ParsedError

for (let transformer of this.#transformers) {
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export interface ParsedError {
name: string
frames: StackFrame[]
metadata: MetadataGroup[]
/**
* Referenced to the raw error formatted using util.inspect
* method.
*/
raw: string
cause?: unknown
hint?: string
code?: string
Expand Down
46 changes: 27 additions & 19 deletions tests/parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ import { fileURLToPath } from 'node:url'
import { readFile } from 'node:fs/promises'
import { httpServer } from './helpers.js'
import { ErrorParser } from '../src/parser.js'
import { inspect } from 'node:util'

test.group('Error parser', () => {
test('should parse error', async ({ assert }) => {
const error = new Error('Something went wrong')
const { frames } = await new ErrorParser().parse(error)
const { frames, raw } = await new ErrorParser().parse(error)

assert.equal(raw, inspect(error))
assert.equal(frames[0].fileName, fileURLToPath(import.meta.url))
assert.equal(frames[0].lineNumber, 22)
assert.equal(frames[0].lineNumber, 23)
assert.equal(frames[0].type, 'app')
assert.equal(frames[0].fileType, 'fs')
assert.equal(
frames[0].source!.find(({ lineNumber }) => lineNumber === 22)?.chunk,
frames[0].source!.find(({ lineNumber }) => lineNumber === 23)?.chunk,
` const error = new Error('Something went wrong')`
)
})
Expand All @@ -39,7 +41,7 @@ test.group('Error parser', () => {
const { frames } = await new ErrorParser().parse(error)

assert.equal(frames[0].fileName, 'invalid-path')
assert.equal(frames[0].lineNumber, 36)
assert.equal(frames[0].lineNumber, 38)
assert.equal(frames[0].type, 'app')
assert.equal(frames[0].fileType, 'fs')
assert.isUndefined(frames[0].source)
Expand All @@ -54,7 +56,7 @@ test.group('Error parser', () => {

const { frames } = await new ErrorParser().parse(error)
assert.equal(frames[0].fileName, join(fileURLToPath(import.meta.url), 'dist', 'webpack:'))
assert.equal(frames[0].lineNumber, 49)
assert.equal(frames[0].lineNumber, 51)
assert.equal(frames[0].type, 'app')
assert.equal(frames[0].fileType, 'fs')
assert.isUndefined(frames[0].source)
Expand Down Expand Up @@ -158,11 +160,11 @@ test.group('Error parser', () => {
} catch (error) {
const { frames } = await new ErrorParser().parse(error)
assert.equal(frames[2].fileName, fileURLToPath(import.meta.url))
assert.equal(frames[2].lineNumber, 157)
assert.equal(frames[2].lineNumber, 159)
assert.equal(frames[2].type, 'app')
assert.equal(frames[2].fileType, 'fs')
assert.equal(
frames[2].source!.find(({ lineNumber }) => lineNumber === 157)?.chunk,
frames[2].source!.find(({ lineNumber }) => lineNumber === 159)?.chunk,
` await unidici.fetch('http://locahost:8100')`
)

Expand All @@ -178,12 +180,12 @@ test.group('Error parser', () => {
} catch (error) {
const { frames } = await new ErrorParser({ offset: 2 }).parse(error)
assert.equal(frames[0].fileName, fileURLToPath(import.meta.url))
assert.equal(frames[0].lineNumber, 177)
assert.equal(frames[0].lineNumber, 179)
assert.equal(frames[0].type, 'app')
assert.equal(frames[0].fileType, 'fs')
assert.equal(frames[1].type, 'module')
assert.equal(
frames[0].source!.find(({ lineNumber }) => lineNumber === 177)?.chunk,
frames[0].source!.find(({ lineNumber }) => lineNumber === 179)?.chunk,
` await unidici.fetch('http://locahost:8100')`
)
}
Expand All @@ -204,11 +206,11 @@ test.group('Error parser', () => {
console.log(error)
const { frames } = await new ErrorParser().parse(error)
assert.equal(frames[2].fileName, fileURLToPath(import.meta.url))
assert.equal(frames[2].lineNumber, 202)
assert.equal(frames[2].lineNumber, 204)
assert.equal(frames[2].type, 'app')
assert.equal(frames[2].fileType, 'fs')
assert.equal(
frames[2].source!.find(({ lineNumber }) => lineNumber === 202)?.chunk,
frames[2].source!.find(({ lineNumber }) => lineNumber === 204)?.chunk,
` await unidici.fetch('http://localhost:3000')`
)

Expand All @@ -232,11 +234,11 @@ test.group('Error parser', () => {
} catch (error) {
const { frames } = await new ErrorParser().parse(error)
assert.equal(frames[2].fileName, fileURLToPath(import.meta.url))
assert.equal(frames[2].lineNumber, 231)
assert.equal(frames[2].lineNumber, 233)
assert.equal(frames[2].type, 'app')
assert.equal(frames[2].fileType, 'fs')
assert.equal(
frames[2].source!.find(({ lineNumber }) => lineNumber === 231)?.chunk,
frames[2].source!.find(({ lineNumber }) => lineNumber === 233)?.chunk,
` await unidici.fetch('http://localhost:3000')`
)

Expand All @@ -249,14 +251,20 @@ test.group('Error parser', () => {
test('normalize boolean thrown as an error', async ({ assert }) => {
const error = await new ErrorParser().parse(true)
assert.equal(error.message, 'true')
assert.equal(error.cause, true)
assert.equal(
error.hint,
'To get as much information as possible from your errors, make sure to throw Error objects. See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error</a> for more information.'
)
})

test('normalize promise thrown as an error', async ({ assert }) => {
const p = new Promise(() => {})
const error = await new ErrorParser().parse(p)
assert.equal(error.message, '{}')
assert.equal(error.cause, p)
assert.equal(
error.hint,
'To get as much information as possible from your errors, make sure to throw Error objects. See <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error</a> for more information.'
)
})

test('define custom parser', async ({ assert }) => {
Expand All @@ -269,11 +277,11 @@ test.group('Error parser', () => {
const error = await parser.parse(p)
assert.equal(error.message, 'Promise cannot be thrown')
assert.equal(error.frames[0].fileName, fileURLToPath(import.meta.url))
assert.equal(error.frames[0].lineNumber, 266)
assert.equal(error.frames[0].lineNumber, 274)
assert.equal(error.frames[0].type, 'app')
assert.equal(error.frames[0].fileType, 'fs')
assert.equal(
error.frames[0].source!.find(({ lineNumber }) => lineNumber === 266)?.chunk,
error.frames[0].source!.find(({ lineNumber }) => lineNumber === 274)?.chunk,
` return value instanceof Promise ? new Error('Promise cannot be thrown') : value`
)
})
Expand All @@ -292,11 +300,11 @@ test.group('Error parser', () => {
const parsedError = await parser.parse(error)
assert.equal(error.message, 'Something went wrong')
assert.equal(parsedError.frames[0].fileName, fileURLToPath(import.meta.url))
assert.equal(parsedError.frames[0].lineNumber, 282)
assert.equal(parsedError.frames[0].lineNumber, 290)
assert.equal(parsedError.frames[0].type, 'app')
assert.equal(parsedError.frames[0].fileType, 'fs')
assert.equal(
parsedError.frames[0].source!.find(({ lineNumber }) => lineNumber === 282)?.chunk,
parsedError.frames[0].source!.find(({ lineNumber }) => lineNumber === 290)?.chunk,
` const error = new Error('Something went wrong')`
)
})
Expand Down

0 comments on commit aac8286

Please sign in to comment.