From 0065a3f73af06a548799c8554bd5c1dab20ddee2 Mon Sep 17 00:00:00 2001 From: johnnyreilly Date: Sun, 28 Apr 2024 07:47:13 +0100 Subject: [PATCH 1/8] feat: add createSitemapItems hook --- .../src/__tests__/createSitemap.test.ts | 31 ++++++++++++++ .../src/__tests__/options.test.ts | 40 +++++++++++++++++++ .../src/createSitemap.ts | 37 +++++++++-------- .../docusaurus-plugin-sitemap/src/options.ts | 22 +++++++++- .../docusaurus-plugin-sitemap/src/types.ts | 11 +++++ website/docs/api/plugins/plugin-sitemap.mdx | 22 ++++++++++ website/docusaurus.config.ts | 10 +++++ 7 files changed, 155 insertions(+), 18 deletions(-) diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts index c080c8b028d4..046fe1734e49 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts @@ -84,6 +84,37 @@ describe('createSitemap', () => { expect(sitemap).not.toContain('/tags'); }); + it('excludes items that createSitemapItems configures to be ignored', async () => { + const sitemap = await createSitemap({ + siteConfig, + routes: routes([ + '/', + '/search/', + '/tags/', + '/search/foo', + '/tags/foo/bar', + ]), + head: {}, + options: { + ...options, + createSitemapItems: async (params) => { + const {defaultCreateSitemapItems, ...rest} = params; + const sitemapItems = await defaultCreateSitemapItems(rest); + const sitemapsWithoutPageAndTags = sitemapItems.filter( + (sitemapItem) => + !sitemapItem.url.includes('/tags/') && + !sitemapItem.url.endsWith('/search/'), + ); + return sitemapsWithoutPageAndTags; + }, + }, + }); + + expect(sitemap).not.toContain('/search/'); + expect(sitemap).toContain('/search/foo'); + expect(sitemap).not.toContain('/tags'); + }); + it('keep trailing slash unchanged', async () => { const sitemap = await createSitemap({ siteConfig, diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts index 7b3cac21b367..dcea70b6a7e6 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/options.test.ts @@ -249,4 +249,44 @@ describe('validateOptions', () => { ); }); }); + + describe('createSitemapItems', () => { + it('accept createSitemapItems undefined', () => { + const userOptions: Options = { + createSitemapItems: undefined, + }; + expect(testValidate(userOptions)).toEqual(defaultOptions); + }); + + it('accept createSitemapItems valid', () => { + const userOptions: Options = { + createSitemapItems: async (params) => { + const {defaultCreateSitemapItems, ...rest} = params; + const sitemapItems = await defaultCreateSitemapItems(rest); + const sitemapsWithoutPageAndTags = sitemapItems.filter( + (sitemapItem) => + !sitemapItem.url.includes('/tags/') && + !sitemapItem.url.includes('/page/'), + ); + return sitemapsWithoutPageAndTags; + }, + }; + expect(testValidate(userOptions)).toEqual({ + ...defaultOptions, + ...userOptions, + }); + }); + + it('rejects createSitemapItems bad input type', () => { + const userOptions: Options = { + // @ts-expect-error: test + createSitemapItems: 'not a function', + }; + expect(() => + testValidate(userOptions), + ).toThrowErrorMatchingInlineSnapshot( + `""createSitemapItems" must be of type function"`, + ); + }); + }); }); diff --git a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts index 1f7790db7924..87a897db6cdb 100644 --- a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts +++ b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts @@ -9,17 +9,9 @@ import type {ReactElement} from 'react'; import {createMatcher, flattenRoutes} from '@docusaurus/utils'; import {sitemapItemsToXmlString} from './xml'; import {createSitemapItem} from './createSitemapItem'; -import type {SitemapItem} from './types'; -import type {DocusaurusConfig, RouteConfig} from '@docusaurus/types'; +import type {SitemapItem, DefaultCreateSitemapParams} from './types'; +import type {RouteConfig} from '@docusaurus/types'; import type {HelmetServerState} from 'react-helmet-async'; -import type {PluginOptions} from './options'; - -type CreateSitemapParams = { - siteConfig: DocusaurusConfig; - routes: RouteConfig[]; - head: {[location: string]: HelmetServerState}; - options: PluginOptions; -}; // Maybe we want to add a routeConfig.metadata.noIndex instead? // But using Helmet is more reliable for third-party plugins... @@ -61,7 +53,7 @@ function isNoIndexMetaRoute({ // - parent routes, used for layouts // - routes matching options.ignorePatterns // - routes with no index metadata -function getSitemapRoutes({routes, head, options}: CreateSitemapParams) { +function getSitemapRoutes({routes, head, options}: DefaultCreateSitemapParams) { const {ignorePatterns} = options; const ignoreMatcher = createMatcher(ignorePatterns); @@ -75,8 +67,8 @@ function getSitemapRoutes({routes, head, options}: CreateSitemapParams) { return flattenRoutes(routes).filter((route) => !isRouteExcluded(route)); } -async function createSitemapItems( - params: CreateSitemapParams, +async function defaultCreateSitemapItems( + params: DefaultCreateSitemapParams, ): Promise { const sitemapRoutes = getSitemapRoutes(params); if (sitemapRoutes.length === 0) { @@ -94,13 +86,24 @@ async function createSitemapItems( } export default async function createSitemap( - params: CreateSitemapParams, + params: DefaultCreateSitemapParams, ): Promise { - const items = await createSitemapItems(params); - if (items.length === 0) { + const {head, options, routes, siteConfig} = params; + const createSitemapItems = + params.options.createSitemapItems ?? defaultCreateSitemapItems; + + const sitemapItems = await createSitemapItems({ + head, + options, + routes, + siteConfig, + defaultCreateSitemapItems, + }); + if (sitemapItems.length === 0) { return null; } - const xmlString = await sitemapItemsToXmlString(items, { + + const xmlString = await sitemapItemsToXmlString(sitemapItems, { lastmod: params.options.lastmod, }); return xmlString; diff --git a/packages/docusaurus-plugin-sitemap/src/options.ts b/packages/docusaurus-plugin-sitemap/src/options.ts index e6d4c94e9a40..c24a1c02ffa4 100644 --- a/packages/docusaurus-plugin-sitemap/src/options.ts +++ b/packages/docusaurus-plugin-sitemap/src/options.ts @@ -8,7 +8,12 @@ import {Joi} from '@docusaurus/utils-validation'; import {ChangeFreqList, LastModOptionList} from './types'; import type {OptionValidationContext} from '@docusaurus/types'; -import type {ChangeFreq, LastModOption} from './types'; +import type { + ChangeFreq, + DefaultCreateSitemapParams, + LastModOption, + SitemapItem, +} from './types'; export type PluginOptions = { /** @@ -44,6 +49,19 @@ export type PluginOptions = { * @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */ priority: number | null; + + /** Allow control over the construction of SitemapItems */ + createSitemapItems?: CreateSitemapItemsFn; +}; + +type CreateSitemapItemsFn = ( + params: CreateSitemapItemsParams, +) => Promise; + +type CreateSitemapItemsParams = DefaultCreateSitemapParams & { + defaultCreateSitemapItems: ( + params: DefaultCreateSitemapParams, + ) => Promise; }; export type Options = Partial; @@ -90,6 +108,8 @@ const PluginOptionSchema = Joi.object({ .valid(null, ...LastModOptionList) .default(DEFAULT_OPTIONS.lastmod), + createSitemapItems: Joi.function(), + ignorePatterns: Joi.array() .items(Joi.string()) .default(DEFAULT_OPTIONS.ignorePatterns), diff --git a/packages/docusaurus-plugin-sitemap/src/types.ts b/packages/docusaurus-plugin-sitemap/src/types.ts index f959ca09018b..e37edb62cbf7 100644 --- a/packages/docusaurus-plugin-sitemap/src/types.ts +++ b/packages/docusaurus-plugin-sitemap/src/types.ts @@ -5,6 +5,10 @@ * LICENSE file in the root directory of this source tree. */ +import type {DocusaurusConfig, RouteConfig} from '@docusaurus/types'; +import type {HelmetServerState} from 'react-helmet-async'; +import type {PluginOptions} from './options'; + export const LastModOptionList = ['date', 'datetime'] as const; export type LastModOption = (typeof LastModOptionList)[number]; @@ -65,3 +69,10 @@ export type SitemapItem = { */ priority?: number | null; }; + +export type DefaultCreateSitemapParams = { + siteConfig: DocusaurusConfig; + routes: RouteConfig[]; + head: {[location: string]: HelmetServerState}; + options: PluginOptions; +}; diff --git a/website/docs/api/plugins/plugin-sitemap.mdx b/website/docs/api/plugins/plugin-sitemap.mdx index 41f240839454..0f54d412248e 100644 --- a/website/docs/api/plugins/plugin-sitemap.mdx +++ b/website/docs/api/plugins/plugin-sitemap.mdx @@ -44,11 +44,25 @@ Accepted fields: | `priority` | `number \| null` | `0.5` | See [sitemap docs](https://www.sitemaps.org/protocol.html#xmlTagDefinitions) | | `ignorePatterns` | `string[]` | `[]` | A list of glob patterns; matching route paths will be filtered from the sitemap. Note that you may need to include the base URL in here. | | `filename` | `string` | `sitemap.xml` | The path to the created sitemap file, relative to the output directory. Useful if you have two plugin instances outputting two files. | +| `createSitemapItems` | [CreateSitemapItemsFn](#CreateSitemapItemsFn) \| undefined | `undefined` | An optional function which can be used to transform and / or filter the items in the sitemap. | ```mdx-code-block ``` +### Types {#types} + +#### `CreateSitemapItemsFn` {#CreateSitemapItemsFn} + +```ts +type CreateSitemapItemsFn = (params: { + siteConfig: DocusaurusConfig; + routes: RouteConfig[]; + head: {[location: string]: HelmetServerState}; + options: PluginOptions; +}) => Promise; +``` + :::info This plugin also respects some site config: @@ -86,6 +100,14 @@ const config = { priority: 0.5, ignorePatterns: ['/tags/**'], filename: 'sitemap.xml', + createSitemapItems: async (params) => { + const {defaultCreateSitemapItems, ...rest} = params; + const sitemapItems = await defaultCreateSitemapItems(rest); + const sitemapsWithoutPage = sitemapItems.filter( + (sitemapItem) => !sitemapItem.url.includes('/page/'), + ); + return sitemapsWithoutPage; + }, }; ``` diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index 996dcb42b0df..cc6877b00606 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -490,6 +490,16 @@ export default async function createConfigAsync() { lastmod: 'date', priority: null, changefreq: null, + createSitemapItems: async (params) => { + const {defaultCreateSitemapItems, ...rest} = params; + const sitemapItems = await defaultCreateSitemapItems(rest); + const sitemapsWithoutPageAndTags = sitemapItems.filter( + (sitemapItem) => + !sitemapItem.url.includes('/tags/') && + !sitemapItem.url.includes('/page/'), + ); + return sitemapsWithoutPageAndTags; + }, }, } satisfies Preset.Options, ], From fb069b129d513486eb378d6a89e40a6d67d86e05 Mon Sep 17 00:00:00 2001 From: johnnyreilly Date: Tue, 30 Apr 2024 07:20:17 +0100 Subject: [PATCH 2/8] fix: remove head and options from params --- .../src/createSitemap.ts | 32 +++++++++++++------ .../docusaurus-plugin-sitemap/src/options.ts | 7 ++-- website/docs/api/plugins/plugin-sitemap.mdx | 2 -- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts index 87a897db6cdb..7c35ab22372c 100644 --- a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts +++ b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts @@ -10,7 +10,7 @@ import {createMatcher, flattenRoutes} from '@docusaurus/utils'; import {sitemapItemsToXmlString} from './xml'; import {createSitemapItem} from './createSitemapItem'; import type {SitemapItem, DefaultCreateSitemapParams} from './types'; -import type {RouteConfig} from '@docusaurus/types'; +import type {DocusaurusConfig, RouteConfig} from '@docusaurus/types'; import type {HelmetServerState} from 'react-helmet-async'; // Maybe we want to add a routeConfig.metadata.noIndex instead? @@ -89,16 +89,28 @@ export default async function createSitemap( params: DefaultCreateSitemapParams, ): Promise { const {head, options, routes, siteConfig} = params; - const createSitemapItems = - params.options.createSitemapItems ?? defaultCreateSitemapItems; - const sitemapItems = await createSitemapItems({ - head, - options, - routes, - siteConfig, - defaultCreateSitemapItems, - }); + const sitemapItems = params.options.createSitemapItems + ? await params.options.createSitemapItems({ + routes, + siteConfig, + defaultCreateSitemapItems: (userParams: { + routes: RouteConfig[]; + siteConfig: DocusaurusConfig; + }) => + defaultCreateSitemapItems({ + head, + options, + ...userParams, + }), + }) + : await defaultCreateSitemapItems({ + head, + options, + routes, + siteConfig, + }); + if (sitemapItems.length === 0) { return null; } diff --git a/packages/docusaurus-plugin-sitemap/src/options.ts b/packages/docusaurus-plugin-sitemap/src/options.ts index c24a1c02ffa4..3211b0bc86bd 100644 --- a/packages/docusaurus-plugin-sitemap/src/options.ts +++ b/packages/docusaurus-plugin-sitemap/src/options.ts @@ -58,9 +58,12 @@ type CreateSitemapItemsFn = ( params: CreateSitemapItemsParams, ) => Promise; -type CreateSitemapItemsParams = DefaultCreateSitemapParams & { +type CreateSitemapItemsParams = Omit< + DefaultCreateSitemapParams, + 'head' | 'options' +> & { defaultCreateSitemapItems: ( - params: DefaultCreateSitemapParams, + params: Omit, ) => Promise; }; diff --git a/website/docs/api/plugins/plugin-sitemap.mdx b/website/docs/api/plugins/plugin-sitemap.mdx index 0f54d412248e..16d5539fc6b8 100644 --- a/website/docs/api/plugins/plugin-sitemap.mdx +++ b/website/docs/api/plugins/plugin-sitemap.mdx @@ -58,8 +58,6 @@ Accepted fields: type CreateSitemapItemsFn = (params: { siteConfig: DocusaurusConfig; routes: RouteConfig[]; - head: {[location: string]: HelmetServerState}; - options: PluginOptions; }) => Promise; ``` From 1830cf293bd6dac2a2166eb78b840df884ffc80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Tue, 30 Apr 2024 18:34:01 +0200 Subject: [PATCH 3/8] Update website/docs/api/plugins/plugin-sitemap.mdx --- website/docs/api/plugins/plugin-sitemap.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/api/plugins/plugin-sitemap.mdx b/website/docs/api/plugins/plugin-sitemap.mdx index 16d5539fc6b8..ed3c5ca65d20 100644 --- a/website/docs/api/plugins/plugin-sitemap.mdx +++ b/website/docs/api/plugins/plugin-sitemap.mdx @@ -58,6 +58,7 @@ Accepted fields: type CreateSitemapItemsFn = (params: { siteConfig: DocusaurusConfig; routes: RouteConfig[]; + defaultCreateSitemapItems: CreateSitemapItemsFn; }) => Promise; ``` From d9816f99b5f6c26499b1f884533034473129f404 Mon Sep 17 00:00:00 2001 From: sebastien Date: Tue, 30 Apr 2024 18:35:07 +0200 Subject: [PATCH 4/8] simplify example --- website/docs/api/plugins/plugin-sitemap.mdx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/website/docs/api/plugins/plugin-sitemap.mdx b/website/docs/api/plugins/plugin-sitemap.mdx index ed3c5ca65d20..75ca74ef8b70 100644 --- a/website/docs/api/plugins/plugin-sitemap.mdx +++ b/website/docs/api/plugins/plugin-sitemap.mdx @@ -101,11 +101,8 @@ const config = { filename: 'sitemap.xml', createSitemapItems: async (params) => { const {defaultCreateSitemapItems, ...rest} = params; - const sitemapItems = await defaultCreateSitemapItems(rest); - const sitemapsWithoutPage = sitemapItems.filter( - (sitemapItem) => !sitemapItem.url.includes('/page/'), - ); - return sitemapsWithoutPage; + const items = await defaultCreateSitemapItems(rest); + return items.filter((item) => !item.url.includes('/page/')); }, }; ``` From c624788e4c4aa2e109cfcb66989af5dba2eb0089 Mon Sep 17 00:00:00 2001 From: sebastien Date: Tue, 30 Apr 2024 19:05:35 +0200 Subject: [PATCH 5/8] refactor a bit types and logic --- .../src/createSitemap.ts | 103 ++++++------------ .../docusaurus-plugin-sitemap/src/head.ts | 47 ++++++++ .../docusaurus-plugin-sitemap/src/options.ts | 20 ++-- .../docusaurus-plugin-sitemap/src/types.ts | 10 +- 4 files changed, 94 insertions(+), 86 deletions(-) create mode 100644 packages/docusaurus-plugin-sitemap/src/head.ts diff --git a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts index 7c35ab22372c..f3f3aace18bc 100644 --- a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts +++ b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts @@ -5,55 +5,20 @@ * LICENSE file in the root directory of this source tree. */ -import type {ReactElement} from 'react'; import {createMatcher, flattenRoutes} from '@docusaurus/utils'; import {sitemapItemsToXmlString} from './xml'; import {createSitemapItem} from './createSitemapItem'; -import type {SitemapItem, DefaultCreateSitemapParams} from './types'; -import type {DocusaurusConfig, RouteConfig} from '@docusaurus/types'; +import {isNoIndexMetaRoute} from './head'; +import type {CreateSitemapItemsFn, CreateSitemapItemsParams} from './types'; +import type {RouteConfig} from '@docusaurus/types'; +import type {PluginOptions} from './options'; import type {HelmetServerState} from 'react-helmet-async'; -// Maybe we want to add a routeConfig.metadata.noIndex instead? -// But using Helmet is more reliable for third-party plugins... -function isNoIndexMetaRoute({ - head, - route, -}: { - head: {[location: string]: HelmetServerState}; - route: string; -}) { - const isNoIndexMetaTag = ({ - name, - content, - }: { - name?: string; - content?: string; - }): boolean => { - if (!name || !content) { - return false; - } - return ( - // meta name is not case-sensitive - name.toLowerCase() === 'robots' && - // Robots directives are not case-sensitive - content.toLowerCase().includes('noindex') - ); - }; - - // https://github.com/staylor/react-helmet-async/pull/167 - const meta = head[route]?.meta.toComponent() as unknown as - | ReactElement<{name?: string; content?: string}>[] - | undefined; - return meta?.some((tag) => - isNoIndexMetaTag({name: tag.props.name, content: tag.props.content}), - ); -} - // Not all routes should appear in the sitemap, and we should filter: // - parent routes, used for layouts // - routes matching options.ignorePatterns // - routes with no index metadata -function getSitemapRoutes({routes, head, options}: DefaultCreateSitemapParams) { +function getSitemapRoutes({routes, head, options}: CreateSitemapParams) { const {ignorePatterns} = options; const ignoreMatcher = createMatcher(ignorePatterns); @@ -67,46 +32,48 @@ function getSitemapRoutes({routes, head, options}: DefaultCreateSitemapParams) { return flattenRoutes(routes).filter((route) => !isRouteExcluded(route)); } -async function defaultCreateSitemapItems( - params: DefaultCreateSitemapParams, -): Promise { - const sitemapRoutes = getSitemapRoutes(params); - if (sitemapRoutes.length === 0) { - return []; - } - return Promise.all( - sitemapRoutes.map((route) => - createSitemapItem({ - route, - siteConfig: params.siteConfig, - options: params.options, - }), - ), - ); +// Our default implementation receives some additional parameters on purpose +// Params such as "head" are "messy" and not directly exposed to the user +function createDefaultCreateSitemapItems( + internalParams: Pick, +): CreateSitemapItemsFn { + return async (params) => { + const sitemapRoutes = getSitemapRoutes({...params, ...internalParams}); + if (sitemapRoutes.length === 0) { + return []; + } + return Promise.all( + sitemapRoutes.map((route) => + createSitemapItem({ + route, + siteConfig: params.siteConfig, + options: internalParams.options, + }), + ), + ); + }; } +type CreateSitemapParams = CreateSitemapItemsParams & { + head: {[location: string]: HelmetServerState}; + options: PluginOptions; +}; + export default async function createSitemap( - params: DefaultCreateSitemapParams, + params: CreateSitemapParams, ): Promise { const {head, options, routes, siteConfig} = params; + const defaultCreateSitemapItems: CreateSitemapItemsFn = + createDefaultCreateSitemapItems({head, options}); + const sitemapItems = params.options.createSitemapItems ? await params.options.createSitemapItems({ routes, siteConfig, - defaultCreateSitemapItems: (userParams: { - routes: RouteConfig[]; - siteConfig: DocusaurusConfig; - }) => - defaultCreateSitemapItems({ - head, - options, - ...userParams, - }), + defaultCreateSitemapItems, }) : await defaultCreateSitemapItems({ - head, - options, routes, siteConfig, }); diff --git a/packages/docusaurus-plugin-sitemap/src/head.ts b/packages/docusaurus-plugin-sitemap/src/head.ts new file mode 100644 index 000000000000..ed16fdf85234 --- /dev/null +++ b/packages/docusaurus-plugin-sitemap/src/head.ts @@ -0,0 +1,47 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import type {ReactElement} from 'react'; +import type {HelmetServerState} from 'react-helmet-async'; + +// Maybe we want to add a routeConfig.metadata.noIndex instead? +// But using Helmet is more reliable for third-party plugins... +export function isNoIndexMetaRoute({ + head, + route, +}: { + head: {[location: string]: HelmetServerState}; + route: string; +}): boolean { + const isNoIndexMetaTag = ({ + name, + content, + }: { + name?: string; + content?: string; + }): boolean => { + if (!name || !content) { + return false; + } + return ( + // meta name is not case-sensitive + name.toLowerCase() === 'robots' && + // Robots directives are not case-sensitive + content.toLowerCase().includes('noindex') + ); + }; + + // https://github.com/staylor/react-helmet-async/pull/167 + const meta = head[route]?.meta.toComponent() as unknown as + | ReactElement<{name?: string; content?: string}>[] + | undefined; + return ( + meta?.some((tag) => + isNoIndexMetaTag({name: tag.props.name, content: tag.props.content}), + ) ?? false + ); +} diff --git a/packages/docusaurus-plugin-sitemap/src/options.ts b/packages/docusaurus-plugin-sitemap/src/options.ts index 3211b0bc86bd..a05a1c74b8f3 100644 --- a/packages/docusaurus-plugin-sitemap/src/options.ts +++ b/packages/docusaurus-plugin-sitemap/src/options.ts @@ -10,9 +10,10 @@ import {ChangeFreqList, LastModOptionList} from './types'; import type {OptionValidationContext} from '@docusaurus/types'; import type { ChangeFreq, - DefaultCreateSitemapParams, LastModOption, SitemapItem, + CreateSitemapItemsFn, + CreateSitemapItemsParams, } from './types'; export type PluginOptions = { @@ -51,22 +52,15 @@ export type PluginOptions = { priority: number | null; /** Allow control over the construction of SitemapItems */ - createSitemapItems?: CreateSitemapItemsFn; + createSitemapItems?: CreateSitemapItemsOption; }; -type CreateSitemapItemsFn = ( - params: CreateSitemapItemsParams, +type CreateSitemapItemsOption = ( + params: CreateSitemapItemsParams & { + defaultCreateSitemapItems: CreateSitemapItemsFn; + }, ) => Promise; -type CreateSitemapItemsParams = Omit< - DefaultCreateSitemapParams, - 'head' | 'options' -> & { - defaultCreateSitemapItems: ( - params: Omit, - ) => Promise; -}; - export type Options = Partial; export const DEFAULT_OPTIONS: PluginOptions = { diff --git a/packages/docusaurus-plugin-sitemap/src/types.ts b/packages/docusaurus-plugin-sitemap/src/types.ts index e37edb62cbf7..ca4536b173b7 100644 --- a/packages/docusaurus-plugin-sitemap/src/types.ts +++ b/packages/docusaurus-plugin-sitemap/src/types.ts @@ -6,8 +6,6 @@ */ import type {DocusaurusConfig, RouteConfig} from '@docusaurus/types'; -import type {HelmetServerState} from 'react-helmet-async'; -import type {PluginOptions} from './options'; export const LastModOptionList = ['date', 'datetime'] as const; @@ -70,9 +68,11 @@ export type SitemapItem = { priority?: number | null; }; -export type DefaultCreateSitemapParams = { +export type CreateSitemapItemsParams = { siteConfig: DocusaurusConfig; routes: RouteConfig[]; - head: {[location: string]: HelmetServerState}; - options: PluginOptions; }; + +export type CreateSitemapItemsFn = ( + params: CreateSitemapItemsParams, +) => Promise; From 60eef877d8d6c7030a898d7b99c84088d719c77b Mon Sep 17 00:00:00 2001 From: sebastien Date: Tue, 30 Apr 2024 19:06:22 +0200 Subject: [PATCH 6/8] add extra unit test covering createSitemapItems returning [] --- .../src/__tests__/createSitemap.test.ts | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts index 046fe1734e49..f1f152ecb137 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React from 'react'; +import {createElement} from 'react'; import {fromPartial} from '@total-typescript/shoehorn'; import createSitemap from '../createSitemap'; import type {PluginOptions} from '../options'; @@ -115,6 +115,22 @@ describe('createSitemap', () => { expect(sitemap).not.toContain('/tags'); }); + it('returns null when createSitemapItems returns no items', async () => { + const sitemap = await createSitemap({ + siteConfig, + routes: routes(['/', '/docs/myDoc/', '/blog/post']), + head: {}, + options: { + ...options, + createSitemapItems: async () => { + return []; + }, + }, + }); + + expect(sitemap).toBeNull(); + }); + it('keep trailing slash unchanged', async () => { const sitemap = await createSitemap({ siteConfig, @@ -171,7 +187,7 @@ describe('createSitemap', () => { meta: { // @ts-expect-error: bad lib def toComponent: () => [ - React.createElement('meta', { + createElement('meta', { name: 'robots', content: 'NoFolloW, NoiNDeX', }), @@ -195,7 +211,7 @@ describe('createSitemap', () => { meta: { // @ts-expect-error: bad lib def toComponent: () => [ - React.createElement('meta', {name: 'robots', content: 'noindex'}), + createElement('meta', {name: 'robots', content: 'noindex'}), ], }, }, @@ -203,7 +219,7 @@ describe('createSitemap', () => { meta: { // @ts-expect-error: bad lib def toComponent: () => [ - React.createElement('meta', {name: 'robots', content: 'noindex'}), + createElement('meta', {name: 'robots', content: 'noindex'}), ], }, }, From d7bbfe085b2cc09f1f00e4a70ddee1515eca7fdd Mon Sep 17 00:00:00 2001 From: sebastien Date: Tue, 30 Apr 2024 19:12:25 +0200 Subject: [PATCH 7/8] remove website example --- website/docusaurus.config.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index cc6877b00606..996dcb42b0df 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -490,16 +490,6 @@ export default async function createConfigAsync() { lastmod: 'date', priority: null, changefreq: null, - createSitemapItems: async (params) => { - const {defaultCreateSitemapItems, ...rest} = params; - const sitemapItems = await defaultCreateSitemapItems(rest); - const sitemapsWithoutPageAndTags = sitemapItems.filter( - (sitemapItem) => - !sitemapItem.url.includes('/tags/') && - !sitemapItem.url.includes('/page/'), - ); - return sitemapsWithoutPageAndTags; - }, }, } satisfies Preset.Options, ], From 61ae6079cd017d04f71e5dd872493945a4741587 Mon Sep 17 00:00:00 2001 From: sebastien Date: Tue, 30 Apr 2024 20:02:32 +0200 Subject: [PATCH 8/8] empty