Skip to content

Commit

Permalink
fix: apply transformers, parsers and source loader to the Error parser
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Dec 13, 2024
1 parent 6eaace2 commit 05d0612
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 8 deletions.
36 changes: 28 additions & 8 deletions src/youch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import { ErrorParser } from 'youch-core'
import type { Parser, SourceLoader, Transformer } from 'youch-core/types'
import type { Parser, SourceLoader, Transformer, YouchParserOptions } from 'youch-core/types'

import { Metadata } from './metadata.js'
import { Templates } from './templates.js'
Expand All @@ -18,7 +18,12 @@ import { YouchANSIOptions, YouchHTMLOptions, YouchJSONOptions } from './types.js
* Youch exposes the API to render errors to HTML output
*/
export class Youch {
#errorParser = new ErrorParser()
/**
* Properties to be shared with the Error parser
*/
#sourceLoader?: SourceLoader
#parsers: Parser[] = []
#transformers: Transformer[] = []

/**
* Manage templates used for converting error to the HTML
Expand All @@ -31,12 +36,27 @@ export class Youch {
*/
metadata = new Metadata()

/**
* Creates an instance of the ErrorParser and applies the
* source loader, parsers and transformers on it
*/
#createErrorParser(options: YouchParserOptions) {
const errorParser = new ErrorParser(options)
if (this.#sourceLoader) {
errorParser.defineSourceLoader(this.#sourceLoader)
}
this.#parsers.forEach((parser) => errorParser.useParser(parser))
this.#transformers.forEach((transformer) => errorParser.useTransformer(transformer))

return errorParser
}

/**
* Define custom implementation for loading the source code
* of a stack frame.
*/
defineSourceLoader(loader: SourceLoader): this {
this.#errorParser.defineSourceLoader(loader)
this.#sourceLoader = loader
return this
}

Expand All @@ -46,7 +66,7 @@ export class Youch {
* modify the error
*/
useParser(parser: Parser): this {
this.#errorParser.useParser(parser)
this.#parsers.push(parser)
return this
}

Expand All @@ -56,7 +76,7 @@ export class Youch {
* properties of the parsed error.
*/
useTransformer(transformer: Transformer): this {
this.#errorParser.useTransformer(transformer)
this.#transformers.push(transformer)
return this
}

Expand All @@ -65,7 +85,7 @@ export class Youch {
*/
async toJSON(error: unknown, options?: YouchJSONOptions) {
options = { ...options }
return new ErrorParser({ offset: options.offset }).parse(error)
return this.#createErrorParser({ offset: options.offset }).parse(error)
}

/**
Expand All @@ -74,7 +94,7 @@ export class Youch {
async toHTML(error: unknown, options?: YouchHTMLOptions) {
options = { ...options }

const parsedError = await new ErrorParser({ offset: options.offset }).parse(error)
const parsedError = await this.#createErrorParser({ offset: options.offset }).parse(error)
return this.templates.toHTML({
title: options.title ?? 'An error has occurred',
ide: options.ide ?? process.env.IDE ?? 'vscode',
Expand All @@ -89,7 +109,7 @@ export class Youch {
*/
async toANSI(error: unknown, options?: YouchANSIOptions) {
options = { ...options }
const parsedError = await new ErrorParser({ offset: options.offset }).parse(error)
const parsedError = await this.#createErrorParser({ offset: options.offset }).parse(error)

return this.templates.toANSI({
title: '',
Expand Down
54 changes: 54 additions & 0 deletions tests/youch.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* youch
*
* (c) Poppinss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { test } from '@japa/runner'
import { Youch } from '../src/youch.js'
import { stripAnsi } from '../src/helpers.js'

test.group('Youch', () => {
test('convert error toJSON', async ({ assert }) => {
const parsedError = await new Youch().toJSON(new Error('Something went wrong'))
assert.equal(parsedError.message, 'Something went wrong')
assert.equal(parsedError.frames[0].lineNumber, 16)
})

test('apply parser to the error', async ({ assert }) => {
const parsedError = await new Youch()
.useParser((source) => {
return new Error('Wrapped', { cause: source })
})
.toJSON(new Error('Something went wrong'))

assert.equal(parsedError.message, 'Wrapped')
assert.equal((parsedError.cause as any).message, 'Something went wrong')
assert.equal(parsedError.frames[0].lineNumber, 24)
})

test('apply transformer to the error', async ({ assert }) => {
const parsedError = await new Youch()
.useTransformer((error) => {
error.frames = error.frames.filter((frame) => {
return frame.type === 'app'
})
})
.toJSON(new Error('Something went wrong'))

assert.lengthOf(parsedError.frames, 1)
})

test('convert error to ANSI output', async ({ assert }) => {
const output = await new Youch().toANSI(new Error('Something went wrong'))
assert.include(stripAnsi(output), 'at Object.executor (tests/youch.spec.ts:45:45)')
})

test('convert error to HTML output', async ({ assert }) => {
const output = await new Youch().toHTML(new Error('Something went wrong'))
assert.include(output, 'at Object.executor (tests/youch.spec.ts:51:45)')
})
})

0 comments on commit 05d0612

Please sign in to comment.