From c4726d7ba8cc93157390ce64d5c8b718ed5cac29 Mon Sep 17 00:00:00 2001 From: Arpan Patel Date: Wed, 6 Nov 2024 08:22:38 -0500 Subject: [PATCH] fix: show file name with invalid frontmatter errors for MDX (#12355) Co-authored-by: Emanuele Stoppa Co-authored-by: Princesseuh <3019731+Princesseuh@users.noreply.github.com> --- .changeset/wise-bulldogs-jump.md | 5 ++ packages/astro/src/cli/index.ts | 4 +- packages/astro/src/cli/sync/index.ts | 7 +- packages/astro/src/core/errors/errors-data.ts | 2 +- packages/astro/src/core/messages.ts | 5 ++ packages/astro/src/core/sync/index.ts | 90 ++++++++----------- 6 files changed, 50 insertions(+), 63 deletions(-) create mode 100644 .changeset/wise-bulldogs-jump.md diff --git a/.changeset/wise-bulldogs-jump.md b/.changeset/wise-bulldogs-jump.md new file mode 100644 index 0000000000..58900bc58d --- /dev/null +++ b/.changeset/wise-bulldogs-jump.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Improves error reporting for invalid frontmatter in MDX files during the `astro build` command. The error message now includes the file path where the frontmatter parsing failed. diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index a963b84143..8511a83049 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -133,8 +133,8 @@ async function runCommand(cmd: string, flags: yargs.Arguments) { } case 'sync': { const { sync } = await import('./sync/index.js'); - const exitCode = await sync({ flags }); - return process.exit(exitCode); + await sync({ flags }); + return; } case 'preferences': { const { preferences } = await import('./preferences/index.js'); diff --git a/packages/astro/src/cli/sync/index.ts b/packages/astro/src/cli/sync/index.ts index 7ffe662c5c..7f488836d6 100644 --- a/packages/astro/src/cli/sync/index.ts +++ b/packages/astro/src/cli/sync/index.ts @@ -22,10 +22,5 @@ export async function sync({ flags }: SyncOptions) { return 0; } - try { - await _sync(flagsToAstroInlineConfig(flags), { telemetry: true }); - return 0; - } catch (_) { - return 1; - } + await _sync(flagsToAstroInlineConfig(flags), { telemetry: true }); } diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index ed805eaffb..e8492584a9 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -1388,7 +1388,7 @@ export const GenerateContentTypesError = { title: 'Failed to generate content types.', message: (errorMessage: string) => `\`astro sync\` command failed to generate content collection types: ${errorMessage}`, - hint: 'Check your `src/content/config.*` file for typos.', + hint: 'This error is often caused by a syntax error inside your content, or your content configuration file. Check your `src/content/config.*` file for typos.', } satisfies ErrorData; /** * @docs diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index 3081c0b6cf..57c44b0650 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -298,6 +298,11 @@ export function formatErrorMessage(err: ErrorWithMetadata, showFullStacktrace: b output.push(` ${cyan(underline(docsLink))}`); } + if (showFullStacktrace && err.loc) { + output.push(` ${bold('Location:')}`); + output.push(` ${underline(`${err.loc.file}:${err.loc.line ?? 0}:${err.loc.column ?? 0}`)}`); + } + if (err.stack) { output.push(` ${bold('Stack trace:')}`); output.push(dim(formatErrorStackTrace(err, showFullStacktrace))); diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 75acbe2c84..a4ee18702c 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -23,6 +23,7 @@ import { AstroError, AstroErrorData, AstroUserError, + type ErrorWithMetadata, createSafeError, isAstroError, } from '../errors/index.js'; @@ -62,17 +63,7 @@ export default async function sync( logger, }); - // Run `astro:config:done` - // Actions will throw if there is misconfiguration, so catch here. - try { - await runHookConfigDone({ settings, logger }); - } catch (err) { - if (err instanceof Error) { - const errorMessage = err.toString(); - logger.error('sync', errorMessage); - } - throw err; - } + await runHookConfigDone({ settings, logger }); return await syncInternal({ settings, logger, fs, force: inlineConfig.force }); } @@ -112,51 +103,41 @@ export async function syncInternal({ const timerStart = performance.now(); - try { - if (!skip?.content) { - await syncContentCollections(settings, { fs, logger }); - settings.timer.start('Sync content layer'); - let store: MutableDataStore | undefined; - try { - const dataStoreFile = getDataStoreFile(settings); - if (existsSync(dataStoreFile)) { - store = await MutableDataStore.fromFile(dataStoreFile); - } - } catch (err: any) { - logger.error('content', err.message); + if (!skip?.content) { + await syncContentCollections(settings, { fs, logger }); + settings.timer.start('Sync content layer'); + let store: MutableDataStore | undefined; + try { + const dataStoreFile = getDataStoreFile(settings); + if (existsSync(dataStoreFile)) { + store = await MutableDataStore.fromFile(dataStoreFile); } - if (!store) { - store = new MutableDataStore(); - } - const contentLayer = globalContentLayer.init({ - settings, - logger, - store, - }); - await contentLayer.sync(); - settings.timer.end('Sync content layer'); - } else if (fs.existsSync(fileURLToPath(getContentPaths(settings.config, fs).contentDir))) { - // Content is synced after writeFiles. That means references are not created - // To work around it, we create a stub so the reference is created and content - // sync will override the empty file - settings.injectedTypes.push({ - filename: CONTENT_TYPES_FILE, - content: '', - }); + } catch (err: any) { + logger.error('content', err.message); } - syncAstroEnv(settings, fs); - - await writeFiles(settings, fs, logger); - logger.info('types', `Generated ${dim(getTimeStat(timerStart, performance.now()))}`); - } catch (err) { - const error = createSafeError(err); - logger.error( - 'types', - formatErrorMessage(collectErrorMetadata(error), logger.level() === 'debug') + '\n', - ); - // Will return exit code 1 in CLI - throw error; + if (!store) { + store = new MutableDataStore(); + } + const contentLayer = globalContentLayer.init({ + settings, + logger, + store, + }); + await contentLayer.sync(); + settings.timer.end('Sync content layer'); + } else if (fs.existsSync(fileURLToPath(getContentPaths(settings.config, fs).contentDir))) { + // Content is synced after writeFiles. That means references are not created + // To work around it, we create a stub so the reference is created and content + // sync will override the empty file + settings.injectedTypes.push({ + filename: CONTENT_TYPES_FILE, + content: '', + }); } + syncAstroEnv(settings, fs); + + await writeFiles(settings, fs, logger); + logger.info('types', `Generated ${dim(getTimeStat(timerStart, performance.now()))}`); } /** @@ -223,7 +204,7 @@ async function syncContentCollections( } } } catch (e) { - const safeError = createSafeError(e); + const safeError = createSafeError(e) as ErrorWithMetadata; if (isAstroError(e)) { throw e; } @@ -233,6 +214,7 @@ async function syncContentCollections( ...AstroErrorData.GenerateContentTypesError, hint, message: AstroErrorData.GenerateContentTypesError.message(safeError.message), + location: safeError.loc, }, { cause: e }, );