diff --git a/.changeset/wild-bobcats-carry.md b/.changeset/wild-bobcats-carry.md new file mode 100644 index 0000000000..ef66ca9524 --- /dev/null +++ b/.changeset/wild-bobcats-carry.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Add a new `astro/errors` module. Developers can import `AstroUserError`, and provide a `message` and an optional `hint` diff --git a/packages/astro/package.json b/packages/astro/package.json index 8e505e8b09..c52c93ea3d 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -69,6 +69,7 @@ "types": "./zod.d.ts", "default": "./zod.mjs" }, + "./errors": "./dist/core/errors/userError.js", "./middleware": { "types": "./dist/core/middleware/index.d.ts", "default": "./dist/core/middleware/index.js" diff --git a/packages/astro/src/core/errors/errors.ts b/packages/astro/src/core/errors/errors.ts index 1960bac4a8..faf3656869 100644 --- a/packages/astro/src/core/errors/errors.ts +++ b/packages/astro/src/core/errors/errors.ts @@ -19,6 +19,7 @@ export interface ErrorLocation { type ErrorTypes = | 'AstroError' + | 'AstroUserError' | 'CompilerError' | 'CSSError' | 'MarkdownError' @@ -171,3 +172,25 @@ export interface ErrorWithMetadata { }; cause?: any; } + +/** + * Special error that is exposed to users. + * Compared to AstroError, it contains a subset of information. + */ +export class AstroUserError extends Error { + type: ErrorTypes = 'AstroUserError'; + /** + * A message that explains to the user how they can fix the error. + */ + hint: string | undefined; + name = 'AstroUserError'; + constructor(message: string, hint?: string) { + super(); + this.message = message; + this.hint = hint; + } + + static is(err: unknown): err is AstroUserError { + return (err as AstroUserError).type === 'AstroUserError'; + } +} diff --git a/packages/astro/src/core/errors/index.ts b/packages/astro/src/core/errors/index.ts index e09225af42..5a796a0b3f 100644 --- a/packages/astro/src/core/errors/index.ts +++ b/packages/astro/src/core/errors/index.ts @@ -7,6 +7,7 @@ export { CompilerError, MarkdownError, isAstroError, + AstroUserError, } from './errors.js'; export { codeFrame } from './printer.js'; export { createSafeError, positionAt } from './utils.js'; diff --git a/packages/astro/src/core/errors/userError.ts b/packages/astro/src/core/errors/userError.ts new file mode 100644 index 0000000000..6635493145 --- /dev/null +++ b/packages/astro/src/core/errors/userError.ts @@ -0,0 +1 @@ +export { AstroUserError as AstroError } from './errors.js'; diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index 51ec39ad92..4fc3ca02a4 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -17,7 +17,12 @@ import { import type { ResolvedServerUrls } from 'vite'; import type { ZodError } from 'zod'; import { renderErrorMarkdown } from './errors/dev/utils.js'; -import { AstroError, CompilerError, type ErrorWithMetadata } from './errors/index.js'; +import { + AstroError, + CompilerError, + type ErrorWithMetadata, + AstroUserError, +} from './errors/index.js'; import { emoji, padMultilineString } from './util.js'; const PREFIX_PADDING = 6; @@ -198,7 +203,7 @@ export function formatConfigErrorMessage(err: ZodError) { } export function formatErrorMessage(err: ErrorWithMetadata, args: string[] = []): string { - const isOurError = AstroError.is(err) || CompilerError.is(err); + const isOurError = AstroError.is(err) || CompilerError.is(err) || AstroUserError.is(err); args.push( `${bgRed(black(` error `))}${red(