From 57908ff7254d9e8c6e55b1a913d45b5e40acf35f Mon Sep 17 00:00:00 2001 From: slorber Date: Wed, 16 Jun 2021 20:02:08 +0200 Subject: [PATCH 1/2] refactor(v2): blog/docs: add more context in error messages --- .../src/blogUtils.ts | 222 ++++++++++-------- .../src/docs.ts | 21 +- 2 files changed, 139 insertions(+), 104 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 94bf7124f03b..b675a9684a29 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -55,6 +55,19 @@ function toUrl({date, link}: DateLink) { .replace(/-/g, '/')}/${link}`; } +function formatBlogPostDate(locale: string, date: Date): string { + try { + return new Intl.DateTimeFormat(locale, { + day: 'numeric', + month: 'long', + year: 'numeric', + timeZone: 'UTC', + }).format(date); + } catch (e) { + throw new Error(`Can't format blog post date "${date}"`); + } +} + export async function generateBlogFeed( contentPaths: BlogContentPaths, context: LoadContext, @@ -131,123 +144,126 @@ export async function generateBlogPosts( const blogPosts: BlogPost[] = []; - await Promise.all( - blogSourceFiles.map(async (blogSourceFile: string) => { - // Lookup in localized folder in priority - const blogDirPath = await getFolderContainingFile( - getContentPathList(contentPaths), - blogSourceFile, - ); + async function processBlogSourceFile(blogSourceFile: string) { + // Lookup in localized folder in priority + const blogDirPath = await getFolderContainingFile( + getContentPathList(contentPaths), + blogSourceFile, + ); - const source = path.join(blogDirPath, blogSourceFile); + const source = path.join(blogDirPath, blogSourceFile); - const { - frontMatter: unsafeFrontMatter, - content, - contentTitle, - excerpt, - } = await parseMarkdownFile(source, {removeContentTitle: true}); - const frontMatter = validateBlogPostFrontMatter(unsafeFrontMatter); + const { + frontMatter: unsafeFrontMatter, + content, + contentTitle, + excerpt, + } = await parseMarkdownFile(source, {removeContentTitle: true}); + const frontMatter = validateBlogPostFrontMatter(unsafeFrontMatter); + + const aliasedSource = aliasedSitePath(source, siteDir); + + const blogFileName = path.basename(blogSourceFile); + + if (frontMatter.draft && process.env.NODE_ENV === 'production') { + return; + } + + if (frontMatter.id) { + console.warn( + chalk.yellow( + `"id" header option is deprecated in ${blogFileName} file. Please use "slug" option instead.`, + ), + ); + } - const aliasedSource = aliasedSitePath(source, siteDir); + let date: Date | undefined; + // Extract date and title from filename. + const dateFilenameMatch = blogFileName.match(DATE_FILENAME_PATTERN); + let linkName = blogFileName.replace(/\.mdx?$/, ''); - const blogFileName = path.basename(blogSourceFile); + if (dateFilenameMatch) { + const [, dateString, name] = dateFilenameMatch; + // Always treat dates as UTC by adding the `Z` + date = new Date(`${dateString}Z`); + linkName = name; + } - if (frontMatter.draft && process.env.NODE_ENV === 'production') { - return; - } + // Prefer user-defined date. + if (frontMatter.date) { + date = frontMatter.date; + } - if (frontMatter.id) { - console.warn( - chalk.yellow( - `"id" header option is deprecated in ${blogFileName} file. Please use "slug" option instead.`, - ), - ); - } + // Use file create time for blog. + date = date ?? (await fs.stat(source)).birthtime; + const formattedDate = formatBlogPostDate(i18n.currentLocale, date); - let date: Date | undefined; - // Extract date and title from filename. - const dateFilenameMatch = blogFileName.match(DATE_FILENAME_PATTERN); - let linkName = blogFileName.replace(/\.mdx?$/, ''); + const title = frontMatter.title ?? contentTitle ?? linkName; + const description = frontMatter.description ?? excerpt ?? ''; - if (dateFilenameMatch) { - const [, dateString, name] = dateFilenameMatch; - // Always treat dates as UTC by adding the `Z` - date = new Date(`${dateString}Z`); - linkName = name; - } + const slug = + frontMatter.slug || + (dateFilenameMatch ? toUrl({date, link: linkName}) : linkName); - // Prefer user-defined date. - if (frontMatter.date) { - date = frontMatter.date; - } - - // Use file create time for blog. - date = date ?? (await fs.stat(source)).birthtime; - const formattedDate = new Intl.DateTimeFormat(i18n.currentLocale, { - day: 'numeric', - month: 'long', - year: 'numeric', - timeZone: 'UTC', - }).format(date); + const permalink = normalizeUrl([baseUrl, routeBasePath, slug]); - const title = frontMatter.title ?? contentTitle ?? linkName; - const description = frontMatter.description ?? excerpt ?? ''; + function getBlogEditUrl() { + const blogPathRelative = path.relative(blogDirPath, path.resolve(source)); - const slug = - frontMatter.slug || - (dateFilenameMatch ? toUrl({date, link: linkName}) : linkName); - - const permalink = normalizeUrl([baseUrl, routeBasePath, slug]); + if (typeof editUrl === 'function') { + return editUrl({ + blogDirPath: posixPath(path.relative(siteDir, blogDirPath)), + blogPath: posixPath(blogPathRelative), + permalink, + locale: i18n.currentLocale, + }); + } else if (typeof editUrl === 'string') { + const isLocalized = blogDirPath === contentPaths.contentPathLocalized; + const fileContentPath = + isLocalized && options.editLocalizedFiles + ? contentPaths.contentPathLocalized + : contentPaths.contentPath; + + const contentPathEditUrl = normalizeUrl([ + editUrl, + posixPath(path.relative(siteDir, fileContentPath)), + ]); + + return getEditUrl(blogPathRelative, contentPathEditUrl); + } else { + return undefined; + } + } + + blogPosts.push({ + id: frontMatter.slug ?? title, + metadata: { + permalink, + editUrl: getBlogEditUrl(), + source: aliasedSource, + title, + description, + date, + formattedDate, + tags: frontMatter.tags ?? [], + readingTime: showReadingTime ? readingTime(content).minutes : undefined, + truncated: truncateMarker?.test(content) || false, + }, + }); + } - function getBlogEditUrl() { - const blogPathRelative = path.relative( - blogDirPath, - path.resolve(source), + await Promise.all( + blogSourceFiles.map(async (blogSourceFile: string) => { + try { + return await processBlogSourceFile(blogSourceFile); + } catch (e) { + console.error( + chalk.red( + `Processing of blog source file failed for path "${blogSourceFile}"`, + ), ); - - if (typeof editUrl === 'function') { - return editUrl({ - blogDirPath: posixPath(path.relative(siteDir, blogDirPath)), - blogPath: posixPath(blogPathRelative), - permalink, - locale: i18n.currentLocale, - }); - } else if (typeof editUrl === 'string') { - const isLocalized = blogDirPath === contentPaths.contentPathLocalized; - const fileContentPath = - isLocalized && options.editLocalizedFiles - ? contentPaths.contentPathLocalized - : contentPaths.contentPath; - - const contentPathEditUrl = normalizeUrl([ - editUrl, - posixPath(path.relative(siteDir, fileContentPath)), - ]); - - return getEditUrl(blogPathRelative, contentPathEditUrl); - } else { - return undefined; - } + throw e; } - - blogPosts.push({ - id: frontMatter.slug ?? title, - metadata: { - permalink, - editUrl: getBlogEditUrl(), - source: aliasedSource, - title, - description, - date, - formattedDate, - tags: frontMatter.tags ?? [], - readingTime: showReadingTime - ? readingTime(content).minutes - : undefined, - truncated: truncateMarker?.test(content) || false, - }, - }); }), ); diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index e2d8b6bd1166..114ffd82cb68 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -32,6 +32,7 @@ import globby from 'globby'; import {getDocsDirPaths} from './versions'; import {stripPathNumberPrefixes} from './numberPrefix'; import {validateDocFrontMatter} from './docFrontMatter'; +import chalk from 'chalk'; type LastUpdateOptions = Pick< PluginOptions, @@ -102,7 +103,7 @@ export async function readVersionDocs( ); } -export function processDocMetadata({ +function doProcessDocMetadata({ docFile, versionMetadata, context, @@ -262,3 +263,21 @@ export function processDocMetadata({ frontMatter, }; } + +export function processDocMetadata(args: { + docFile: DocFile; + versionMetadata: VersionMetadata; + context: LoadContext; + options: MetadataOptions; +}): DocMetadataBase { + try { + return doProcessDocMetadata(args); + } catch (e) { + console.error( + chalk.red( + `Can't process doc metadatas for doc at path "${args.docFile.filePath}" in version "${args.versionMetadata.versionName}"`, + ), + ); + throw e; + } +} From b4a07ea1e96b32fe5246ef756be6f1c4e0a96d30 Mon Sep 17 00:00:00 2001 From: slorber Date: Wed, 16 Jun 2021 20:09:14 +0200 Subject: [PATCH 2/2] more error handling --- .../src/index.ts | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index e54f11c243a8..e836ca302697 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -49,6 +49,7 @@ import { getLoadedContentTranslationFiles, } from './translations'; import {CategoryMetadataFilenamePattern} from './sidebarItemsGenerator'; +import chalk from 'chalk'; export default function pluginContentDocs( context: LoadContext, @@ -163,7 +164,7 @@ export default function pluginContentDocs( return Promise.all(docFiles.map(processVersionDoc)); } - async function loadVersion( + async function doLoadVersion( versionMetadata: VersionMetadata, ): Promise { const unprocessedSidebars = loadSidebars( @@ -267,6 +268,19 @@ export default function pluginContentDocs( }; } + async function loadVersion(versionMetadata: VersionMetadata) { + try { + return await doLoadVersion(versionMetadata); + } catch (e) { + console.error( + chalk.red( + `Loading of version failed for version "${versionMetadata.versionName}"`, + ), + ); + throw e; + } + } + return { loadedVersions: await Promise.all(versionsMetadata.map(loadVersion)), }; @@ -307,7 +321,7 @@ export default function pluginContentDocs( return routes.sort((a, b) => a.path.localeCompare(b.path)); }; - async function handleVersion(loadedVersion: LoadedVersion) { + async function doCreateVersionRoutes(loadedVersion: LoadedVersion) { const versionMetadataPropPath = await createData( `${docuHash( `version-${loadedVersion.versionName}-metadata-prop`, @@ -334,7 +348,20 @@ export default function pluginContentDocs( }); } - await Promise.all(loadedVersions.map(handleVersion)); + async function createVersionRoutes(loadedVersion: LoadedVersion) { + try { + return await doCreateVersionRoutes(loadedVersion); + } catch (e) { + console.error( + chalk.red( + `Can't create version routes for version "${loadedVersion.versionName}"`, + ), + ); + throw e; + } + } + + await Promise.all(loadedVersions.map(createVersionRoutes)); setGlobalData({ path: normalizeUrl([baseUrl, options.routeBasePath]),