aboutsummaryrefslogtreecommitdiff
path: root/website/scripts/prepare-docs.mjs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-08-03 01:21:30 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-08-03 01:21:30 +0300
commit0e434881b3f8da1db58dba8d103ddc234ad17238 (patch)
treea25d6e4655710d2e0b4d5c3fb3ca72570e5403a7 /website/scripts/prepare-docs.mjs
parent0a800b8f2e9894433c6ef9d106d10766ac408218 (diff)
fix(docs): publish only released documentation
Diffstat (limited to 'website/scripts/prepare-docs.mjs')
-rw-r--r--website/scripts/prepare-docs.mjs161
1 files changed, 125 insertions, 36 deletions
diff --git a/website/scripts/prepare-docs.mjs b/website/scripts/prepare-docs.mjs
index 6b5c4b5f..a96e2c41 100644
--- a/website/scripts/prepare-docs.mjs
+++ b/website/scripts/prepare-docs.mjs
@@ -4,18 +4,20 @@ import { fileURLToPath } from 'node:url';
import process from 'node:process';
const websiteDir = dirname(fileURLToPath(import.meta.url));
-const repoRoot = resolve(websiteDir, '../..');
+const repoRoot = process.env.HERDR_DOCS_REPO_ROOT
+ ? resolve(process.env.HERDR_DOCS_REPO_ROOT)
+ : resolve(websiteDir, '../..');
const publicDir = resolve(repoRoot, 'website/public');
const stableDocsDir = resolve(repoRoot, 'website/src/content/docs');
-const previewDocsSourceDir = resolve(repoRoot, 'docs/next/website/src/content/docs');
const previewDocsDir = resolve(stableDocsDir, 'preview');
const generatedVersionsDocsDir = resolve(stableDocsDir, '_versions');
const versionsDir = resolve(repoRoot, 'docs/versions');
const versionsManifestPath = resolve(versionsDir, 'manifest.json');
+const previewManifestPath = resolve(repoRoot, 'website/preview.json');
const generatedVersionsDataPath = resolve(repoRoot, 'website/src/data/docs-versions.json');
-const previewConfigReferenceSource = resolve(
+const stableConfigReferenceDestination = resolve(
repoRoot,
- 'docs/next/website/src/data/config-reference.json',
+ 'website/src/data/config-reference.json',
);
const previewConfigReferenceDestination = resolve(
repoRoot,
@@ -29,7 +31,12 @@ const generatedVersionReferencesPath = resolve(
if (process.argv[2] === '--rewrite-preview-doc-fixture') {
const chunks = [];
for await (const chunk of process.stdin) chunks.push(chunk);
- process.stdout.write(rewritePreviewDocContent(Buffer.concat(chunks).toString('utf8')));
+ process.stdout.write(
+ rewritePreviewDocContent(Buffer.concat(chunks).toString('utf8'), '', {
+ buildId: '2026-07-29-44b3adb12552',
+ commit: '44b3adb125524ea9a55739eee3776f922f2115ad',
+ }),
+ );
} else if (process.argv[2] === '--rewrite-version-doc-fixture') {
const chunks = [];
for await (const chunk of process.stdin) chunks.push(chunk);
@@ -42,8 +49,13 @@ if (process.argv[2] === '--rewrite-preview-doc-fixture') {
}),
);
} else {
- await preparePublicAssets();
- await prepareDocs();
+ const supported = new Set(['--docs-only', '--draft']);
+ const unsupported = process.argv.slice(2).filter((argument) => !supported.has(argument));
+ if (unsupported.length > 0) {
+ throw new Error('usage: node website/scripts/prepare-docs.mjs [--docs-only] [--draft]');
+ }
+ if (!process.argv.includes('--docs-only')) await preparePublicAssets();
+ await prepareDocs({ draft: process.argv.includes('--draft') });
}
async function preparePublicAssets() {
@@ -75,22 +87,69 @@ async function preparePublicAssets() {
}
}
-async function prepareDocs() {
- await rm(previewDocsDir, { recursive: true, force: true });
- await rm(generatedVersionsDocsDir, { recursive: true, force: true });
+async function prepareDocs({ draft }) {
+ const manifest = JSON.parse(await readFile(versionsManifestPath, 'utf8'));
+ if (
+ manifest.schema_version !== 1 ||
+ typeof manifest.current !== 'string' ||
+ !['legacy', 'snapshot'].includes(manifest.stable_source ?? 'legacy')
+ ) {
+ throw new Error(`${versionsManifestPath} has an unsupported schema`);
+ }
+ const currentEntry = manifest.versions.find((entry) => entry.version === manifest.current);
+ if (!currentEntry) throw new Error(`current docs version ${manifest.current} has no snapshot`);
- await copyPreparedDocs(previewDocsSourceDir, previewDocsDir, (content, relativePath) =>
- rewritePreviewDocContent(content, relativePath),
+ const previewManifest = JSON.parse(await readFile(previewManifestPath, 'utf8'));
+ if (!/^[0-9a-f]{40}$/.test(previewManifest.commit ?? '')) {
+ throw new Error(`${previewManifestPath} must contain a full preview commit SHA`);
+ }
+ const previewWebsiteRoot = resolve(repoRoot, draft ? 'docs/next/website' : 'docs/preview/website');
+ const previewDocsSourceDir = resolve(previewWebsiteRoot, 'src/content/docs');
+ const previewConfigReferenceSource = resolve(
+ previewWebsiteRoot,
+ 'src/data/config-reference.json',
);
- await cp(previewConfigReferenceSource, previewConfigReferenceDestination);
- const manifest = JSON.parse(await readFile(versionsManifestPath, 'utf8'));
- if (manifest.schema_version !== 1 || typeof manifest.current !== 'string') {
- throw new Error(`${versionsManifestPath} has an unsupported schema`);
+ if ((manifest.stable_source ?? 'legacy') === 'snapshot') {
+ await rm(stableDocsDir, { recursive: true, force: true });
+ const currentSnapshotRoot = resolve(versionsDir, manifest.current, 'website');
+ await copyPreparedDocs(
+ resolve(currentSnapshotRoot, 'src/content/docs'),
+ stableDocsDir,
+ (content, relativePath) =>
+ rewriteStableDocContent(content, {
+ tag: currentEntry.tag,
+ sourceRoot: currentEntry.source,
+ relativePath,
+ }),
+ );
+ const currentReference = resolve(currentSnapshotRoot, 'src/data/config-reference.json');
+ try {
+ await cp(currentReference, stableConfigReferenceDestination);
+ } catch (error) {
+ if (error.code !== 'ENOENT') throw error;
+ await rm(stableConfigReferenceDestination, { force: true });
+ }
+ } else {
+ await rm(previewDocsDir, { recursive: true, force: true });
+ await rm(generatedVersionsDocsDir, { recursive: true, force: true });
}
+ await copyPreparedDocs(previewDocsSourceDir, previewDocsDir, (content, relativePath) =>
+ rewritePreviewDocContent(content, relativePath, {
+ buildId: draft ? 'draft' : previewManifest.build_id,
+ commit: draft ? 'master' : previewManifest.commit,
+ }),
+ );
+ await cp(previewConfigReferenceSource, previewConfigReferenceDestination);
+
const scopes = {
- stable: await collectDocsScope(stableDocsDir, new Set(['preview', '_versions'])),
+ stable: await collectDocsScope(
+ (manifest.stable_source ?? 'legacy') === 'snapshot'
+ ? resolve(versionsDir, manifest.current, 'website/src/content/docs')
+ : stableDocsDir,
+ new Set(['preview', '_versions']),
+ ),
preview: await collectDocsScope(previewDocsSourceDir),
};
const configReferences = {};
@@ -123,7 +182,14 @@ async function prepareDocs() {
await writeFile(
generatedVersionsDataPath,
- `${JSON.stringify({ ...manifest, scopes }, null, 2)}\n`,
+ `${JSON.stringify({
+ ...manifest,
+ preview: {
+ build_id: draft ? 'draft' : previewManifest.build_id,
+ commit: draft ? 'master' : previewManifest.commit,
+ },
+ scopes,
+ }, null, 2)}\n`,
'utf8',
);
await writeFile(
@@ -183,34 +249,56 @@ async function collectDocsScope(sourceDir, excludedDirectories = new Set()) {
return { locales };
}
-export function rewritePreviewDocContent(content, relativePath = '') {
- const rewritten = rewriteRelativeDocPaths(
+export function rewritePreviewDocContent(
+ content,
+ relativePath = '',
+ { buildId, commit } = {
+ buildId: 'preview',
+ commit: 'master',
+ },
+) {
+ const taggedContent = rewriteRepositoryLinks(
content.replaceAll('/docs/', '/docs/preview/'),
- 1,
+ commit,
);
- const withEditLink = setGeneratedEditUrl(
+ const rewritten = rewriteRelativeDocPaths(taggedContent, 1);
+ const withSourceLink = setGeneratedEditUrl(
rewritten,
- `https://github.com/herdrdev/herdr/edit/master/docs/next/website/src/content/docs/${relativePath}`,
+ `https://github.com/herdrdev/herdr/blob/${commit}/docs/next/website/src/content/docs/${relativePath}`,
+ );
+ return insertPreviewNotice(withSourceLink, relativePath, { buildId, commit });
+}
+
+export function rewriteStableDocContent(content, { tag, sourceRoot, relativePath }) {
+ const taggedContent = rewriteRepositoryLinks(content, tag);
+ return setGeneratedEditUrl(
+ taggedContent,
+ `https://github.com/herdrdev/herdr/blob/${tag}/${sourceRoot}/${relativePath}`,
);
- return insertPreviewNotice(withEditLink, relativePath);
}
export function rewriteVersionDocContent(content, { version, tag, sourceRoot, relativePath }) {
- const taggedContent = content
- .replaceAll('/docs/', `/docs/${version}/`)
+ const taggedContent = rewriteRepositoryLinks(
+ content.replaceAll('/docs/', `/docs/${version}/`),
+ tag,
+ );
+ const rewritten = rewriteRelativeDocPaths(taggedContent, 2);
+ return setGeneratedEditUrl(
+ rewritten,
+ `https://github.com/herdrdev/herdr/blob/${tag}/${sourceRoot}/${relativePath}`,
+ );
+}
+
+function rewriteRepositoryLinks(content, ref) {
+ return content
.replaceAll(
'https://github.com/herdrdev/herdr/blob/master/',
- `https://github.com/herdrdev/herdr/blob/${tag}/`,
+ `https://github.com/herdrdev/herdr/blob/${ref}/`,
)
.replaceAll(
'https://raw.githubusercontent.com/herdrdev/herdr/master/',
- `https://raw.githubusercontent.com/herdrdev/herdr/${tag}/`,
+ `https://raw.githubusercontent.com/herdrdev/herdr/${ref}/`,
);
- const rewritten = rewriteRelativeDocPaths(taggedContent, 2);
- return setGeneratedEditUrl(
- rewritten,
- `https://github.com/herdrdev/herdr/blob/${tag}/${sourceRoot}/${relativePath}`,
- );
}
function rewriteRelativeDocPaths(content, extraDepth) {
@@ -225,15 +313,16 @@ function setGeneratedEditUrl(content, editUrl) {
return content.replace(/^---\n/, `---\neditUrl: ${editUrl}\n`);
}
-function insertPreviewNotice(content, relativePath) {
+function insertPreviewNotice(content, relativePath, { buildId, commit }) {
+ const source = commit === 'master' ? '`master` draft' : `[${commit.slice(0, 12)}](https://github.com/herdrdev/herdr/commit/${commit})`;
const notice = [
- '> Next docs describe unreleased work from `master`. Stable docs remain at [/docs/](/docs/).',
+ `> Preview build \`${buildId}\`, published from ${source}. Stable docs remain at [/docs/](/docs/).`,
'',
'',
].join('\n');
const indexPrefix =
relativePath === 'index.mdx'
- ? content.replace('title: Herdr documentation', 'title: Herdr next documentation')
+ ? content.replace('title: Herdr documentation', 'title: Herdr preview documentation')
: content;
const frontmatter = indexPrefix.match(/^---\n[\s\S]*?\n---\n/);
if (!frontmatter) {