Skip to content

Commit 46c4c0e

Browse files
authored
feat(cli): Add docs error link to errors in the CLI (#8251)
1 parent ed39fbf commit 46c4c0e

File tree

4 files changed

+31
-15
lines changed

4 files changed

+31
-15
lines changed

.changeset/chatty-ways-hunt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Adds a link to the error reference in the CLI when an error occurs

packages/astro/src/core/errors/dev/utils.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { normalizePath } from 'vite';
99
import type { SSRError } from '../../../@types/astro.js';
1010
import { removeLeadingForwardSlashWindows } from '../../path.js';
1111
import { AggregateError, type ErrorWithMetadata } from '../errors.js';
12+
import { AstroErrorData } from '../index.js';
1213
import { codeFrame } from '../printer.js';
1314
import { normalizeLF } from '../utils.js';
1415

@@ -206,13 +207,29 @@ function cleanErrorStack(stack: string) {
206207
.join('\n');
207208
}
208209

210+
export function getDocsForError(err: ErrorWithMetadata): string | undefined {
211+
if (err.name in AstroErrorData) {
212+
return `https://docs.astro.build/en/reference/errors/${getKebabErrorName(err.name)}/`;
213+
}
214+
215+
return undefined;
216+
217+
/**
218+
* The docs has kebab-case urls for errors, so we need to convert the error name
219+
* @param errorName
220+
*/
221+
function getKebabErrorName(errorName: string): string {
222+
return errorName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
223+
}
224+
}
225+
209226
/**
210227
* Render a subset of Markdown to HTML or a CLI output
211228
*/
212229
export function renderErrorMarkdown(markdown: string, target: 'html' | 'cli') {
213230
const linkRegex = /\[(.+)\]\((.+)\)/gm;
214231
const boldRegex = /\*\*(.+)\*\*/gm;
215-
const urlRegex = / (\b(https?|ftp):\/\/[-A-Z0-9+&@#\\/%?=~_|!:,.;]*[-A-Z0-9+&@#\\/%=~_|]) /gim;
232+
const urlRegex = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\\/%?=~_|!:,.;]*[-A-Z0-9+&@#\\/%=~_|])/gim;
216233
const codeRegex = /`([^`]+)`/gim;
217234

218235
if (target === 'html') {

packages/astro/src/core/errors/dev/vite.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { FailedToLoadModuleSSR, InvalidGlob, MdxIntegrationMissingError } from '
77
import { AstroError, type ErrorWithMetadata } from '../errors.js';
88
import { createSafeError } from '../utils.js';
99
import type { SSRLoadedRenderer } from './../../../@types/astro.js';
10-
import { renderErrorMarkdown } from './utils.js';
10+
import { getDocsForError, renderErrorMarkdown } from './utils.js';
1111

1212
export function enhanceViteSSRError({
1313
error,
@@ -137,10 +137,7 @@ export async function getViteErrorPayload(err: ErrorWithMetadata): Promise<Astro
137137
const message = renderErrorMarkdown(err.message.trim(), 'html');
138138
const hint = err.hint ? renderErrorMarkdown(err.hint.trim(), 'html') : undefined;
139139

140-
const hasDocs = !!err.name;
141-
const docslink = hasDocs
142-
? `https://docs.astro.build/en/reference/errors/${getKebabErrorName(err.name)}/`
143-
: undefined;
140+
const docslink = getDocsForError(err);
144141

145142
const highlighter = await getHighlighter({ theme: 'css-variables' });
146143
let highlighterLang = err.loc?.file?.split('.').pop();
@@ -178,12 +175,4 @@ export async function getViteErrorPayload(err: ErrorWithMetadata): Promise<Astro
178175
cause: err.cause,
179176
},
180177
};
181-
182-
/**
183-
* The docs has kebab-case urls for errors, so we need to convert the error name
184-
* @param errorName
185-
*/
186-
function getKebabErrorName(errorName: string): string {
187-
return errorName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
188-
}
189178
}

packages/astro/src/core/messages.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
} from 'kleur/colors';
1717
import type { ResolvedServerUrls } from 'vite';
1818
import type { ZodError } from 'zod';
19-
import { renderErrorMarkdown } from './errors/dev/utils.js';
19+
import { getDocsForError, renderErrorMarkdown } from './errors/dev/utils.js';
2020
import {
2121
AstroError,
2222
AstroUserError,
@@ -216,6 +216,11 @@ export function formatErrorMessage(err: ErrorWithMetadata, args: string[] = []):
216216
yellow(padMultilineString(isOurError ? renderErrorMarkdown(err.hint, 'cli') : err.hint, 4))
217217
);
218218
}
219+
const docsLink = getDocsForError(err);
220+
if (docsLink) {
221+
args.push(` ${bold('Error reference:')}`);
222+
args.push(` ${underline(docsLink)}`);
223+
}
219224
if (err.id || err.loc?.file) {
220225
args.push(` ${bold('File:')}`);
221226
args.push(

0 commit comments

Comments
 (0)