diff --git a/packages/stacks-docs/.eleventy.js b/packages/stacks-docs/.eleventy.js index d9b9f6981b..acdc51237b 100644 --- a/packages/stacks-docs/.eleventy.js +++ b/packages/stacks-docs/.eleventy.js @@ -18,8 +18,12 @@ module.exports = function(eleventyConfig) { eleventyConfig.addPlugin(iconPlugin); eleventyConfig.addPlugin(headerPlugin); eleventyConfig.addPlugin(tipPlugin); + // Produces /llms-full.txt — a content dump for tools that want the full + // markdown of every page in one file. The spec-compliant index lives at + // /llms.txt and is rendered by llms.11ty.js. eleventyConfig.addPlugin(llmsTxtPlugin, { siteUrl: 'https://v2.stackoverflow.design', + outputPath: 'llms-full.txt', collections: ['base', 'components', 'develop', 'foundation'], additionalMetadata: ['description'], normalizeWhitespace: true, diff --git a/packages/stacks-docs/llms.11ty.js b/packages/stacks-docs/llms.11ty.js new file mode 100644 index 0000000000..4730200001 --- /dev/null +++ b/packages/stacks-docs/llms.11ty.js @@ -0,0 +1,60 @@ +// Renders the spec-compliant llms.txt index at /llms.txt +// (see https://llmstxt.org). The full content dump lives at /llms-full.txt, +// generated by eleventy-plugin-llms-txt — see .eleventy.js. + +const SECTIONS = [ + { tag: "base", heading: "Base utilities" }, + { tag: "components", heading: "Components" }, + { tag: "develop", heading: "Develop" }, + { tag: "foundation", heading: "Foundation" }, +]; + +// Descriptions may contain inline HTML for the rendered page; strip it for +// llms.txt. Loop until stable so unclosed/nested-looking tags can't reintroduce +// the pattern (CodeQL js/incomplete-multi-character-sanitization). +function stripHtml(input) { + let previous; + let output = input; + do { + previous = output; + output = output.replace(/<[^>]+>/g, ""); + } while (output !== previous); + return output; +} + +function pageLink(page, siteUrl) { + const title = page.data.title; + const description = stripHtml(page.data.description || "") + .replace(/\s+/g, " ") + .trim(); + const suffix = description ? `: ${description}` : ""; + return `- [${title}](${siteUrl}${page.url})${suffix}`; +} + +module.exports = class { + data() { + return { + permalink: "/llms.txt", + eleventyExcludeFromCollections: true, + }; + } + + render({ collections, site }) { + const sections = SECTIONS.map(({ tag, heading }) => { + const pages = (collections[tag] || []) + .slice() + .sort((a, b) => + (a.data.title || "").localeCompare(b.data.title || "") + ); + const lines = pages.map((p) => pageLink(p, site.url)); + return `## ${heading}\n\n${lines.join("\n")}`; + }); + + return `# ${site.title} + +> ${site.description} + +${sections.join("\n\n")} +`; + } +};