|
1 | | -'use strict'; |
2 | | - |
3 | 1 | import { readFile, writeFile } from 'node:fs/promises'; |
4 | 2 | import { join } from 'node:path'; |
5 | | -import { generateDocEntry } from './utils/generateDocEntry.mjs'; |
6 | | -import { LATEST_DOC_API_BASE_URL } from './constants.mjs'; |
| 3 | + |
| 4 | +import { buildApiDocLink } from './utils/buildApiDocLink.mjs'; |
| 5 | +import { ENTRY_IGNORE_LIST } from './constants.mjs'; |
| 6 | +import { getIntroLinks } from './utils/getIntroLinks.mjs'; |
7 | 7 |
|
8 | 8 | /** |
| 9 | + * This generator generates a llms.txt file to provide information to LLMs at |
| 10 | + * inference time |
| 11 | + * |
9 | 12 | * @typedef {Array<ApiDocMetadataEntry>} Input |
10 | 13 | * |
11 | 14 | * @type {GeneratorMetadata<Input, string>} |
12 | 15 | */ |
13 | 16 | export default { |
14 | 17 | name: 'llms-txt', |
| 18 | + |
15 | 19 | version: '1.0.0', |
16 | | - description: 'Generates a llms.txt file of the API docs', |
| 20 | + |
| 21 | + description: |
| 22 | + 'Generates a llms.txt file to provide information to LLMs at inference time', |
| 23 | + |
17 | 24 | dependsOn: 'ast', |
18 | 25 |
|
19 | 26 | /** |
20 | | - * @param {Input} input The API documentation metadata |
21 | | - * @param {Partial<GeneratorOptions>} options Generator options |
22 | | - * @returns {Promise<string>} The generated documentation text |
| 27 | + * Generates a llms.txt file |
| 28 | + * |
| 29 | + * @param {Input} entries |
| 30 | + * @param {Partial<GeneratorOptions>} options |
| 31 | + * @returns {Promise<void>} |
23 | 32 | */ |
24 | | - async generate(input, options) { |
| 33 | + async generate(entries, { output }) { |
25 | 34 | const template = await readFile( |
26 | 35 | join(import.meta.dirname, 'template.txt'), |
27 | 36 | 'utf-8' |
28 | 37 | ); |
29 | 38 |
|
30 | | - const apiDocEntries = input.map(generateDocEntry).filter(Boolean); |
| 39 | + const introLinks = getIntroLinks().join('\n'); |
31 | 40 |
|
32 | | - const introductionEntries = [ |
33 | | - `- [About this documentation](${LATEST_DOC_API_BASE_URL}/api/documentation.md)`, |
34 | | - `- [Usage and examples](${LATEST_DOC_API_BASE_URL}/api/synopsis.md)`, |
35 | | - ]; |
| 41 | + const apiDocsLinks = entries |
| 42 | + .filter(entry => { |
| 43 | + // Filter non top-level headings and ignored entries |
| 44 | + return ( |
| 45 | + entry.heading.depth === 1 || ENTRY_IGNORE_LIST.includes(entry.path) |
| 46 | + ); |
| 47 | + }) |
| 48 | + .map(entry => { |
| 49 | + const link = buildApiDocLink(entry); |
| 50 | + return `- ${link}`; |
| 51 | + }) |
| 52 | + .join('\n'); |
36 | 53 |
|
37 | 54 | const filledTemplate = template |
38 | | - .replace('__INTRODUCTION__', introductionEntries.join('\n')) |
39 | | - .replace('__API_DOCS__', apiDocEntries.join('\n')); |
| 55 | + .replace('__INTRODUCTION__', introLinks) |
| 56 | + .replace('__API_DOCS__', apiDocsLinks); |
40 | 57 |
|
41 | | - if (options.output) { |
42 | | - await writeFile(join(options.output, 'llms.txt'), filledTemplate); |
| 58 | + if (output) { |
| 59 | + await writeFile(join(output, 'llms.txt'), filledTemplate); |
43 | 60 | } |
44 | 61 |
|
45 | 62 | return filledTemplate; |
|
0 commit comments