From adb7faa05f3bd503608596d18a99cbc75243b5f2 Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Wed, 29 Jan 2025 14:15:30 +0100 Subject: [PATCH 1/2] fix: more readable and usable error message when a render error occurs --- src/render/render.ts | 8 ++++- src/render/template-render-error.spec.ts | 18 +++++++++++ src/render/template-render-error.ts | 39 ++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/render/template-render-error.spec.ts create mode 100644 src/render/template-render-error.ts diff --git a/src/render/render.ts b/src/render/render.ts index d5affca51..12ac892cb 100644 --- a/src/render/render.ts +++ b/src/render/render.ts @@ -26,6 +26,7 @@ import { TemplateLoader } from "./template-loader"; import * as filter from "./filter"; import { findTemplate } from "./find-template"; import { createMarkdownRenderer } from "./create-markdown-renderer"; +import { TemplateRenderError } from "./template-render-error"; interface ActiveNavigationLeaf extends NavigationLeaf { active: boolean; @@ -328,7 +329,12 @@ export async function render( try { content = await renderTemplate(template, templateData); } catch (err: unknown) { - const prefix = `Failed to render "${fileInfo.fullPath}"`; + const filename = fileInfo.fullPath; + if (err instanceof Error && err.name === "Template render error") { + /* recreate nunjucks template errors to be a bit more useful and readable */ + throw new TemplateRenderError(err.message, filename); + } + const prefix = `Failed to render "${filename}"`; const message = err instanceof Error ? err.message : String(err); throw new Error(`${prefix}: ${message}`, { cause: err }); } diff --git a/src/render/template-render-error.spec.ts b/src/render/template-render-error.spec.ts new file mode 100644 index 000000000..d57cc3a47 --- /dev/null +++ b/src/render/template-render-error.spec.ts @@ -0,0 +1,18 @@ +import { getActualMessage } from "./template-render-error"; + +it("should extract actual error from nunjucks error", () => { + expect.assertions(1); + const error = [ + "(/path/to/template.html) [Line 8, Column 3]", + " Error: lorem ipsum dolor sit amet", + ].join("\n"); + const result = getActualMessage(error); + expect(result).toBe("lorem ipsum dolor sit amet"); +}); + +it("should return original message if it cannot be matched", () => { + expect.assertions(1); + const error = ["lorem ipsum dolor sit amet"].join("\n"); + const result = getActualMessage(error); + expect(result).toBe("lorem ipsum dolor sit amet"); +}); diff --git a/src/render/template-render-error.ts b/src/render/template-render-error.ts new file mode 100644 index 000000000..422b8fe49 --- /dev/null +++ b/src/render/template-render-error.ts @@ -0,0 +1,39 @@ +const messageRegex = /^[(][^)]+[)] \[Line \d+, Column \d+\]\n\s+Error: (.*)$/; + +/** + * Extracts the actual error message from a nunjucks render error. + * + * The error instance should have properties such as `.cause` but these are lost + * somewhere so this serves as a workaround. + * + * @internal + */ +export function getActualMessage(message: string): string { + const match = message.match(messageRegex); + if (match) { + return match[1].trim(); + } else { + return message; + } +} + +/** + * @internal + */ +export class TemplateRenderError extends Error { + private readonly filename: string; + + public constructor(message: string, filename: string) { + super(getActualMessage(message)); + this.name = "RenderError"; + this.filename = filename; + } + + public prettyError(): string { + return [ + `An error occured when rendering a document.`, + ` Document: "${this.filename}".`, + ` Message: ${this.message}`, + ].join("\n"); + } +} From 8ed2f234bf0667399cdcfd168f9ccfb92525669d Mon Sep 17 00:00:00 2001 From: David Sveningsson Date: Wed, 29 Jan 2025 14:30:41 +0100 Subject: [PATCH 2/2] fix: show original cause when a vue parse error occurs --- internal/plugin-vue3/src/generate-code.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/plugin-vue3/src/generate-code.ts b/internal/plugin-vue3/src/generate-code.ts index e407f5924..40a256249 100644 --- a/internal/plugin-vue3/src/generate-code.ts +++ b/internal/plugin-vue3/src/generate-code.ts @@ -35,8 +35,11 @@ export function generateCode(options: ExampleOptions): ExampleResult { const { descriptor, errors } = parse(code, { filename }); const scopeId = `data-v-${fingerprint}`; - if (errors.length) { - throw new Error(`Errors occured when trying to parse ${filename}.`); + if (errors.length > 0) { + const first = errors[0].message; + throw new Error( + `Errors occured when trying to parse "${filename}": ${first}`, + ); } const hasScoped = descriptor.styles.some((e) => e.scoped);