refactor, create getLocalizedSource()

This commit is contained in:
sebastienlorber 2024-01-04 20:08:49 +01:00
parent ecf6888840
commit e9b20ca990
5 changed files with 107 additions and 51 deletions

View File

@ -26,6 +26,8 @@ import {
getContentPathList, getContentPathList,
isUnlisted, isUnlisted,
isDraft, isDraft,
filterFilesWithLocaleExtension,
getLocalizedSource,
} from '@docusaurus/utils'; } from '@docusaurus/utils';
import {validateBlogPostFrontMatter} from './frontMatter'; import {validateBlogPostFrontMatter} from './frontMatter';
import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors'; import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors';
@ -208,13 +210,19 @@ async function parseBlogPostMarkdownFile({
const defaultReadingTime: ReadingTimeFunction = ({content, options}) => const defaultReadingTime: ReadingTimeFunction = ({content, options}) =>
readingTime(content, options).minutes; readingTime(content, options).minutes;
async function processBlogSourceFile( async function processBlogSourceFile({
blogSourceRelative: string, blogSourceRelative,
contentPaths: BlogContentPaths, contentPaths,
context: LoadContext, context,
options: PluginOptions, options,
authorsMap?: AuthorsMap, authorsMap,
): Promise<BlogPost | undefined> { }: {
blogSourceRelative: string;
contentPaths: BlogContentPaths;
context: LoadContext;
options: PluginOptions;
authorsMap?: AuthorsMap;
}): Promise<BlogPost | undefined> {
const { const {
siteConfig: { siteConfig: {
baseUrl, baseUrl,
@ -231,21 +239,30 @@ async function processBlogSourceFile(
editUrl, editUrl,
} = options; } = options;
// TODO remove this in favor of getLocalizedSource
// Lookup in localized folder in priority // Lookup in localized folder in priority
const blogDirPath = await getFolderContainingFile( const blogDirPath = await getFolderContainingFile(
getContentPathList(contentPaths), getContentPathList(contentPaths),
blogSourceRelative, blogSourceRelative,
); );
const blogSourceAbsolute = path.join(blogDirPath, blogSourceRelative); const {
source: blogSource,
// contentPath: blogDirPath
} = await getLocalizedSource({
relativeSource: blogSourceRelative,
contentPaths,
locale: context.i18n.currentLocale,
});
const {frontMatter, content, contentTitle, excerpt} = const {frontMatter, content, contentTitle, excerpt} =
await parseBlogPostMarkdownFile({ await parseBlogPostMarkdownFile({
filePath: blogSourceAbsolute, filePath: blogSource,
parseFrontMatter, parseFrontMatter,
}); });
const aliasedSource = aliasedSitePath(blogSourceAbsolute, siteDir); const aliasedSource = aliasedSitePath(blogSource, siteDir);
const draft = isDraft({frontMatter}); const draft = isDraft({frontMatter});
const unlisted = isUnlisted({frontMatter}); const unlisted = isUnlisted({frontMatter});
@ -274,14 +291,14 @@ async function processBlogSourceFile(
} }
try { try {
const result = getFileCommitDate(blogSourceAbsolute, { const result = getFileCommitDate(blogSource, {
age: 'oldest', age: 'oldest',
includeAuthor: false, includeAuthor: false,
}); });
return result.date; return result.date;
} catch (err) { } catch (err) {
logger.warn(err); logger.warn(err);
return (await fs.stat(blogSourceAbsolute)).birthtime; return (await fs.stat(blogSource)).birthtime;
} }
} }
@ -302,7 +319,7 @@ async function processBlogSourceFile(
function getBlogEditUrl() { function getBlogEditUrl() {
const blogPathRelative = path.relative( const blogPathRelative = path.relative(
blogDirPath, blogDirPath,
path.resolve(blogSourceAbsolute), path.resolve(blogSource),
); );
if (typeof editUrl === 'function') { if (typeof editUrl === 'function') {
@ -374,28 +391,36 @@ export async function generateBlogPosts(
return []; return [];
} }
const blogSourceFiles = await Globby(include, { async function getBlogSourceFiles() {
cwd: contentPaths.contentPath, const files = await Globby(include, {
ignore: exclude, cwd: contentPaths.contentPath,
}); ignore: exclude,
});
return filterFilesWithLocaleExtension({
files,
locales: context.i18n.locales,
});
}
const blogSourceFiles = await getBlogSourceFiles();
const authorsMap = await getAuthorsMap({ const authorsMap = await getAuthorsMap({
contentPaths, contentPaths,
authorsMapPath: options.authorsMapPath, authorsMapPath: options.authorsMapPath,
}); });
async function doProcessBlogSourceFile(blogSourceFile: string) { async function doProcessBlogSourceFile(blogSourceRelative: string) {
try { try {
return await processBlogSourceFile( return await processBlogSourceFile({
blogSourceFile, blogSourceRelative,
contentPaths, contentPaths,
context, context,
options, options,
authorsMap, authorsMap,
); });
} catch (err) { } catch (err) {
throw new Error( throw new Error(
`Processing of blog source file path=${blogSourceFile} failed.`, `Processing of blog source file path=${blogSourceRelative} failed.`,
{cause: err as Error}, {cause: err as Error},
); );
} }

View File

@ -72,6 +72,7 @@ yarn workspace v1.22.19image` is a collocated image path, this entry will be the
* preserved as-is. Default values will be applied when generating metadata * preserved as-is. Default values will be applied when generating metadata
*/ */
export type BlogPostFrontMatter = { export type BlogPostFrontMatter = {
// TODO Docusaurus v4: remove
/** /**
* @deprecated Use `slug` instead. * @deprecated Use `slug` instead.
*/ */

View File

@ -21,7 +21,7 @@ import {
parseMarkdownFile, parseMarkdownFile,
isUnlisted, isUnlisted,
isDraft, isDraft,
getLocalizedSourcePath, getLocalizedSource,
filterFilesWithLocaleExtension, filterFilesWithLocaleExtension,
} from '@docusaurus/utils'; } from '@docusaurus/utils';
import {validatePageFrontMatter} from './frontMatter'; import {validatePageFrontMatter} from './frontMatter';
@ -95,7 +95,7 @@ export default function pluginContentPages(
async function processPageSourceFile( async function processPageSourceFile(
relativeSource: string, relativeSource: string,
): Promise<Metadata | undefined> { ): Promise<Metadata | undefined> {
const source = await getLocalizedSourcePath({ const {source} = await getLocalizedSource({
relativeSource, relativeSource,
contentPaths, contentPaths,
locale: context.i18n.currentLocale, locale: context.i18n.currentLocale,

View File

@ -127,13 +127,13 @@ function addLocaleExtension(filePath: string, locale: string) {
return path.join(dir, `${name}.${locale}${ext}`); return path.join(dir, `${name}.${locale}${ext}`);
} }
/** type LocalizedSource = {
* Returns the first existing localized path of a content file contentPath: string;
* @param relativeSource source: string;
* @param contentPaths type: 'locale-extension' | 'locale-folder' | 'original';
* @param locale };
*/
export async function getLocalizedSourcePath({ function getLocalizedSourceCandidates({
relativeSource, relativeSource,
contentPaths, contentPaths,
locale, locale,
@ -141,38 +141,68 @@ export async function getLocalizedSourcePath({
relativeSource: string; relativeSource: string;
contentPaths: ContentPaths; contentPaths: ContentPaths;
locale: string; locale: string;
}): Promise<string> { }): LocalizedSource[] {
// docs/myDoc.fr.md // docs/myDoc.fr.md
const localeExtensionSource = path.join( const localeExtensionSource: LocalizedSource = {
contentPaths.contentPath, contentPath: contentPaths.contentPath,
addLocaleExtension(relativeSource, locale), source: path.join(
); contentPaths.contentPath,
addLocaleExtension(relativeSource, locale),
),
type: 'locale-extension',
};
// i18n/fr/docs/current/myDoc.md // i18n/fr/docs/current/myDoc.md
const i18nFolderSource = path.join( const i18nFolderSource: LocalizedSource = {
contentPaths.contentPathLocalized, contentPath: contentPaths.contentPath,
relativeSource, source: path.join(contentPaths.contentPathLocalized, relativeSource),
); type: 'locale-folder',
};
// docs/myDoc.md // docs/myDoc.md
const originalSource = path.join(contentPaths.contentPath, relativeSource); const originalSource: LocalizedSource = {
contentPath: contentPaths.contentPath,
source: path.join(contentPaths.contentPath, relativeSource),
type: 'original',
};
// Order matters // Order matters
const possibleSources = [ return [localeExtensionSource, i18nFolderSource, originalSource];
localeExtensionSource, }
i18nFolderSource,
originalSource, /**
]; * Returns the first existing localized path of a content file
* @param relativeSource
* @param contentPaths
* @param locale
*/
export async function getLocalizedSource({
relativeSource,
contentPaths,
locale,
}: {
relativeSource: string;
contentPaths: ContentPaths;
locale: string;
}): Promise<LocalizedSource> {
// docs/myDoc.fr.md
const candidates = getLocalizedSourceCandidates({
relativeSource,
contentPaths,
locale,
});
// TODO can we avoid/optimize this by passing all the files we know as param? // TODO can we avoid/optimize this by passing all the files we know as param?
const localizedSource = await findAsyncSequential( const localizedSource = await findAsyncSequential(candidates, (candidate) =>
possibleSources, fs.pathExists(candidate.source),
fs.pathExists,
); );
if (!localizedSource) { if (!localizedSource) {
throw new Error( throw new Error(
`Unexpected error, couldn't find any existing file at ${originalSource}`, `Unexpected error, couldn't find any localized source for file at ${path.join(
contentPaths.contentPath,
relativeSource,
)}`,
); );
} }

View File

@ -34,7 +34,7 @@ export {
updateTranslationFileMessages, updateTranslationFileMessages,
getPluginI18nPath, getPluginI18nPath,
localizePath, localizePath,
getLocalizedSourcePath, getLocalizedSource,
filterFilesWithLocaleExtension, filterFilesWithLocaleExtension,
} from './i18nUtils'; } from './i18nUtils';
export { export {