tinymist/scripts/link-docs.mjs
Myriad-Dreamin 1210b54515
Some checks are pending
tinymist::ci / publish-vscode (push) Blocked by required conditions
tinymist::ci / build-vsc-assets (push) Blocked by required conditions
tinymist::ci / build-vscode (push) Blocked by required conditions
tinymist::ci / build-vscode-others (push) Blocked by required conditions
tinymist::ci / Duplicate Actions Detection (push) Waiting to run
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Waiting to run
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Waiting to run
tinymist::ci / E2E Tests (darwin-arm64 on macos-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-22.04) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-2022) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-latest) (push) Blocked by required conditions
tinymist::ci / prepare-build (push) Waiting to run
tinymist::ci / build-binary (push) Blocked by required conditions
tinymist::gh_pages / build-gh-pages (push) Waiting to run
feat: finally directly generate markdown files (#1881)
* feat: finally directly generate markdown files

* fix: trim

* fix: await
2025-07-07 13:11:23 +08:00

162 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { resolve, basename, relative } from "path";
import * as fs from "fs";
import * as util from "util";
import { execSync } from "child_process";
const exec = util.promisify(execSync);
const root = resolve(import.meta.dirname, "..");
const dry = process.argv.includes("--dry");
const yarn = (cmd, stdio = "inherit") => {
const script = `yarn run ${cmd}`;
if (dry) {
return script;
}
return execSync(script, { stdio });
};
const typlite = (input, output) => {
const assets_flag = dry
? ""
: `--assets-path ${relative(root, resolve(output, "../assets/images/", basename(input.slice(0, -4))))}`;
// return stdout
const res = yarn(`--silent typlite ${assets_flag} --root ${root} ${input} -`, "pipe");
return res.toString();
};
const isCheck = process.argv.includes("--check");
const convert = async ({ input: inp, output: out }) => {
const input = resolve(root, inp);
const output = resolve(root, out);
const outputContent = typlite(input, output).trim();
if (dry) {
console.log(outputContent);
return;
}
await fs.promises.writeFile(output, outputContent.trim() + "\n");
if (isCheck) {
const gitStatus = (
await exec(`git status --porcelain ${output}`, {
encoding: "utf-8",
})
).trim();
if (gitStatus) {
throw new Error(
`The file ${out} is not up to date. Please run \`node scripts/link-docs.mjs\` locally to update it.`,
);
}
}
};
// todo: generate me using typlite.
const maintainerMd = async () => {
const maintainers = JSON.parse(yarn(`--silent maintainers --input=action=maintainers`, "pipe"));
const features = JSON.parse(yarn(`--silent maintainers --input=action=features`, "pipe"));
const output = [];
output.push("<!-- This file is generated by scripts/link-docs.mjs. Do not edit manually. -->\n");
output.push("# Tinymist Maintainers\n\n");
output.push(
"Tinymist [ˈtaɪni mɪst] is an integrated language service for [Typst](https://typst.app/) [taɪpst].",
);
output.push(
"\nThis page is generated from [./MAINTAINERS.typ](./MAINTAINERS.typ) and renders information of [maintainers](#maintainers) and [features.](#features)\n",
);
output.push("## Maintainers\n");
const italicIt = (it) => `*${it}*`;
const featureLink = (it) => {
const feature = features.find((f) => f.name === it);
if (feature) {
return `[${it}](#${it.replace(/\s+/g, "-").toLowerCase()})`;
}
return it;
};
const fsPath = (it) => {
if (!fs.existsSync(it)) {
throw new Error(`Path ${it} does not exist!`);
}
return `[\`${it}\`](./${it})`;
};
for (const maintainer of maintainers) {
output.push(`- [**${maintainer["name"]}**](https://github.com/${maintainer["github-name"]})`);
output.push(` - Email: ${maintainer.email}`);
if (maintainer.maintains.length > 0) {
const rendered = maintainer.maintains.map(featureLink).map(italicIt);
if (rendered.length > 1) {
const last = rendered.pop();
output.push(` - Maintains: ${rendered.join(", ")}, and ${last}`);
} else {
output.push(` - Maintains: ${rendered.join(", ")}`);
}
}
output.push("");
}
output.push("## Features\n");
for (const feature of features) {
output.push(`### ${feature.name}`);
output.push(`${feature.description}`);
output.push(`- Scope: ${feature.scope.map(fsPath).join(", ")}`);
}
const outPath = resolve(root, "MAINTAINERS.md");
const outputContent = output.join("\n");
if (dry) {
console.log(content);
return;
}
await fs.promises.writeFile(outPath, outputContent);
};
const tasks = [
{
input: "docs/tinymist/introduction.typ",
output: "README.md",
},
{
input: "docs/tinymist/release-instruction.typ",
output: "docs/release-instruction.md",
},
{
input: "docs/tinymist/crates/typlite.typ",
output: "crates/typlite/README.md",
},
{
input: "docs/tinymist/frontend/emacs.typ",
output: "editors/emacs/README.md",
},
{
input: "docs/tinymist/frontend/helix.typ",
output: "editors/helix/README.md",
},
{
input: "docs/tinymist/frontend/neovim.typ",
output: "editors/neovim/README.md",
},
{
input: "docs/tinymist/frontend/sublime-text.typ",
output: "editors/sublime-text/README.md",
},
{
input: "docs/tinymist/frontend/vscode.typ",
output: "editors/vscode/README.md",
},
{
input: "docs/tinymist/frontend/zed.typ",
output: "editors/zed/README.md",
},
];
const main = async () => await Promise.all([...tasks.map(convert), maintainerMd()]);
main();