diff options
| author | Leitwolf11 | 2026-11-05 05:56:00 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-11-05 05:56:00 +0300 |
| commit | 6f114e3df68d0b20c7e58c5ffb8c46070317008a (patch) | |
| tree | 2b282d5ba7cdee5ac453d8cfd8699ea77a824af4 /scripts/sync-docs.mjs | |
| download | tazel.net-6f114e3df68d0b20c7e58c5ffb8c46070317008a.tar.gz | |
Build the site of Tazel with Nuxt
tazel.net is the site of Tazel itself: a Nuxt 4 site generated to static
files, in en-US, de-DE, ru-RU and he-IL, light by default with a dark
theme that is kept per browser.
- Home: the release and its kind, what Tazel does, the steps from a
project file to a program, and a sample.
- Docs: Markdown through Nuxt Content, highlighted by Shiki (Kotlin,
shell, PowerShell, and Tala through the grammar of the compiler
repository), with a tree of the pages on the left, the headings of
the page on the right, and the previous and next pages below.
Installation, a first project, and releases and support are written
in every language; the reference (commands, project file, lockfile,
plugins, how Tazel works) is copied from the Documents of Tazel by
scripts/sync-docs.mjs, and a language without a page shows the
English one with a note.
- Every page has its canonical address, hreflang alternates and a
sitemap entry; generation fails on a link to a page that does not
exist.
CI checks the format, the types and the language helpers, generates
the site and runs Dependency Review on pull requests.
Diffstat (limited to 'scripts/sync-docs.mjs')
| -rw-r--r-- | scripts/sync-docs.mjs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/scripts/sync-docs.mjs b/scripts/sync-docs.mjs new file mode 100644 index 0000000..c36cbdb --- /dev/null +++ b/scripts/sync-docs.mjs @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> +// SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 + +// Copies the reference of Tazel from a checkout of Progmasoft/tazel into the English docs: +// +// node scripts/sync-docs.mjs ../tazel +// +// The title of each document becomes its front matter, links between the documents become +// links between pages of the site, and links to other files of the repository go to GitHub. + +import { readFileSync, writeFileSync, mkdirSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; + +const checkout = process.argv[2]; +if (!checkout) { + console.error("usage: node scripts/sync-docs.mjs <checkout of Progmasoft/tazel>"); + process.exit(2); +} + +const repository = "https://github.com/Progmasoft/tazel/blob/main"; +const documents = [ + { source: "CLI.md", target: "2.reference/1.commands.md", path: "/docs/reference/commands" }, + { + source: "PROJECT_FILES.md", + target: "2.reference/2.project-file.md", + path: "/docs/reference/project-file", + }, + { source: "LOCKFILE.md", target: "2.reference/3.lockfile.md", path: "/docs/reference/lockfile" }, + { source: "PLUGINS.md", target: "3.extending/1.plugins.md", path: "/docs/extending/plugins" }, + { + source: "ARCHITECTURE.md", + target: "4.internals/1.architecture.md", + path: "/docs/internals/architecture", + }, +]; +const pages = new Map(documents.map((document) => [document.source, document.path])); + +function link(target) { + const [file, anchor] = target.split("#", 2); + const suffix = anchor === undefined ? "" : `#${anchor}`; + if (file === "") return target; + const page = pages.get(file); + if (page) return `${page}${suffix}`; + if (file.startsWith("../")) return `${repository}/${file.slice(3)}${suffix}`; + return `${repository}/Documents/${file}${suffix}`; +} + +function convert(text, source) { + const lines = text.replace(/\r\n/g, "\n").split("\n"); + const spdx = lines.filter((line) => line.startsWith("<!-- SPDX-")); + const body = lines.filter((line) => !line.startsWith("<!-- SPDX-")); + const titleIndex = body.findIndex((line) => line.startsWith("# ")); + if (titleIndex < 0) throw new Error(`${source} has no title`); + const title = body[titleIndex].slice(2).replace(/`/g, ""); + body.splice(0, titleIndex + 1); + while (body[0] === "") body.shift(); + const firstParagraph = []; + for (const line of body) { + if (line === "") break; + firstParagraph.push(line); + } + const paragraph = firstParagraph + .join(" ") + .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") + .replace(/[`*]/g, "") + .replace(/"/g, "'"); + // The first sentence describes the page to search engines. + const description = paragraph.match(/^.*?\.(?=\s|$)/)?.[0] ?? paragraph; + const converted = body + .join("\n") + .replace(/\]\(((?!https?:|mailto:|#)[^)\s]+)\)/g, (_, target) => `](${link(target)})`); + return [ + "---", + `title: ${JSON.stringify(title)}`, + `description: ${JSON.stringify(description)}`, + `source: ${JSON.stringify(`${repository}/Documents/${source}`)}`, + "---", + "", + ...spdx, + "", + converted.trimEnd(), + "", + ].join("\n"); +} + +const root = resolve(import.meta.dirname, "../content/en-US/docs"); +for (const document of documents) { + const text = readFileSync(join(checkout, "Documents", document.source), "utf8"); + const target = join(root, document.target); + mkdirSync(dirname(target), { recursive: true }); + writeFileSync(target, convert(text, document.source)); + console.log(`${document.source} -> content/en-US/docs/${document.target}`); +} |