fix(blog): normalize inline authors socials (#10424)
Some checks are pending
Argos CI / take-screenshots (push) Waiting to run
Build Hash Router / Build Hash Router (push) Waiting to run
Canary Release / Publish Canary (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Continuous Releases / Continuous Releases (push) Waiting to run
E2E Tests / E2E — Yarn v1 (18.0) (push) Waiting to run
E2E Tests / E2E — Yarn v1 (20) (push) Waiting to run
E2E Tests / E2E — Yarn v1 (22) (push) Waiting to run
E2E Tests / E2E — Yarn Berry (node-modules, -s) (push) Waiting to run
E2E Tests / E2E — Yarn Berry (node-modules, -st) (push) Waiting to run
E2E Tests / E2E — Yarn Berry (pnp, -s) (push) Waiting to run
E2E Tests / E2E — Yarn Berry (pnp, -st) (push) Waiting to run
E2E Tests / E2E — npm (push) Waiting to run
E2E Tests / E2E — pnpm (push) Waiting to run

Co-authored-by: OzakIOne <OzakIOne@users.noreply.github.com>
Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
This commit is contained in:
ozaki 2024-08-29 18:42:03 +02:00 committed by GitHub
parent 200b38b763
commit 2aef92cb9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 273 additions and 12 deletions

View File

@ -7,7 +7,11 @@
import {fromPartial, type PartialDeep} from '@total-typescript/shoehorn';
import {getBlogPostAuthors, groupBlogPostsByAuthorKey} from '../authors';
import type {AuthorsMap, BlogPost} from '@docusaurus/plugin-content-blog';
import type {
AuthorAttributes,
AuthorsMap,
BlogPost,
} from '@docusaurus/plugin-content-blog';
function post(partial: PartialDeep<BlogPost>): BlogPost {
return fromPartial(partial);
@ -268,11 +272,90 @@ describe('getBlogPostAuthors', () => {
]);
});
it('can read authors Author', () => {
it('read different values from socials', () => {
function testSocials(socials: AuthorAttributes['socials'] | undefined) {
return getBlogPostAuthors({
frontMatter: {
authors: {
name: 'Sébastien Lorber',
title: 'maintainer',
socials,
},
},
authorsMap: undefined,
baseUrl: '/',
});
}
// @ts-expect-error test
expect(() => testSocials(null)).not.toThrow();
// @ts-expect-error test
expect(testSocials(null)).toEqual([
{
name: 'Sébastien Lorber',
title: 'maintainer',
imageURL: undefined,
socials: {},
key: null,
page: null,
},
]);
expect(() => () => testSocials(undefined)).not.toThrow();
// @ts-expect-error test
expect(() => testSocials({twitter: undefined}))
.toThrowErrorMatchingInlineSnapshot(`
"Author socials should be usernames/userIds/handles, or fully qualified HTTP(s) absolute URLs.
Social platform 'twitter' has illegal value 'undefined'"
`);
expect(
// @ts-expect-error test
() => testSocials({twitter: null}),
).toThrowErrorMatchingInlineSnapshot(`
"Author socials should be usernames/userIds/handles, or fully qualified HTTP(s) absolute URLs.
Social platform 'twitter' has illegal value 'null'"
`);
});
it('can read empty socials', () => {
expect(
getBlogPostAuthors({
frontMatter: {
authors: {name: 'Sébastien Lorber', title: 'maintainer'},
authors: {
name: 'Sébastien Lorber',
title: 'maintainer',
socials: {},
},
},
authorsMap: undefined,
baseUrl: '/',
}),
).toEqual([
{
name: 'Sébastien Lorber',
title: 'maintainer',
imageURL: undefined,
socials: {},
key: null,
page: null,
},
]);
});
it('can normalize full socials from Author', () => {
expect(
getBlogPostAuthors({
frontMatter: {
authors: {
name: 'Sébastien Lorber',
title: 'maintainer',
socials: {
github: 'https://github.com/slorber',
linkedin: 'https://www.linkedin.com/in/sebastienlorber/',
stackoverflow: 'https://stackoverflow.com/users/82609',
twitter: 'https://twitter.com/sebastienlorber',
x: 'https://x.com/sebastienlorber',
},
},
},
authorsMap: undefined,
baseUrl: '/',
@ -283,18 +366,81 @@ describe('getBlogPostAuthors', () => {
title: 'maintainer',
imageURL: undefined,
key: null,
socials: {
github: 'https://github.com/slorber',
linkedin: 'https://www.linkedin.com/in/sebastienlorber/',
stackoverflow: 'https://stackoverflow.com/users/82609',
twitter: 'https://twitter.com/sebastienlorber',
x: 'https://x.com/sebastienlorber',
},
page: null,
},
]);
});
it('can read authors Author[]', () => {
it('can normalize handle socials from Author', () => {
expect(
getBlogPostAuthors({
frontMatter: {
authors: {
name: 'Sébastien Lorber',
title: 'maintainer',
socials: {
github: 'slorber',
x: 'sebastienlorber',
linkedin: 'sebastienlorber',
stackoverflow: '82609',
twitter: 'sebastienlorber',
},
},
},
authorsMap: undefined,
baseUrl: '/',
}),
).toEqual([
{
name: 'Sébastien Lorber',
title: 'maintainer',
imageURL: undefined,
key: null,
socials: {
github: 'https://github.com/slorber',
linkedin: 'https://www.linkedin.com/in/sebastienlorber/',
stackoverflow: 'https://stackoverflow.com/users/82609',
twitter: 'https://twitter.com/sebastienlorber',
x: 'https://x.com/sebastienlorber',
},
page: null,
},
]);
});
it('can normalize socials from Author[]', () => {
expect(
getBlogPostAuthors({
frontMatter: {
authors: [
{name: 'Sébastien Lorber', title: 'maintainer'},
{name: 'Yangshun Tay'},
{
name: 'Sébastien Lorber',
title: 'maintainer',
socials: {
github: 'slorber',
x: 'sebastienlorber',
linkedin: 'sebastienlorber',
stackoverflow: '82609',
twitter: 'sebastienlorber',
},
},
{
name: 'Seb',
socials: {
github: 'https://github.com/slorber',
linkedin: 'https://www.linkedin.com/in/sebastienlorber/',
stackoverflow: 'https://stackoverflow.com/users/82609',
twitter: 'https://twitter.com/sebastienlorber',
x: 'https://x.com/sebastienlorber',
},
},
],
},
authorsMap: undefined,
@ -306,9 +452,64 @@ describe('getBlogPostAuthors', () => {
title: 'maintainer',
imageURL: undefined,
key: null,
socials: {
github: 'https://github.com/slorber',
linkedin: 'https://www.linkedin.com/in/sebastienlorber/',
stackoverflow: 'https://stackoverflow.com/users/82609',
twitter: 'https://twitter.com/sebastienlorber',
x: 'https://x.com/sebastienlorber',
},
page: null,
},
{
name: 'Seb',
imageURL: undefined,
key: null,
socials: {
github: 'https://github.com/slorber',
linkedin: 'https://www.linkedin.com/in/sebastienlorber/',
stackoverflow: 'https://stackoverflow.com/users/82609',
twitter: 'https://twitter.com/sebastienlorber',
x: 'https://x.com/sebastienlorber',
},
page: null,
},
]);
});
it('can read authors Author[]', () => {
expect(
getBlogPostAuthors({
frontMatter: {
authors: [
{
name: 'Sébastien Lorber',
title: 'maintainer',
},
{
name: 'Yangshun Tay',
},
],
},
authorsMap: undefined,
baseUrl: '/',
}),
).toEqual([
{
name: 'Sébastien Lorber',
title: 'maintainer',
imageURL: undefined,
key: null,
socials: {},
page: null,
},
{
name: 'Yangshun Tay',
imageURL: undefined,
socials: {},
key: null,
page: null,
},
{name: 'Yangshun Tay', imageURL: undefined, key: null, page: null},
]);
});
@ -323,7 +524,12 @@ describe('getBlogPostAuthors', () => {
title: 'Yangshun title local override',
extra: 42,
},
{name: 'Alexey'},
{
name: 'Alexey',
socials: {
github: 'lex111',
},
},
],
},
authorsMap: {
@ -355,10 +561,19 @@ describe('getBlogPostAuthors', () => {
name: 'Yangshun Tay',
title: 'Yangshun title local override',
extra: 42,
socials: {},
imageURL: undefined,
page: null,
},
{name: 'Alexey', imageURL: undefined, key: null, page: null},
{
name: 'Alexey',
imageURL: undefined,
key: null,
page: null,
socials: {
github: 'https://github.com/lex111',
},
},
]);
});
@ -627,6 +842,7 @@ describe('getBlogPostAuthors', () => {
imageURL: './ozaki.png',
key: null,
page: null,
socials: {},
},
]);
expect(() => withoutBaseUrlTest).not.toThrow();
@ -635,6 +851,7 @@ describe('getBlogPostAuthors', () => {
imageURL: './ozaki.png',
key: null,
page: null,
socials: {},
},
]);
});
@ -654,6 +871,7 @@ describe('getBlogPostAuthors', () => {
imageURL: '/ozaki.png',
key: null,
page: null,
socials: {},
},
]);
});
@ -673,6 +891,7 @@ describe('getBlogPostAuthors', () => {
imageURL: '/img/ozaki.png',
key: null,
page: null,
socials: {},
},
]);
});
@ -692,6 +911,7 @@ describe('getBlogPostAuthors', () => {
imageURL: '/img/ozaki.png',
key: null,
page: null,
socials: {},
},
]);
});
@ -711,6 +931,7 @@ describe('getBlogPostAuthors', () => {
imageURL: '/img/img/ozaki.png',
key: null,
page: null,
socials: {},
},
]);
});

View File

@ -308,7 +308,7 @@ describe('authors socials', () => {
});
it('throw socials that are not strings', () => {
const authorsMap: AuthorsMapInput = {
const socialNumber: AuthorsMapInput = {
ozaki: {
name: 'ozaki',
socials: {
@ -318,11 +318,39 @@ describe('authors socials', () => {
},
};
const socialNull: AuthorsMapInput = {
ozaki: {
name: 'ozaki',
socials: {
// @ts-expect-error: for tests
twitter: null,
},
},
};
const socialNull2: AuthorsMapInput = {
ozaki: {
name: 'ozaki',
// @ts-expect-error: for tests
socials: null,
},
};
expect(() =>
validateAuthorsMap(authorsMap),
validateAuthorsMap(socialNumber),
).toThrowErrorMatchingInlineSnapshot(
`""ozaki.socials.twitter" must be a string"`,
);
expect(() =>
validateAuthorsMap(socialNull),
).toThrowErrorMatchingInlineSnapshot(
`""ozaki.socials.twitter" must be a string"`,
);
expect(() =>
validateAuthorsMap(socialNull2),
).toThrowErrorMatchingInlineSnapshot(
`""ozaki.socials" should be an author object containing properties like name, title, and imageURL."`,
);
});
it('throw socials that are objects', () => {

View File

@ -224,6 +224,7 @@ describe('blog plugin', () => {
imageURL: undefined,
key: null,
page: null,
socials: {},
},
{
email: 'lorber.sebastien@gmail.com',
@ -231,6 +232,7 @@ describe('blog plugin', () => {
name: 'Sébastien Lorber (translated)',
title: 'Docusaurus maintainer (translated)',
imageURL: undefined,
socials: undefined,
page: {permalink: '/blog/authors/slorber-custom-permalink-localized'},
},
],

View File

@ -7,6 +7,7 @@
import _ from 'lodash';
import {normalizeUrl} from '@docusaurus/utils';
import {normalizeSocials} from './authorsSocials';
import type {
Author,
AuthorsMap,
@ -107,7 +108,10 @@ function getFrontMatterAuthors(params: AuthorsParam): Author[] {
// becoming a name and may end up unnoticed
return {key: authorInput};
}
return authorInput;
return {
...authorInput,
socials: normalizeSocials(authorInput.socials ?? {}),
};
}
return Array.isArray(frontMatter.authors)

View File

@ -41,6 +41,12 @@ type SocialEntry = [string, string];
function normalizeSocialEntry([platform, value]: SocialEntry): SocialEntry {
const normalizer = PredefinedPlatformNormalizers[platform.toLowerCase()];
if (typeof value !== 'string') {
throw new Error(
`Author socials should be usernames/userIds/handles, or fully qualified HTTP(s) absolute URLs.
Social platform '${platform}' has illegal value '${value}'`,
);
}
const isAbsoluteUrl =
value.startsWith('http://') || value.startsWith('https://');
if (isAbsoluteUrl) {