feat(blog): authors page (#10216)

Co-authored-by: OzakIOne <OzakIOne@users.noreply.github.com>
Co-authored-by: sebastien <lorber.sebastien@gmail.com>
Co-authored-by: slorber <slorber@users.noreply.github.com>
This commit is contained in:
ozaki 2024-08-01 17:30:49 +02:00 committed by GitHub
parent 50f9fce29b
commit f356e29938
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 1670 additions and 706 deletions

View file

@ -0,0 +1 @@
{"content": "json"}

View file

@ -0,0 +1 @@
content: original yaml

View file

@ -0,0 +1 @@
}{{{{12434665¨£%£%%£%£}}}}

View file

@ -0,0 +1 @@
content: localized yaml

View file

@ -10,7 +10,7 @@ import {
findFolderContainingFile,
getFolderContainingFile,
getDataFilePath,
getDataFileData,
readDataFile,
} from '../dataFileUtils';
describe('getDataFilePath', () => {
@ -125,46 +125,40 @@ describe('getDataFilePath', () => {
});
describe('getDataFileData', () => {
const fixturesDir = path.join(__dirname, '__fixtures__/dataFiles/actualData');
function readDataFile(filePath: string) {
return getDataFileData(
{
filePath,
contentPaths: {contentPath: fixturesDir, contentPathLocalized: ''},
fileType: 'test',
},
(content) => {
// @ts-expect-error: good enough
if (content.a !== 1) {
throw new Error('Nope');
}
return content;
},
function testFile(filePath: string) {
const contentPath = path.join(
__dirname,
'__fixtures__/dataFiles/dataFiles',
);
const contentPathLocalized = path.join(contentPath, 'localized');
return readDataFile({
filePath,
contentPaths: {contentPath, contentPathLocalized},
});
}
it('returns undefined for nonexistent file', async () => {
await expect(readDataFile('nonexistent.yml')).resolves.toBeUndefined();
});
it('read valid yml author file', async () => {
await expect(readDataFile('valid.yml')).resolves.toEqual({a: 1});
await expect(testFile('nonexistent.yml')).resolves.toBeUndefined();
});
it('read valid json author file', async () => {
await expect(readDataFile('valid.json')).resolves.toEqual({a: 1});
await expect(testFile('dataFile.json')).resolves.toEqual({
content: 'json',
});
});
it('fail to read invalid yml', async () => {
await expect(
readDataFile('bad.yml'),
).rejects.toThrowErrorMatchingInlineSnapshot(`"Nope"`);
it('read valid yml author file using localized source in priority', async () => {
await expect(testFile('dataFile.yml')).resolves.toEqual({
content: 'localized yaml',
});
});
it('fail to read invalid json', async () => {
it('throw for invalid file', async () => {
await expect(
readDataFile('bad.json'),
).rejects.toThrowErrorMatchingInlineSnapshot(`"Nope"`);
testFile('invalid.yml'),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"The file at "packages/docusaurus-utils/src/__tests__/__fixtures__/dataFiles/dataFiles/invalid.yml" looks invalid (not Yaml nor JSON)."`,
);
});
});

View file

@ -43,31 +43,28 @@ export async function getDataFilePath({
}
/**
* Looks up for a data file in the content paths, returns the object validated
* and normalized according to the `validate` callback.
* Looks up for a data file in the content paths
* Favors the localized content path over the base content path
* Currently supports Yaml and JSON data files
* It is the caller responsibility to validate and normalize the resulting data
*
* @returns `undefined` when file not found
* @throws Throws when validation fails, displaying a helpful context message.
* @throws Throws when data file can't be parsed
*/
export async function getDataFileData<T>(
params: DataFileParams & {
/** Used for the "The X file looks invalid" message. */
fileType: string;
},
validate: (content: unknown) => T,
): Promise<T | undefined> {
export async function readDataFile(params: DataFileParams): Promise<unknown> {
const filePath = await getDataFilePath(params);
if (!filePath) {
return undefined;
}
try {
const contentString = await fs.readFile(filePath, {encoding: 'utf8'});
const unsafeContent = Yaml.load(contentString);
// TODO we shouldn't validate here: it makes validation harder to test
return validate(unsafeContent);
return Yaml.load(contentString);
} catch (err) {
logger.error`The ${params.fileType} file at path=${filePath} looks invalid.`;
throw err;
const msg = logger.interpolate`The file at path=${path.relative(
process.cwd(),
filePath,
)} looks invalid (not Yaml nor JSON).`;
throw new Error(msg, {cause: err as Error});
}
}

View file

@ -109,7 +109,7 @@ export {escapeShellArg} from './shellUtils';
export {loadFreshModule} from './moduleUtils';
export {
getDataFilePath,
getDataFileData,
readDataFile,
getContentPathList,
findFolderContainingFile,
getFolderContainingFile,

View file

@ -45,6 +45,7 @@ export type TagsListItem = Tag & {
/** What the tag's own page should know about the tag. */
export type TagModule = TagsListItem & {
/** The tags list page's permalink. */
// TODO move this global value to a shared docs/blog bundle
allTagsPath: string;
/** Is this tag unlisted? (when it only contains unlisted items) */
unlisted: boolean;