Skip to content

Commit fa32828

Browse files
authored
Merge pull request #92 from rescript-lang/llm.txt
Add API documentation as llm.txt
2 parents ba7e2d9 + 561cdf8 commit fa32828

File tree

4 files changed

+128
-1
lines changed

4 files changed

+128
-1
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
.bsb.lock
44
.astro
55
dist/
6-
tmp/
6+
tmp/
7+
docs/public/llm.txt

astro.config.mjs

+8
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ export default defineConfig({
7777
...apiSidebarItems,
7878
],
7979
},
80+
{
81+
label: "LLM Documentation",
82+
link: "./llm.txt",
83+
badge: {
84+
text: "New",
85+
variant: "tip",
86+
},
87+
},
8088
],
8189
customCss: ["./docs/styles/fonts.css", "./docs/styles/theme.css"],
8290
expressiveCode: {

docs/llm.js

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import * as path from "node:path";
2+
import { exec } from "node:child_process";
3+
import { promisify } from "node:util";
4+
import fs from "node:fs/promises";
5+
6+
const execAsync = promisify(exec);
7+
8+
const bins = await import(
9+
path.join(import.meta.dirname, "../node_modules/rescript/cli/common/bins.js")
10+
);
11+
const rescriptTools = bins["rescript_tools_exe"];
12+
13+
if (!rescriptTools) {
14+
throw new Error("rescript-tools not found");
15+
}
16+
17+
async function getDocJson(filePath) {
18+
try {
19+
const command = `${rescriptTools} doc "${filePath}"`;
20+
const options = { maxBuffer: 10 * 1024 * 1024 };
21+
const { stdout, stderr } = await execAsync(command, options);
22+
23+
if (stderr) {
24+
throw new Error(`Error executing command for ${filePath}: ${stderr}`);
25+
}
26+
27+
return JSON.parse(stdout);
28+
} catch (error) {
29+
throw new Error(`Failed to get documentation JSON for ${filePath}:`, error);
30+
}
31+
}
32+
33+
async function processFile(filePath) {
34+
const json = await getDocJson(filePath);
35+
36+
const moduleName = "WebAPI." + json.name.replace("-WebAPI", "");
37+
38+
const types = [];
39+
const functions = [];
40+
41+
function mkType(item) {
42+
let description = "";
43+
if (item.docstrings.length > 0) {
44+
description = "\n Description: " + item.docstrings.join("\n");
45+
}
46+
let fields = "";
47+
if (item.detail && item.detail.kind === "record") {
48+
fields =
49+
"\n Fields:\n" +
50+
item.detail.items
51+
.map((field) => {
52+
let fieldDoc = "";
53+
if (field.docstrings.length > 0) {
54+
fieldDoc = " - " + field.docstrings.join(" ");
55+
}
56+
return ` - ${field.name}: ${field.signature}${fieldDoc}`;
57+
})
58+
.join("\n");
59+
}
60+
return `- ${item.signature}${description}${fields}`;
61+
}
62+
63+
function mkFunction(item) {
64+
let description = "";
65+
if (item.docstrings.length > 0) {
66+
description = "\n Description: " + item.docstrings.join("\n");
67+
}
68+
return `- ${item.signature}${description}`;
69+
}
70+
71+
for (const item of json.items) {
72+
switch (item.kind) {
73+
case "type":
74+
types.push(mkType(item));
75+
break;
76+
case "value":
77+
functions.push(mkFunction(item));
78+
break;
79+
}
80+
}
81+
82+
let typeString = "";
83+
if (types.length > 0) {
84+
typeString = "\n\nTypes:\n\n" + types.join("\n\n");
85+
}
86+
87+
let functionString = "";
88+
if (functions.length > 0) {
89+
functionString = "\n\nFunctions:\n\n" + functions.join("\n\n");
90+
}
91+
92+
return `File: ${json.source.filepath}
93+
Module: ${moduleName}${typeString}${functionString}
94+
`;
95+
}
96+
97+
const pattern = "../src/**/*.res"
98+
const files = [];
99+
for await (const file of fs.glob(pattern, { recursive: true, cwd: import.meta.dirname })) {
100+
files.push(path.join(import.meta.dirname, file));
101+
}
102+
files.sort();
103+
104+
const pages = await Promise.all(files.map(processFile))
105+
const packageJson = await fs.readFile(path.join(import.meta.dirname, "../package.json"), "utf-8");
106+
let version = JSON.parse(packageJson).version;
107+
const sha = await execAsync("git rev-parse --short HEAD").then(({ stdout }) => stdout.trim());
108+
const fullVersion = `${version}-${sha}`;
109+
const header = `Experimental Rescript WebAPI Documentation ${fullVersion}
110+
111+
This is the API documentation for the experimental WebAPI module version ${fullVersion}.
112+
More information can be found on https://rescript-lang.github.io/experimental-rescript-webapi/
113+
114+
`
115+
const content = pages.join("\n---\n\n");
116+
await fs.writeFile(path.join(import.meta.dirname, "public/llm.txt"), header + content);
117+
console.log("Generated llm.txt");

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"build": "rescript",
3232
"format": "rescript format -all && prettier --write ./tests/index.js ./package.json ./docs/pages",
3333
"docs": "astro dev",
34+
"pre:build:docs": "node docs/llm.js",
3435
"build:docs": "astro build"
3536
},
3637
"license": "MIT",

0 commit comments

Comments
 (0)