Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(v2): blog/docs: add more context in error messages #4989

Merged
merged 2 commits into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 119 additions & 103 deletions packages/docusaurus-plugin-content-blog/src/blogUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
},
});
}),
);

Expand Down
21 changes: 20 additions & 1 deletion packages/docusaurus-plugin-content-docs/src/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -102,7 +103,7 @@ export async function readVersionDocs(
);
}

export function processDocMetadata({
function doProcessDocMetadata({
docFile,
versionMetadata,
context,
Expand Down Expand Up @@ -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;
}
}
33 changes: 30 additions & 3 deletions packages/docusaurus-plugin-content-docs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
getLoadedContentTranslationFiles,
} from './translations';
import {CategoryMetadataFilenamePattern} from './sidebarItemsGenerator';
import chalk from 'chalk';

export default function pluginContentDocs(
context: LoadContext,
Expand Down Expand Up @@ -163,7 +164,7 @@ export default function pluginContentDocs(
return Promise.all(docFiles.map(processVersionDoc));
}

async function loadVersion(
async function doLoadVersion(
versionMetadata: VersionMetadata,
): Promise<LoadedVersion> {
const unprocessedSidebars = loadSidebars(
Expand Down Expand Up @@ -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)),
};
Expand Down Expand Up @@ -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`,
Expand All @@ -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<GlobalPluginData>({
path: normalizeUrl([baseUrl, options.routeBasePath]),
Expand Down