129 lines
4.0 KiB
JavaScript
Executable File
129 lines
4.0 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
"use strict";
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const repoRoot = path.resolve(__dirname, "..");
|
|
const stdDir = path.join(repoRoot, "lib", "std");
|
|
const outputPath = path.join(repoRoot, "docs", "language", "STDLIB_API.md");
|
|
const cargoTomlPath = path.join(repoRoot, "compiler", "Cargo.toml");
|
|
|
|
function tokenize(source) {
|
|
const tokens = [];
|
|
const pattern = /\(|\)|[^\s()]+/g;
|
|
let match;
|
|
while ((match = pattern.exec(source)) !== null) {
|
|
tokens.push(match[0]);
|
|
}
|
|
return tokens;
|
|
}
|
|
|
|
function parseList(tokens, cursor) {
|
|
if (tokens[cursor.index] !== "(") {
|
|
throw new Error(`expected list at token ${cursor.index}`);
|
|
}
|
|
cursor.index += 1;
|
|
const list = [];
|
|
while (cursor.index < tokens.length && tokens[cursor.index] !== ")") {
|
|
if (tokens[cursor.index] === "(") {
|
|
list.push(parseList(tokens, cursor));
|
|
} else {
|
|
list.push(tokens[cursor.index]);
|
|
cursor.index += 1;
|
|
}
|
|
}
|
|
if (tokens[cursor.index] !== ")") {
|
|
throw new Error("unterminated list");
|
|
}
|
|
cursor.index += 1;
|
|
return list;
|
|
}
|
|
|
|
function moduleForm(source, file) {
|
|
const tokens = tokenize(source);
|
|
if (tokens[0] !== "(") {
|
|
throw new Error(`${file}: expected module form`);
|
|
}
|
|
const form = parseList(tokens, { index: 0 });
|
|
if (form[0] !== "module" || typeof form[1] !== "string") {
|
|
throw new Error(`${file}: expected (module name ...) form`);
|
|
}
|
|
const exportForm = form.find((item) => Array.isArray(item) && item[0] === "export");
|
|
if (!exportForm) {
|
|
throw new Error(`${file}: module must have an explicit export list`);
|
|
}
|
|
return {
|
|
name: form[1],
|
|
exports: exportForm.slice(1),
|
|
};
|
|
}
|
|
|
|
function stdModules() {
|
|
return fs
|
|
.readdirSync(stdDir)
|
|
.filter((name) => name.endsWith(".slo"))
|
|
.sort()
|
|
.map((fileName) => {
|
|
const relativePath = path.join("lib", "std", fileName);
|
|
const source = fs.readFileSync(path.join(stdDir, fileName), "utf8");
|
|
const module = moduleForm(source, relativePath);
|
|
return {
|
|
fileName,
|
|
relativePath,
|
|
name: module.name,
|
|
exports: module.exports,
|
|
};
|
|
});
|
|
}
|
|
|
|
function packageVersion() {
|
|
const cargoToml = fs.readFileSync(cargoTomlPath, "utf8");
|
|
const versionMatch = cargoToml.match(/^version\s*=\s*"([^"]+)"$/m);
|
|
if (!versionMatch) {
|
|
throw new Error("compiler/Cargo.toml must declare a package version");
|
|
}
|
|
return versionMatch[1];
|
|
}
|
|
|
|
function render(modules, version) {
|
|
const totalExports = modules.reduce((count, module) => count + module.exports.length, 0);
|
|
const out = [];
|
|
out.push("# Slovo Standard Library API Catalog");
|
|
out.push("");
|
|
out.push("Generated from `lib/std/*.slo` by `scripts/render-stdlib-api-doc.sh`.");
|
|
out.push("Do not edit this file by hand.");
|
|
out.push("");
|
|
out.push("## Stability Tiers");
|
|
out.push("");
|
|
out.push("- `beta-supported`: exported from `lib/std` and covered by source-search, promotion, or facade gates in the current beta line.");
|
|
out.push(`- \`experimental\`: not used for exported \`lib/std\` helpers in \`${version}\`; future releases may mark new helpers this way before they graduate.`);
|
|
out.push("- `internal`: helper names that are not exported from their module; they are intentionally omitted from this catalog.");
|
|
out.push("");
|
|
out.push("The catalog is a beta compatibility aid, not a stable `1.0.0` API freeze.");
|
|
out.push("");
|
|
out.push("## Summary");
|
|
out.push("");
|
|
out.push(`- Modules: ${modules.length}`);
|
|
out.push(`- Exported helpers: ${totalExports}`);
|
|
out.push("- Default tier: `beta-supported`");
|
|
out.push("");
|
|
out.push("## Modules");
|
|
out.push("");
|
|
for (const module of modules) {
|
|
out.push(`### std.${module.name}`);
|
|
out.push("");
|
|
out.push(`- Path: \`${module.relativePath}\``);
|
|
out.push("- Tier: `beta-supported`");
|
|
out.push(`- Exported helpers: ${module.exports.length}`);
|
|
out.push("");
|
|
for (const exported of module.exports) {
|
|
out.push(`- \`${exported}\``);
|
|
}
|
|
out.push("");
|
|
}
|
|
return `${out.join("\n")}\n`;
|
|
}
|
|
|
|
fs.writeFileSync(outputPath, render(stdModules(), packageVersion()));
|