mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-30 09:27:04 +02:00
feat(blog): add onUntruncatedBlogPosts
blog options (#10375)
Co-authored-by: OzakIOne <OzakIOne@users.noreply.github.com> Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com> Co-authored-by: sebastien <lorber.sebastien@gmail.com>
This commit is contained in:
parent
f43be857d7
commit
a096bbc0b9
10 changed files with 189 additions and 0 deletions
|
@ -5,12 +5,14 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {jest} from '@jest/globals';
|
||||
import {fromPartial} from '@total-typescript/shoehorn';
|
||||
import {
|
||||
truncate,
|
||||
parseBlogFileName,
|
||||
paginateBlogPosts,
|
||||
applyProcessBlogPosts,
|
||||
reportUntruncatedBlogPosts,
|
||||
} from '../blogUtils';
|
||||
import type {BlogPost} from '@docusaurus/plugin-content-blog';
|
||||
|
||||
|
@ -32,6 +34,109 @@ describe('truncate', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('reportUntruncatedBlogPosts', () => {
|
||||
function testPost({
|
||||
source,
|
||||
hasTruncateMarker,
|
||||
}: {
|
||||
source: string;
|
||||
hasTruncateMarker: boolean;
|
||||
}): BlogPost {
|
||||
return fromPartial({
|
||||
metadata: {
|
||||
source,
|
||||
hasTruncateMarker,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
it('throw for untruncated blog posts', () => {
|
||||
const blogPosts = [
|
||||
testPost({source: '@site/blog/post1.md', hasTruncateMarker: false}),
|
||||
testPost({source: '@site/blog/post2.md', hasTruncateMarker: true}),
|
||||
testPost({
|
||||
source: '@site/blog/subDir/post3.md',
|
||||
hasTruncateMarker: false,
|
||||
}),
|
||||
];
|
||||
expect(() =>
|
||||
reportUntruncatedBlogPosts({blogPosts, onUntruncatedBlogPosts: 'throw'}),
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Docusaurus found blog posts without truncation markers:
|
||||
- "blog/post1.md"
|
||||
- "blog/subDir/post3.md"
|
||||
|
||||
We recommend using truncation markers (\`<!-- truncate -->\` or \`{/* truncate */}\`) in blog posts to create shorter previews on blog paginated lists.
|
||||
Tip: turn this security off with the \`onUntruncatedBlogPosts: 'ignore'\` blog plugin option."
|
||||
`);
|
||||
});
|
||||
|
||||
it('warn for untruncated blog posts', () => {
|
||||
const consoleMock = jest.spyOn(console, 'warn');
|
||||
|
||||
const blogPosts = [
|
||||
testPost({source: '@site/blog/post1.md', hasTruncateMarker: false}),
|
||||
testPost({source: '@site/blog/post2.md', hasTruncateMarker: true}),
|
||||
testPost({
|
||||
source: '@site/blog/subDir/post3.md',
|
||||
hasTruncateMarker: false,
|
||||
}),
|
||||
];
|
||||
expect(() =>
|
||||
reportUntruncatedBlogPosts({blogPosts, onUntruncatedBlogPosts: 'warn'}),
|
||||
).not.toThrow();
|
||||
|
||||
expect(consoleMock.mock.calls).toMatchInlineSnapshot(`
|
||||
[
|
||||
[
|
||||
"[WARNING] Docusaurus found blog posts without truncation markers:
|
||||
- "blog/post1.md"
|
||||
- "blog/subDir/post3.md"
|
||||
|
||||
We recommend using truncation markers (\`<!-- truncate -->\` or \`{/* truncate */}\`) in blog posts to create shorter previews on blog paginated lists.
|
||||
Tip: turn this security off with the \`onUntruncatedBlogPosts: 'ignore'\` blog plugin option.",
|
||||
],
|
||||
]
|
||||
`);
|
||||
consoleMock.mockRestore();
|
||||
});
|
||||
|
||||
it('ignore untruncated blog posts', () => {
|
||||
const logMock = jest.spyOn(console, 'log');
|
||||
const warnMock = jest.spyOn(console, 'warn');
|
||||
const errorMock = jest.spyOn(console, 'error');
|
||||
|
||||
const blogPosts = [
|
||||
testPost({source: '@site/blog/post1.md', hasTruncateMarker: false}),
|
||||
testPost({source: '@site/blog/post2.md', hasTruncateMarker: true}),
|
||||
testPost({
|
||||
source: '@site/blog/subDir/post3.md',
|
||||
hasTruncateMarker: false,
|
||||
}),
|
||||
];
|
||||
expect(() =>
|
||||
reportUntruncatedBlogPosts({blogPosts, onUntruncatedBlogPosts: 'ignore'}),
|
||||
).not.toThrow();
|
||||
|
||||
expect(logMock).not.toHaveBeenCalled();
|
||||
expect(warnMock).not.toHaveBeenCalled();
|
||||
expect(errorMock).not.toHaveBeenCalled();
|
||||
logMock.mockRestore();
|
||||
warnMock.mockRestore();
|
||||
errorMock.mockRestore();
|
||||
});
|
||||
|
||||
it('does not throw for truncated posts', () => {
|
||||
const blogPosts = [
|
||||
testPost({source: '@site/blog/post1.md', hasTruncateMarker: true}),
|
||||
testPost({source: '@site/blog/post2.md', hasTruncateMarker: true}),
|
||||
];
|
||||
expect(() =>
|
||||
reportUntruncatedBlogPosts({blogPosts, onUntruncatedBlogPosts: 'throw'}),
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('paginateBlogPosts', () => {
|
||||
const blogPosts = [
|
||||
{id: 'post1', metadata: {}, content: 'Foo 1'},
|
||||
|
|
|
@ -374,4 +374,46 @@ describe('validateOptions', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onUntruncatedBlogPosts', () => {
|
||||
it('accepts onUntruncatedBlogPosts - undefined', () => {
|
||||
expect(
|
||||
testValidate({onUntruncatedBlogPosts: undefined})
|
||||
.onUntruncatedBlogPosts,
|
||||
).toBe('warn');
|
||||
});
|
||||
|
||||
it('accepts onUntruncatedBlogPosts - "throw"', () => {
|
||||
expect(
|
||||
testValidate({onUntruncatedBlogPosts: 'throw'}).onUntruncatedBlogPosts,
|
||||
).toBe('throw');
|
||||
});
|
||||
|
||||
it('rejects onUntruncatedBlogPosts - "trace"', () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error: test
|
||||
testValidate({onUntruncatedBlogPosts: 'trace'}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`""onUntruncatedBlogPosts" must be one of [ignore, log, warn, throw]"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects onUntruncatedBlogPosts - null', () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error: test
|
||||
testValidate({onUntruncatedBlogPosts: 42}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`""onUntruncatedBlogPosts" must be one of [ignore, log, warn, throw]"`,
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects onUntruncatedBlogPosts - 42', () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error: test
|
||||
testValidate({onUntruncatedBlogPosts: 42}),
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`""onUntruncatedBlogPosts" must be one of [ignore, log, warn, throw]"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
isDraft,
|
||||
readLastUpdateData,
|
||||
normalizeTags,
|
||||
aliasedSitePathToRelativePath,
|
||||
} from '@docusaurus/utils';
|
||||
import {getTagsFile} from '@docusaurus/utils-validation';
|
||||
import {validateBlogPostFrontMatter} from './frontMatter';
|
||||
|
@ -47,6 +48,28 @@ export function truncate(fileString: string, truncateMarker: RegExp): string {
|
|||
return fileString.split(truncateMarker, 1).shift()!;
|
||||
}
|
||||
|
||||
export function reportUntruncatedBlogPosts({
|
||||
blogPosts,
|
||||
onUntruncatedBlogPosts,
|
||||
}: {
|
||||
blogPosts: BlogPost[];
|
||||
onUntruncatedBlogPosts: PluginOptions['onUntruncatedBlogPosts'];
|
||||
}): void {
|
||||
const untruncatedBlogPosts = blogPosts.filter(
|
||||
(p) => !p.metadata.hasTruncateMarker,
|
||||
);
|
||||
if (onUntruncatedBlogPosts !== 'ignore' && untruncatedBlogPosts.length > 0) {
|
||||
const message = logger.interpolate`Docusaurus found blog posts without truncation markers:
|
||||
- ${untruncatedBlogPosts
|
||||
.map((p) => logger.path(aliasedSitePathToRelativePath(p.metadata.source)))
|
||||
.join('\n- ')}
|
||||
|
||||
We recommend using truncation markers (code=${`<!-- truncate -->`} or code=${`{/* truncate */}`}) in blog posts to create shorter previews on blog paginated lists.
|
||||
Tip: turn this security off with the code=${`onUntruncatedBlogPosts: 'ignore'`} blog plugin option.`;
|
||||
logger.report(onUntruncatedBlogPosts)(message);
|
||||
}
|
||||
}
|
||||
|
||||
export function paginateBlogPosts({
|
||||
blogPosts,
|
||||
basePageUrl,
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
shouldBeListed,
|
||||
applyProcessBlogPosts,
|
||||
generateBlogPosts,
|
||||
reportUntruncatedBlogPosts,
|
||||
} from './blogUtils';
|
||||
import footnoteIDFixer from './remark/footnoteIDFixer';
|
||||
import {translateContent, getTranslationFiles} from './translations';
|
||||
|
@ -189,6 +190,10 @@ export default async function pluginContentBlog(
|
|||
blogPosts,
|
||||
processBlogPosts: options.processBlogPosts,
|
||||
});
|
||||
reportUntruncatedBlogPosts({
|
||||
blogPosts,
|
||||
onUntruncatedBlogPosts: options.onUntruncatedBlogPosts,
|
||||
});
|
||||
const listedBlogPosts = blogPosts.filter(shouldBeListed);
|
||||
|
||||
if (!blogPosts.length) {
|
||||
|
|
|
@ -72,6 +72,7 @@ export const DEFAULT_OPTIONS: PluginOptions = {
|
|||
tags: undefined,
|
||||
authorsBasePath: 'authors',
|
||||
onInlineAuthors: 'warn',
|
||||
onUntruncatedBlogPosts: 'warn',
|
||||
};
|
||||
|
||||
export const XSLTBuiltInPaths = {
|
||||
|
@ -240,6 +241,9 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
|
|||
onInlineAuthors: Joi.string()
|
||||
.equal('ignore', 'log', 'warn', 'throw')
|
||||
.default(DEFAULT_OPTIONS.onInlineAuthors),
|
||||
onUntruncatedBlogPosts: Joi.string()
|
||||
.equal('ignore', 'log', 'warn', 'throw')
|
||||
.default(DEFAULT_OPTIONS.onUntruncatedBlogPosts),
|
||||
}).default(DEFAULT_OPTIONS);
|
||||
|
||||
export function validateOptions({
|
||||
|
|
|
@ -521,6 +521,8 @@ declare module '@docusaurus/plugin-content-blog' {
|
|||
authorsBasePath: string;
|
||||
/** The behavior of Docusaurus when it finds inline authors. */
|
||||
onInlineAuthors: 'ignore' | 'log' | 'warn' | 'throw';
|
||||
/** The behavior of Docusaurus when it finds untruncated blog posts. */
|
||||
onUntruncatedBlogPosts: 'ignore' | 'log' | 'warn' | 'throw';
|
||||
};
|
||||
|
||||
export type UserFeedXSLTOptions =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue