Skip to content

Commit 277f607

Browse files
committed
refactor: improvements
1 parent 21bb6e2 commit 277f607

File tree

6 files changed

+105
-94
lines changed

6 files changed

+105
-94
lines changed

src/constants.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,3 @@ 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-
export const DOC_API_LATEST_BASE_URL = 'https://nodejs.org/docs/latest';

src/generators/llms-txt/constants.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const ENTRY_IGNORE_LIST = ['doc/api/synopsis.md'];
2+
3+
export const LATEST_DOC_API_BASE_URL = 'https://nodejs.org/docs/latest';

src/generators/llms-txt/index.mjs

Lines changed: 18 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,9 @@
11
'use strict';
22

3-
import { writeFile } from 'node:fs/promises';
3+
import { readFile, writeFile } from 'node:fs/promises';
44
import { join } from 'node:path';
5-
import { DOC_API_LATEST_BASE_URL } from '../../constants.mjs';
6-
7-
const IGNORE_LIST = ['doc/api/synopsis.md'];
8-
9-
/**
10-
* Extracts text content from a node recursively
11-
*
12-
* @param {import('mdast').Paragraph} node The AST node to extract text from
13-
* @returns {string} The extracted text content
14-
*/
15-
function extractTextContent(node) {
16-
if (!node) {
17-
return '';
18-
}
19-
20-
if (node.type === 'text' || node.type === 'inlineCode') {
21-
return node.value;
22-
}
23-
24-
if (node.children && Array.isArray(node.children)) {
25-
return node.children.map(extractTextContent).join('');
26-
}
27-
28-
return '';
29-
}
30-
31-
/**
32-
* Extracts text from a paragraph node.
33-
*
34-
* @param {import('mdast').Paragraph} node The paragraph node to extract text from
35-
* @returns {string} The extracted text content
36-
* @throws {Error} If the node is not a paragraph
37-
*/
38-
function paragraphToString(node) {
39-
if (node.type !== 'paragraph') {
40-
throw new Error('Node is not a paragraph');
41-
}
42-
43-
return node.children.map(extractTextContent).join('');
44-
}
45-
46-
/**
47-
* Generates a documentation entry string
48-
*
49-
* @param {ApiDocMetadataEntry} entry
50-
* @returns {string}
51-
*/
52-
function generateDocEntry(entry) {
53-
if (IGNORE_LIST.includes(entry.api_doc_source)) {
54-
return null;
55-
}
56-
57-
if (entry.heading.depth !== 1) {
58-
return null;
59-
}
60-
61-
// Remove the leading /doc of string
62-
const path = entry.api_doc_source.replace(/^doc\//, '');
63-
64-
const entryLink = `[${entry.heading.data.name}](${DOC_API_LATEST_BASE_URL}/${path})`;
65-
66-
const descriptionNode = entry.content.children.find(
67-
child => child.type === 'paragraph'
68-
);
69-
70-
if (!descriptionNode) {
71-
console.warn(`No description found for entry: ${entry.api_doc_source}`);
72-
return `- ${entryLink}`;
73-
}
74-
75-
const description = paragraphToString(descriptionNode).replace(
76-
/[\r\n]+/g,
77-
' '
78-
);
79-
80-
return `- ${entryLink}: ${description}`;
81-
}
5+
import { generateDocEntry } from './utils/generateDocEntry.mjs';
6+
import { LATEST_DOC_API_BASE_URL } from './constants.mjs';
827

838
/**
849
* @typedef {Array<ApiDocMetadataEntry>} Input
@@ -87,7 +12,7 @@ function generateDocEntry(entry) {
8712
*/
8813
export default {
8914
name: 'llms-txt',
90-
version: '0.1.0',
15+
version: '1.0.0',
9116
description: 'Generates a llms.txt file of the API docs',
9217
dependsOn: 'ast',
9318

@@ -97,25 +22,26 @@ export default {
9722
* @returns {Promise<string>} The generated documentation text
9823
*/
9924
async generate(input, options) {
100-
const output = [
101-
'# Node.js Documentation',
102-
'> Node.js is an open-source, cross-platform JavaScript runtime environment that executes JavaScript code outside a web browser. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient for building scalable network applications.',
103-
'## Introduction',
104-
`- [About this documentation](${DOC_API_LATEST_BASE_URL}/api/documentation.md)`,
105-
`- [Usage and example](${DOC_API_LATEST_BASE_URL}/api/synopsis.md)`,
106-
'## API Documentation',
107-
];
25+
const template = await readFile(
26+
join(import.meta.dirname, 'template.txt'),
27+
'utf-8'
28+
);
10829

109-
const docEntries = input.map(generateDocEntry).filter(Boolean);
30+
const apiDocEntries = input.map(generateDocEntry).filter(Boolean);
11031

111-
output.push(...docEntries);
32+
const introductionEntries = [
33+
`- [About this documentation](${LATEST_DOC_API_BASE_URL}/api/documentation.md)`,
34+
`- [Usage and example](${LATEST_DOC_API_BASE_URL}/api/synopsis.md)`,
35+
];
11236

113-
const resultText = output.join('\n');
37+
const filledTemplate = template
38+
.replace('__INTRODUCTION__', introductionEntries.join('\n'))
39+
.replace('__API_DOCS__', apiDocEntries.join('\n'));
11440

11541
if (options.output) {
116-
await writeFile(join(options.output, 'llms.txt'), resultText);
42+
await writeFile(join(options.output, 'llms.txt'), filledTemplate);
11743
}
11844

119-
return resultText;
45+
return filledTemplate;
12046
},
12147
};

src/generators/llms-txt/template.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Node.js Documentation
2+
3+
> Node.js is an open-source, cross-platform JavaScript runtime environment that executes JavaScript code outside a web browser. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient for building scalable network applications.
4+
5+
## Introduction
6+
__INTRODUCTION__
7+
8+
## API Documentations
9+
__API_DOCS__
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { ENTRY_IGNORE_LIST, LATEST_DOC_API_BASE_URL } from '../constants.mjs';
2+
import { paragraphToString } from './paragraphToString.mjs';
3+
4+
/**
5+
* Generates a documentation entry string
6+
*
7+
* @param {ApiDocMetadataEntry} entry
8+
* @returns {string}
9+
*/
10+
export function generateDocEntry(entry) {
11+
if (ENTRY_IGNORE_LIST.includes(entry.api_doc_source)) {
12+
return null;
13+
}
14+
15+
if (entry.heading.depth !== 1) {
16+
return null;
17+
}
18+
19+
// Remove the leading /doc of string
20+
const path = entry.api_doc_source.replace(/^doc\//, '');
21+
22+
const entryLink = `[${entry.heading.data.name}](${LATEST_DOC_API_BASE_URL}/${path})`;
23+
24+
const descriptionNode = entry.content.children.find(
25+
child => child.type === 'paragraph'
26+
);
27+
28+
if (!descriptionNode) {
29+
console.warn(`No description found for entry: ${entry.api_doc_source}`);
30+
return `- ${entryLink}`;
31+
}
32+
33+
const description = paragraphToString(descriptionNode).replace(
34+
/[\r\n]+/g,
35+
' '
36+
);
37+
38+
return `- ${entryLink}: ${description}`;
39+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Extracts text content from a node recursively
3+
*
4+
* @param {import('mdast').Paragraph} node The AST node to extract text from
5+
* @returns {string} The extracted text content
6+
*/
7+
function extractTextContent(node) {
8+
if (!node) {
9+
return '';
10+
}
11+
12+
if (node.type === 'text' || node.type === 'inlineCode') {
13+
return node.value;
14+
}
15+
16+
if (node.children && Array.isArray(node.children)) {
17+
return node.children.map(extractTextContent).join('');
18+
}
19+
20+
return '';
21+
}
22+
23+
/**
24+
* Extracts text from a paragraph node.
25+
*
26+
* @param {import('mdast').Paragraph} node The paragraph node to extract text from
27+
* @returns {string} The extracted text content
28+
* @throws {Error} If the node is not a paragraph
29+
*/
30+
export function paragraphToString(node) {
31+
if (node.type !== 'paragraph') {
32+
throw new Error('Node is not a paragraph');
33+
}
34+
35+
return node.children.map(extractTextContent).join('');
36+
}

0 commit comments

Comments
 (0)