llm-txt-plugin.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. const path = require('path');
  2. const fs = require('fs');
  3. const DOCS_BASE_URL = process.env.DOCS_BASE_URL || 'https://docs.vendure.io';
  4. module.exports = function (context) {
  5. return {
  6. name: 'llms-txt-plugin',
  7. loadContent: async () => {
  8. const { siteDir } = context;
  9. const contentDir = siteDir;
  10. const allMdx = [];
  11. // recursive function to get all mdx and md files
  12. const getMdxFiles = async dir => {
  13. const entries = await fs.promises.readdir(dir, { withFileTypes: true });
  14. for (const entry of entries) {
  15. const fullPath = path.join(dir, entry.name);
  16. if (entry.isDirectory()) {
  17. await getMdxFiles(fullPath);
  18. } else if (entry.name.endsWith('.mdx') || entry.name.endsWith('.md')) {
  19. const content = await fs.promises.readFile(fullPath, 'utf8');
  20. allMdx.push(content);
  21. }
  22. }
  23. };
  24. await getMdxFiles(contentDir);
  25. return { allMdx };
  26. },
  27. postBuild: async ({ content, routes, outDir }) => {
  28. const { allMdx } = content;
  29. // Remove the README.md file of the docs
  30. const filteredMdx = allMdx.slice(1);
  31. // Write concatenated MD and MDX content
  32. const concatenatedPath = path.join(outDir, 'llms-full.txt');
  33. await fs.promises.writeFile(concatenatedPath, filteredMdx.join('\n\n---\n\n'));
  34. // we need to dig down several layers:
  35. // find PluginRouteConfig marked by plugin.name === "docusaurus-plugin-content-docs"
  36. const docsPluginRouteConfig = routes.filter(
  37. route => route.plugin.name === 'docusaurus-plugin-content-docs',
  38. )[0];
  39. // docsPluginRouteConfig has a routes property has a record with the path "/" that contains all docs routes.
  40. const allDocsRouteConfig = docsPluginRouteConfig.routes?.filter(route => route.path === '/')[0];
  41. // A little type checking first
  42. if (!allDocsRouteConfig?.props?.version) {
  43. return;
  44. }
  45. // this route config has a `props` property that contains the current documentation.
  46. const currentVersionDocsRoutes = allDocsRouteConfig.props.version.docs;
  47. // for every single docs route we now parse a path (which is the key) and a title
  48. const docsRecords = Object.entries(currentVersionDocsRoutes)
  49. .filter(([path, record]) => record.id !== 'TODO')
  50. .map(([path, record]) => {
  51. return `- [${record.title}](${DOCS_BASE_URL}/${path}): ${record.description}`;
  52. });
  53. // Build up llms.txt file
  54. const llmsTxt = `# ${context.siteConfig.title}\n\n## Docs\n\n${docsRecords.join('\n')}`;
  55. // Write llms.txt file
  56. const llmsTxtPath = path.join(outDir, 'llms.txt');
  57. try {
  58. fs.writeFileSync(llmsTxtPath, llmsTxt);
  59. } catch (err) {
  60. throw err;
  61. }
  62. },
  63. };
  64. };