Skip to content

Commit

Permalink
fix: highlight line with error in the error overlay (#11574)
Browse files Browse the repository at this point in the history
* fix: highlight line with error in the error overlay

* chore: changeset

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

Co-authored-by: Bjorn Lu <[email protected]>

---------

Co-authored-by: Bjorn Lu <[email protected]>
  • Loading branch information
Princesseuh and bluwy authored Jul 30, 2024
1 parent 0dcef3a commit e3f29d4
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/old-bats-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes line with the error not being properly highlighted in the error overlay
8 changes: 8 additions & 0 deletions packages/astro/e2e/errors.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
});
9 changes: 6 additions & 3 deletions packages/astro/e2e/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', {
Expand All @@ -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 };
}

/**
Expand Down
34 changes: 31 additions & 3 deletions packages/astro/src/core/errors/dev/vite.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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;

Expand All @@ -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;
},
};
}

0 comments on commit e3f29d4

Please sign in to comment.