Skip to content

Commit

Permalink
Add sitemapBaseUrl option
Browse files Browse the repository at this point in the history
Resolves #2480
  • Loading branch information
Gerrit0 committed Jan 12, 2024
1 parent 0dd9d08 commit aa9afef
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions .config/typedoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"treatWarningsAsErrors": false,
"categorizeByGroup": false,
"categoryOrder": ["Reflections", "Types", "Comments", "*"],
"sitemapBaseUrl": "https://typedoc.org/api/",
"validation": {
"notExported": true,
"invalidLink": true,
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Unreleased

## Features

- Added a new `--sitemapBaseUrl` option. When specified, TypeDoc will generate a `sitemap.xml` in your output folder that describes the site, #2480.

## v0.25.7 (2024-01-08)

### Bug Fixes
Expand Down
94 changes: 94 additions & 0 deletions src/lib/output/plugins/SitemapPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import Path from "path";
import { Component, RendererComponent } from "../components";
import { RendererEvent } from "../events";
import { DefaultTheme } from "../themes/default/DefaultTheme";
import { Option, writeFile } from "../../utils";
import { escapeHtml } from "../../utils/html";

@Component({ name: "sitemap" })
export class SitemapPlugin extends RendererComponent {
@Option("sitemapBaseUrl")
accessor sitemapBaseUrl!: string;

override initialize() {
this.listenTo(this.owner, RendererEvent.BEGIN, this.onRendererBegin);
}

private onRendererBegin(event: RendererEvent) {
if (!(this.owner.theme instanceof DefaultTheme)) {
return;
}
if (event.isDefaultPrevented || !this.sitemapBaseUrl) {
return;
}

this.owner.preRenderAsyncJobs.push((event) => this.buildSitemap(event));
}

private async buildSitemap(event: RendererEvent) {
// cSpell:words lastmod urlset
const sitemapXml = Path.join(event.outputDirectory, "sitemap.xml");
const lastmod = new Date(this.owner.renderStartTime).toISOString();

const urls: XmlElementData[] =
event.urls?.map((url) => {
return {
tag: "url",
children: [
{
tag: "loc",
children: new URL(
url.url,
this.sitemapBaseUrl,
).toString(),
},
{
tag: "lastmod",
children: lastmod,
},
],
};
}) ?? [];

const sitemap =
`<?xml version="1.0" encoding="UTF-8"?>\n` +
stringifyXml({
tag: "urlset",
attr: { xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9" },
children: urls,
}) +
"\n";

await writeFile(sitemapXml, sitemap);
}
}

interface XmlElementData {
attr?: Record<string, string>;
tag: string;
children: XmlElementData[] | string;
}

function stringifyXml(xml: XmlElementData, indent = 0) {
const parts = ["\t".repeat(indent), "<", xml.tag];

for (const [key, val] of Object.entries(xml.attr || {})) {
parts.push(" ", key, '="', escapeHtml(val), '"');
}

parts.push(">");

if (typeof xml.children === "string") {
parts.push(escapeHtml(xml.children));
} else {
for (const child of xml.children) {
parts.push("\n");
parts.push(stringifyXml(child, indent + 1));
}
parts.push("\n", "\t".repeat(indent));
}

parts.push("</", xml.tag, ">");

return parts.join("");
}
1 change: 1 addition & 0 deletions src/lib/output/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { MarkedPlugin } from "../themes/MarkedPlugin";
export { AssetsPlugin } from "./AssetsPlugin";
export { JavascriptIndexPlugin } from "./JavascriptIndexPlugin";
export { NavigationPlugin } from "./NavigationPlugin";
export { SitemapPlugin } from "./SitemapPlugin";
1 change: 1 addition & 0 deletions src/lib/utils/options/declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export interface TypeDocOptionMap {
cname: string;
htmlLang: string;
githubPages: boolean;
sitemapBaseUrl: string;
cacheBust: boolean;
gaID: string;
hideGenerator: boolean;
Expand Down
11 changes: 11 additions & 0 deletions src/lib/utils/options/sources/typedoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,17 @@ export function addTypeDocOptions(options: Pick<Options, "addDeclaration">) {
type: ParameterType.Boolean,
defaultValue: true,
});
options.addDeclaration({
name: "sitemapBaseUrl",
help: "Specify a base URL to be used in generating a sitemap.xml in our output folder. If not specified, no sitemap will be generated.",
validate(value) {
if (!/https?:\/\//.test(value)) {
throw new Error(
"sitemapBaseUrl must start with http:// or https://",
);
}
},
});
options.addDeclaration({
name: "htmlLang",
help: "Sets the lang attribute in the generated html tag.",
Expand Down

0 comments on commit aa9afef

Please sign in to comment.