0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

fix: highlight line with error in the error overlay (#11574)

* fix: highlight line with error in the error overlay

* chore: changeset

* Update packages/astro/e2e/errors.test.js

Co-authored-by: Bjorn Lu <bjornlu.dev@gmail.com>

---------

Co-authored-by: Bjorn Lu <bjornlu.dev@gmail.com>
This commit is contained in:
Erika 2024-07-30 15:26:51 +02:00 committed by GitHub
parent 0dcef3ab17
commit e3f29d416a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 50 additions and 6 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes line with the error not being properly highlighted in the error overlay

View file

@ -131,4 +131,12 @@ test.describe('Error display', () => {
const message = (await getErrorOverlayContent(page)).message;
expect(message).toMatch('The operation was aborted due to timeout');
});
test('properly highlight the line with the error', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/import-not-found'), { waitUntil: 'networkidle' });
const { codeFrame } = await getErrorOverlayContent(page);
const codeFrameContent = await codeFrame.innerHTML();
expect(codeFrameContent).toContain('error-line');
});
});

View file

@ -51,8 +51,8 @@ export function testFactory(inlineConfig) {
/**
*
* @param {string} page
* @returns {Promise<{message: string, hint: string, absoluteFileLocation: string, fileLocation: string}>}
* @param {import('@playwright/test').Page} page
* @returns {Promise<{message: string, hint: string, absoluteFileLocation: string, fileLocation: string, codeFrame: import('@playwright/test').ElementHandle}>}
*/
export async function getErrorOverlayContent(page) {
const overlay = await page.waitForSelector('vite-error-overlay', {
@ -68,7 +68,10 @@ export async function getErrorOverlayContent(page) {
m[0].title,
m[0].textContent,
]);
return { message, hint, absoluteFileLocation, fileLocation };
const codeFrame = await overlay.$('#code pre code');
return { message, hint, absoluteFileLocation, fileLocation, codeFrame };
}
/**

View file

@ -1,6 +1,7 @@
import * as fs from 'node:fs';
import { fileURLToPath } from 'node:url';
import { codeToHtml, createCssVariablesTheme } from 'shiki';
import type { ShikiTransformer } from 'shiki';
import type { ErrorPayload } from 'vite';
import type { ModuleLoader } from '../../module-loader/index.js';
import { FailedToLoadModuleSSR, InvalidGlob, MdxIntegrationMissingError } from '../errors-data.js';
@ -151,10 +152,13 @@ export async function getViteErrorPayload(err: ErrorWithMetadata): Promise<Astro
}
const highlightedCode = err.fullCode
? await codeToHtml(err.fullCode, {
// @ts-expect-error always assume that shiki can accept the lang string
lang: highlighterLang,
lang: highlighterLang ?? 'text',
theme: cssVariablesTheme(),
lineOptions: err.loc?.line ? [{ line: err.loc.line, classes: ['error-line'] }] : undefined,
transformers: [
transformerCompactLineOptions(
err.loc?.line ? [{ line: err.loc.line, classes: ['error-line'] }] : undefined
),
],
})
: undefined;
@ -180,3 +184,27 @@ export async function getViteErrorPayload(err: ErrorWithMetadata): Promise<Astro
},
};
}
/**
* Transformer for `shiki`'s legacy `lineOptions`, allows to add classes to specific lines
* FROM: https://github.com/shikijs/shiki/blob/4a58472070a9a359a4deafec23bb576a73e24c6a/packages/transformers/src/transformers/compact-line-options.ts
* LICENSE: https://github.com/shikijs/shiki/blob/4a58472070a9a359a4deafec23bb576a73e24c6a/LICENSE
*/
export function transformerCompactLineOptions(
lineOptions: {
/**
* 1-based line number.
*/
line: number;
classes?: string[];
}[] = []
): ShikiTransformer {
return {
name: '@shikijs/transformers:compact-line-options',
line(node, line) {
const lineOption = lineOptions.find((o) => o.line === line);
if (lineOption?.classes) this.addClassToHast(node, lineOption.classes);
return node;
},
};
}