UNPKG

docusaurus-plugin-llms

Version:

Docusaurus plugin for generating LLM-friendly documentation following the llmstxt.org standard

163 lines (144 loc) 4.88 kB
/** * @fileoverview Docusaurus plugin that generates LLM-friendly documentation following the llmstxt.org standard. * * This plugin creates two files: * - llms.txt: Contains links to all sections of documentation * - llms-full.txt: Contains all documentation content in a single file * * The plugin runs during the Docusaurus build process and scans all Markdown files in the docs directory. */ import * as path from 'path'; import type { LoadContext, Plugin, Props, RouteConfig } from '@docusaurus/types'; import { PluginOptions, PluginContext } from './types'; import { collectDocFiles, generateStandardLLMFiles, generateCustomLLMFiles } from './generator'; /** * A Docusaurus plugin to generate LLM-friendly documentation following * the llmstxt.org standard * * @param context - Docusaurus context * @param options - Plugin options * @returns Plugin object */ export default function docusaurusPluginLLMs( context: LoadContext, options: PluginOptions = {} ): Plugin<void> { // Set default options const { generateLLMsTxt = true, generateLLMsFullTxt = true, docsDir = 'docs', ignoreFiles = [], title, description, llmsTxtFilename = 'llms.txt', llmsFullTxtFilename = 'llms-full.txt', includeBlog = false, pathTransformation, includeOrder = [], includeUnmatchedLast = true, customLLMFiles = [], excludeImports = false, removeDuplicateHeadings = false, generateMarkdownFiles = false, keepFrontMatter = [], rootContent, fullRootContent, } = options; const { siteDir, siteConfig, outDir, } = context; // Build the site URL with proper trailing slash const siteUrl = siteConfig.url + ( siteConfig.baseUrl.endsWith('/') ? siteConfig.baseUrl.slice(0, -1) : siteConfig.baseUrl || '' ); // Create a plugin context object with processed options const pluginContext: PluginContext = { siteDir, outDir, siteUrl, docsDir, docTitle: title || siteConfig.title, docDescription: description || siteConfig.tagline || '', options: { generateLLMsTxt, generateLLMsFullTxt, docsDir, ignoreFiles, title, description, llmsTxtFilename, llmsFullTxtFilename, includeBlog, pathTransformation, includeOrder, includeUnmatchedLast, customLLMFiles, excludeImports, removeDuplicateHeadings, generateMarkdownFiles, keepFrontMatter, rootContent, fullRootContent, } }; return { name: 'docusaurus-plugin-llms', /** * Generates LLM-friendly documentation files after the build is complete */ async postBuild(props?: Props & { content: unknown }): Promise<void> { console.log('Generating LLM-friendly documentation...'); try { let enhancedContext = pluginContext; // If props are provided (Docusaurus 3.x+), use the resolved routes if (props?.routes) { // Create a map of file paths to their resolved URLs const routeMap = new Map<string, string>(); // Helper function to recursively process routes const processRoutes = (routes: RouteConfig[]) => { routes.forEach(route => { if (route.path) { // Store the actual resolved path routeMap.set(route.path, route.path); } // Process nested routes recursively if (route.routes) { processRoutes(route.routes); } }); }; // Process all routes (cast to RouteConfig[] for recursive processing) processRoutes(props.routes as RouteConfig[]); // Pass the resolved routes to the plugin context enhancedContext = { ...pluginContext, routesPaths: props.routesPaths, routes: props.routes, routeMap, }; } // Collect all document files const allDocFiles = await collectDocFiles(enhancedContext); // Skip further processing if no documents were found if (allDocFiles.length === 0) { console.warn('No documents found to process.'); return; } // Process standard LLM files (llms.txt and llms-full.txt) await generateStandardLLMFiles(enhancedContext, allDocFiles); // Process custom LLM files await generateCustomLLMFiles(enhancedContext, allDocFiles); // Output overall statistics console.log(`Stats: ${allDocFiles.length} total available documents processed`); } catch (err: any) { console.error('Error generating LLM documentation:', err); } }, }; } export type { PluginOptions };