104 lines
2.8 KiB
TypeScript
104 lines
2.8 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import path, { dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { XMLParser } from "fast-xml-parser";
|
|
import { z } from "zod/v4";
|
|
|
|
import { createDocumentationLink } from "./index";
|
|
import { integrationDocSlugs } from "./integration-doc-slugs";
|
|
import { widgetDocSlugs } from "./widget-doc-slugs";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
const removeCommonUrl = (url: string) => {
|
|
return url.replace("https://homarr.dev", "");
|
|
};
|
|
|
|
const sitemapSchema = z.object({
|
|
urlset: z.object({
|
|
url: z.array(
|
|
z.object({
|
|
loc: z.string(),
|
|
}),
|
|
),
|
|
}),
|
|
});
|
|
|
|
const fetchSitemapAsync = async () => {
|
|
const response = await fetch(createDocumentationLink("/sitemap.xml"));
|
|
return await response.text();
|
|
};
|
|
|
|
const parseXml = (sitemapXml: string) => {
|
|
const parser = new XMLParser();
|
|
const data: unknown = parser.parse(sitemapXml);
|
|
const result = sitemapSchema.safeParse(data);
|
|
if (!result.success) {
|
|
throw new Error("Invalid sitemap schema");
|
|
}
|
|
|
|
return result.data;
|
|
};
|
|
|
|
const mapSitemapXmlToPaths = (sitemapData: z.infer<typeof sitemapSchema>) => {
|
|
return sitemapData.urlset.url.map((url) => removeCommonUrl(url.loc));
|
|
};
|
|
|
|
const createSitemapPathType = (paths: string[]) => {
|
|
return "export type HomarrDocumentationPath =\n" + paths.map((path) => ` | "${path.replace(/\/$/, "")}"`).join("\n");
|
|
};
|
|
|
|
const updateSitemapTypeFileAsync = async (sitemapPathType: string) => {
|
|
const content =
|
|
"// This file is auto-generated by the codegen script\n" +
|
|
"// it uses the sitemap.xml to generate the HomarrDocumentationPath type\n" +
|
|
sitemapPathType +
|
|
";\n";
|
|
|
|
await fs.writeFile(outputPath, content);
|
|
};
|
|
|
|
const slugMapPaths = [
|
|
...Object.values(integrationDocSlugs)
|
|
.filter(Boolean)
|
|
.map((slug) => `/docs/integrations/${slug}`),
|
|
...Object.values(widgetDocSlugs)
|
|
.filter(Boolean)
|
|
.map((slug) => `/docs/widgets/${slug}`),
|
|
];
|
|
|
|
const outputPath = path.join(__dirname, "homarr-docs-sitemap.ts");
|
|
|
|
const main = async () => {
|
|
let paths: string[];
|
|
try {
|
|
const sitemapXml = await fetchSitemapAsync();
|
|
const sitemapData = parseXml(sitemapXml);
|
|
paths = mapSitemapXmlToPaths(sitemapData);
|
|
} catch {
|
|
const exists = await fs.access(outputPath).then(
|
|
() => true,
|
|
() => false,
|
|
);
|
|
if (exists) {
|
|
console.warn("Could not fetch sitemap from homarr.dev, keeping existing generated file");
|
|
return;
|
|
}
|
|
console.warn("Could not fetch sitemap from homarr.dev and no existing file, generating from slug maps only");
|
|
paths = [];
|
|
}
|
|
|
|
paths.push("/sitemap.xml");
|
|
for (const p of slugMapPaths) {
|
|
if (!paths.includes(p)) {
|
|
paths.push(p);
|
|
}
|
|
}
|
|
|
|
const sitemapPathType = createSitemapPathType(paths);
|
|
await updateSitemapTypeFileAsync(sitemapPathType);
|
|
};
|
|
|
|
void main();
|