Skip to content

Commit b074a7f

Browse files
committed
refactor: some improvements
1 parent 32fb861 commit b074a7f

File tree

6 files changed

+95
-60
lines changed

6 files changed

+95
-60
lines changed

src/constants.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ export const DOC_NODE_VERSION = process.version;
66
// This is the Node.js CHANGELOG to be consumed to generate a list of all major Node.js versions
77
export const DOC_NODE_CHANGELOG_URL =
88
'https://raw.githubusercontent.com/nodejs/node/HEAD/CHANGELOG.md';
9+
10+
// The base URL for the latest Node.js documentation
11+
export const LATEST_DOC_API_BASE_URL = 'https://nodejs.org/docs/latest/';

src/generators/llms-txt/constants.mjs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
export const ENTRY_IGNORE_LIST = ['doc/api/synopsis.md'];
2-
3-
export const LATEST_DOC_API_BASE_URL = 'https://nodejs.org/docs/latest';
1+
// These files are not part of the API documentation and are manually included
2+
// in the llms.txt file
3+
export const ENTRY_IGNORE_LIST = [
4+
'doc/api/synopsis.md',
5+
'doc/api/documentation.md',
6+
];

src/generators/llms-txt/index.mjs

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,62 @@
1-
'use strict';
2-
31
import { readFile, writeFile } from 'node:fs/promises';
42
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';
77

88
/**
9+
* This generator generates a llms.txt file to provide information to LLMs at
10+
* inference time
11+
*
912
* @typedef {Array<ApiDocMetadataEntry>} Input
1013
*
1114
* @type {GeneratorMetadata<Input, string>}
1215
*/
1316
export default {
1417
name: 'llms-txt',
18+
1519
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+
1724
dependsOn: 'ast',
1825

1926
/**
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>}
2332
*/
24-
async generate(input, options) {
33+
async generate(entries, { output }) {
2534
const template = await readFile(
2635
join(import.meta.dirname, 'template.txt'),
2736
'utf-8'
2837
);
2938

30-
const apiDocEntries = input.map(generateDocEntry).filter(Boolean);
39+
const introLinks = getIntroLinks().join('\n');
3140

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');
3653

3754
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);
4057

41-
if (options.output) {
42-
await writeFile(join(options.output, 'llms.txt'), filledTemplate);
58+
if (output) {
59+
await writeFile(join(output, 'llms.txt'), filledTemplate);
4360
}
4461

4562
return filledTemplate;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { LATEST_DOC_API_BASE_URL } from '../../../constants.mjs';
2+
import { transformNodeToString } from '../../../utils/unist.mjs';
3+
4+
/**
5+
* Builds a markdown link for an API doc entry
6+
*
7+
* @param {ApiDocMetadataEntry} entry
8+
* @returns {string}
9+
*/
10+
export const buildApiDocLink = entry => {
11+
const title = entry.heading.data.name;
12+
13+
// Remove the leading doc/ from the path
14+
const path = entry.api_doc_source.replace(/^doc\//, '');
15+
const url = new URL(path, LATEST_DOC_API_BASE_URL);
16+
17+
const link = `[${title}](${url})`;
18+
19+
// Find the first paragraph in the content
20+
const descriptionNode = entry.content.children.find(
21+
child => child.type === 'paragraph'
22+
);
23+
24+
if (!descriptionNode) {
25+
return link;
26+
}
27+
28+
const description = transformNodeToString(descriptionNode)
29+
// Remove newlines and extra spaces
30+
.replace(/[\r\n]+/g, ' ');
31+
32+
return `${link}: ${description}`;
33+
};

src/generators/llms-txt/utils/generateDocEntry.mjs

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { LATEST_DOC_API_BASE_URL } from '../constants.mjs';
2+
3+
/**
4+
* Generates a list of introduction links for the llms.txt file
5+
*
6+
* @returns {string[]}
7+
*/
8+
export const getIntroLinks = () => {
9+
const aboutDocUrl = new URL('/api/documentation.md', LATEST_DOC_API_BASE_URL);
10+
const usageExamplesUrl = new URL('/api/synopsis.md', LATEST_DOC_API_BASE_URL);
11+
12+
const introLinks = [
13+
`- [About this documentation](${aboutDocUrl})`,
14+
`- [Usage and examples](${usageExamplesUrl})`,
15+
];
16+
17+
return introLinks;
18+
};

0 commit comments

Comments
 (0)