Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sitemap): add ignorePatterns option #6979

Merged
merged 7 commits into from
Apr 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe('createSitemap', () => {
{
changefreq: EnumChangefreq.DAILY,
priority: 0.7,
ignorePatterns: [],
},
);
expect(sitemap).toContain(
Expand All @@ -42,11 +43,34 @@ describe('createSitemap', () => {
{
changefreq: EnumChangefreq.DAILY,
priority: 0.7,
ignorePatterns: [],
},
);
expect(sitemap).not.toContain('404');
});

it('excludes patterns configured to be ignored', async () => {
const sitemap = await createSitemap(
{
url: 'https://example.com',
} as DocusaurusConfig,
['/', '/search/', '/tags/', '/search/foo', '/tags/foo/bar'],
{
changefreq: EnumChangefreq.DAILY,
priority: 0.7,
ignorePatterns: [
// Shallow ignore
'/search/',
// Deep ignore
'/tags/**',
],
},
);
expect(sitemap).not.toContain('/search/</loc>');
expect(sitemap).toContain('/search/foo');
expect(sitemap).not.toContain('/tags');
});

it('keep trailing slash unchanged', async () => {
const sitemap = await createSitemap(
{
Expand All @@ -57,6 +81,7 @@ describe('createSitemap', () => {
{
changefreq: EnumChangefreq.DAILY,
priority: 0.7,
ignorePatterns: [],
},
);

Expand All @@ -76,6 +101,7 @@ describe('createSitemap', () => {
{
changefreq: EnumChangefreq.DAILY,
priority: 0.7,
ignorePatterns: [],
},
);

Expand All @@ -95,6 +121,7 @@ describe('createSitemap', () => {
{
changefreq: EnumChangefreq.DAILY,
priority: 0.7,
ignorePatterns: [],
},
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('validateOptions', () => {
const userOptions = {
changefreq: 'yearly',
priority: 0.9,
ignorePatterns: ['/search/**'],
};
expect(testValidate(userOptions)).toEqual({
...defaultOptions,
Expand All @@ -49,4 +50,17 @@ describe('validateOptions', () => {
`"\\"changefreq\\" must be one of [daily, monthly, always, hourly, weekly, yearly, never]"`,
);
});

it('rejects bad ignorePatterns inputs', () => {
expect(() =>
testValidate({ignorePatterns: '/search'}),
).toThrowErrorMatchingInlineSnapshot(
`"\\"ignorePatterns\\" must be an array"`,
);
expect(() =>
testValidate({ignorePatterns: [/^\/search/]}),
).toThrowErrorMatchingInlineSnapshot(
`"\\"ignorePatterns[0]\\" must be a string"`,
);
});
});
11 changes: 7 additions & 4 deletions packages/docusaurus-plugin-sitemap/src/createSitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,28 @@
*/

import {SitemapStream, streamToPromise} from 'sitemap';
import type {Options} from '@docusaurus/plugin-sitemap';
import type {PluginOptions} from '@docusaurus/plugin-sitemap';
import type {DocusaurusConfig} from '@docusaurus/types';
import {applyTrailingSlash} from '@docusaurus/utils-common';
import {createMatcher} from '@docusaurus/utils';

export default async function createSitemap(
siteConfig: DocusaurusConfig,
routesPaths: string[],
options: Options,
options: PluginOptions,
): Promise<string> {
const {url: hostname} = siteConfig;
if (!hostname) {
throw new Error('URL in docusaurus.config.js cannot be empty/undefined.');
}
const {changefreq, priority} = options;
const {changefreq, priority, ignorePatterns} = options;

const ignoreMatcher = createMatcher(ignorePatterns);

const sitemapStream = new SitemapStream({hostname});

routesPaths
.filter((route) => !route.endsWith('404.html'))
.filter((route) => !route.endsWith('404.html') && !ignoreMatcher(route))
.forEach((routePath) =>
sitemapStream.write({
url: applyTrailingSlash(routePath, {
Expand Down
4 changes: 2 additions & 2 deletions packages/docusaurus-plugin-sitemap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

import fs from 'fs-extra';
import path from 'path';
import type {Options} from '@docusaurus/plugin-sitemap';
import type {PluginOptions} from '@docusaurus/plugin-sitemap';
import createSitemap from './createSitemap';
import type {LoadContext, Plugin} from '@docusaurus/types';

export default function pluginSitemap(
context: LoadContext,
options: Options,
options: PluginOptions,
): Plugin<void> {
return {
name: 'docusaurus-plugin-sitemap',
Expand Down
10 changes: 7 additions & 3 deletions packages/docusaurus-plugin-sitemap/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@

import {Joi} from '@docusaurus/utils-validation';
import {EnumChangefreq} from 'sitemap';
import type {Options} from '@docusaurus/plugin-sitemap';
import type {Options, PluginOptions} from '@docusaurus/plugin-sitemap';
import type {OptionValidationContext} from '@docusaurus/types';

export const DEFAULT_OPTIONS: Options = {
export const DEFAULT_OPTIONS: PluginOptions = {
changefreq: EnumChangefreq.WEEKLY,
priority: 0.5,
ignorePatterns: [],
};

const PluginOptionSchema = Joi.object({
Expand All @@ -24,6 +25,9 @@ const PluginOptionSchema = Joi.object({
.valid(...Object.values(EnumChangefreq))
.default(DEFAULT_OPTIONS.changefreq),
priority: Joi.number().min(0).max(1).default(DEFAULT_OPTIONS.priority),
ignorePatterns: Joi.array()
.items(Joi.string())
.default(DEFAULT_OPTIONS.ignorePatterns),
trailingSlash: Joi.forbidden().messages({
'any.unknown':
'Please use the new Docusaurus global trailingSlash config instead, and the sitemaps plugin will use it.',
Expand All @@ -33,7 +37,7 @@ const PluginOptionSchema = Joi.object({
export function validateOptions({
validate,
options,
}: OptionValidationContext<Options, Options>): Options {
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
const validatedOptions = validate(PluginOptionSchema, options);
return validatedOptions;
}
14 changes: 10 additions & 4 deletions packages/docusaurus-plugin-sitemap/src/plugin-sitemap.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@

import type {EnumChangefreq} from 'sitemap';

export type Options = {
id?: string;
export type PluginOptions = {
/** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */
changefreq?: EnumChangefreq;
changefreq: EnumChangefreq;
/** @see https://www.sitemaps.org/protocol.html#xmlTagDefinitions */
priority?: number;
priority: number;
/**
* 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.
*/
ignorePatterns: string[];
};

export type Options = Partial<PluginOptions>;
7 changes: 6 additions & 1 deletion packages/docusaurus-utils/src/globUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,16 @@ type Matcher = (str: string) => boolean;
* A very thin wrapper around `Micromatch.makeRe`.
*
* @see {@link createAbsoluteFilePathMatcher}
* @param patterns A list of glob patterns.
* @param patterns A list of glob patterns. If the list is empty, it defaults to
* matching none.
* @returns A matcher handle that tells if a file path is matched by any of the
* patterns.
*/
export function createMatcher(patterns: string[]): Matcher {
if (patterns.length === 0) {
// `/(?:)/.test("foo")` is `true`
return () => false;
}
const regexp = new RegExp(
patterns.map((pattern) => Micromatch.makeRe(pattern).source).join('|'),
);
Expand Down
2 changes: 2 additions & 0 deletions website/docs/api/plugins/plugin-sitemap.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Accepted fields:
| --- | --- | --- | --- |
| `changefreq` | `string` | `'weekly'` | See [sitemap docs](https://www.sitemaps.org/protocol.html#xmlTagDefinitions) |
| `priority` | `number` | `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. |

</APITable>

Expand Down Expand Up @@ -68,6 +69,7 @@ Most Docusaurus users configure this plugin through the preset options.
const config = {
changefreq: 'weekly',
priority: 0.5,
ignorePatterns: ['/tags/**'],
};
```

Expand Down
3 changes: 3 additions & 0 deletions website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ const config = {
trackingID: 'UA-141789564-1',
}
: undefined,
sitemap: {
ignorePatterns: ['/tests/**'],
},
}),
],
],
Expand Down