Skip to content
Draft
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
31 changes: 26 additions & 5 deletions app/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import path from "node:path";
import type { MetadataRoute } from "next";
import { listToolkitRoutes } from "./_lib/toolkit-static-params";

const SITE_URL = process.env.SITE_URL ?? "https://docs.arcade.dev";
const NORMALIZED_SITE_URL = SITE_URL.replace(/\/+$/, "");
Expand Down Expand Up @@ -43,13 +44,33 @@ async function collectRoutes(dir: string): Promise<MetadataRoute.Sitemap> {
return entries;
}

async function buildSitemap(): Promise<MetadataRoute.Sitemap> {
const [mdxRoutes, toolkitRoutes] = await Promise.all([
collectRoutes(APP_DIR),
listToolkitRoutes(),
]);

const toolkitEntries: MetadataRoute.Sitemap = toolkitRoutes
.filter((route) => route.category !== "others")
.map((route) => ({
url: `${NORMALIZED_SITE_URL}/en/resources/integrations/${route.category}/${route.toolkitId}`,
}));

const seen = new Set<string>(mdxRoutes.map((r) => r.url));
const uniqueToolkitEntries = toolkitEntries.filter((entry) => {
if (seen.has(entry.url)) { return false; }
seen.add(entry.url);
return true;
});

return [...mdxRoutes, ...uniqueToolkitEntries].sort((a, b) =>
a.url.localeCompare(b.url)
);
}

export default function sitemap(): Promise<MetadataRoute.Sitemap> {
if (!cachedRoutes) {
cachedRoutes = collectRoutes(APP_DIR).then((routes) => {
routes.sort((a, b) => a.url.localeCompare(b.url));
return routes;
});
cachedRoutes = buildSitemap();
}

return cachedRoutes;
}
14 changes: 13 additions & 1 deletion tests/sitemap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,21 @@ test("sitemap lists expected URLs", async () => {
true
);

// Known page should be present
// Known static page should be present
expect(urls).toContain("https://example.test/en/references/changelog");

// Toolkit pages should be included
expect(urls).toContain(
"https://example.test/en/resources/integrations/development/github"
);
const integrationUrls = urls.filter((url) =>
url.includes("/en/resources/integrations/")
);
expect(integrationUrls.length).toBeGreaterThan(10);

// No dynamic-segment placeholders should leak into output
expect(urls.every((url) => !url.includes("["))).toBe(true);

// No duplicates
const duplicates = urls.filter(
(url, index, arr) => arr.indexOf(url) !== index
Expand Down
Loading