From dd69d06dc6d06293751994e5199b17bc984c59f6 Mon Sep 17 00:00:00 2001 From: Eva Sarafianou Date: Thu, 9 Jul 2026 12:32:39 +0300 Subject: [PATCH] Migrate docs site: Docusaurus config, Algolia, OpenAPI pipeline, and CI (#37402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Align Docusaurus config for monorepo, wire Algolia DocSearch (P6) Fixes projectName/editUrl/path references left over from the docs-unified repo split, adds trailingSlash for predictable CloudFront 404 handling, and wires an Algolia search block into themeConfig that's only included when credentials are present (Docusaurus's schema rejects an empty appId/apiKey, so this keeps builds green with or without them). Also fixes the sidebar/redirect generator scripts, which still pointed at the pre-rename docs/ directory instead of main/, and adds docs/Makefile, .env.local.example, and an updated README for local dev. Co-authored-by: Cursor * Wire OpenAPI generation to api/v4/source and add docs-ci.yaml (P7) Replaces build-openapi.mjs's custom YAML-merge implementation with a thin wrapper around the canonical `make -C api build` target, keeping only the MDX sanitization step (quote/autolink fixes) that docusaurus-plugin-openapi-docs needs. Adds a "prebuild" npm script so `npm run build` regenerates the spec automatically, and ignores the generated api/v4/html artifacts (narrow form, since ssr_template.hbs and static/favicon.ico under that path are committed). Also adds docs-ci.yaml as a path-scoped PR/master build+typecheck gate for the docs site, replacing the legacy `docs` repo's Sphinx-based ci.yml now that docs live in this monorepo. Co-authored-by: Cursor * Rename OpenAPI prebuild script for clarity "prebuild" is an npm lifecycle hook name (auto-runs before "npm run build"), not a descriptive name, so `npm run prebuild` didn't signal it's specifically about OpenAPI generation. Split it into "build:openapi" (the actual script, runnable directly and self-explanatory) with "prebuild" now just delegating to it, preserving the automatic pre-build trigger. Co-authored-by: Cursor * Regenerate sidebars automatically before dev/build (P7 fixup) documentation.generated.json and developers.generated.json are gitignored and nothing produced them on a fresh checkout, so both `npm start` and `npm run build` failed with MODULE_NOT_FOUND outside a working tree that happened to have stale copies lying around. Wire the sidebar generators into `prestart`/`prebuild` so they're always regenerated first. Co-authored-by: Cursor * Remove docs/site/.env.local.example There's a single Algolia DocSearch app for docs.mattermost.com; credentials aren't distributed to individual developers, so a per-dev .env.local workflow doesn't apply. Credentials are only ever injected in CI/CD via repository variables. Local builds/dev server run fine without them (the Algolia block in docusaurus.config.ts is conditional). Co-authored-by: Cursor * Wire OpenAPI doc generation into prestart/prebuild, drop unused Makefile docusaurus-plugin-openapi-docs requires a separate `docusaurus gen-api-docs` CLI step to populate docs/api/reference/ (gitignored) — nothing was invoking it, so a fresh checkout's npm start/build failed the same way the sidebar JSONs did. Split build:openapi into build:openapi:spec (slow, runs make -C api build) and build:openapi:docs (fast, generates MDX from the existing spec), and wire prestart to reuse an existing spec instead of rebuilding it every dev-server start. Also drops docs/Makefile: four of its five targets were pure passthroughs to npm scripts, unreferenced by CI or anything else, and there's no repo-wide `make -C ` convention to fit into. Note: a duplicate-doc-id build failure (operationId `status` in the Playbooks OpenAPI spec colliding with the main API's `status` tag) is being fixed separately in mattermost-plugin-playbooks. Co-authored-by: Cursor * Fix stale docs/ reference in sidebar generator's error message The existence check still hardcoded "docs/" in its error text after SRC was repointed to main/. Use the SRC constant in the message so it can't drift out of sync with the actual path again. Co-authored-by: Cursor * remove code comment * Drop unused artifact upload from docs-ci.yaml Nothing consumes it: P9's docs-cd.yml will rebuild independently on push to master rather than downloading it via workflow_run (avoids workflow_run trigger footguns for an infrequent, cheap-enough rebuild), and P10's preview build always needs its own independent build anyway (bakes a per-PR BASE_URL). This was carried over from the old docs repo's ci.yml out of habit; that repo's own PR-time uploads had the same unused-artifact issue (only cd.yml's post-merge run ever consumed it). Co-authored-by: Cursor --------- Co-authored-by: Cursor --- .github/workflows/docs-ci.yaml | 55 ++++++ .gitignore | 6 + docs/site/README.md | 129 +++++++++++--- docs/site/docusaurus.config.ts | 23 +++ docs/site/package.json | 6 + docs/site/scripts/build-openapi.mjs | 161 ++++-------------- docs/site/scripts/gen-active-redirects.mjs | 2 +- .../scripts/gen-documentation-sidebar.mjs | 6 +- 8 files changed, 231 insertions(+), 157 deletions(-) create mode 100644 .github/workflows/docs-ci.yaml diff --git a/.github/workflows/docs-ci.yaml b/.github/workflows/docs-ci.yaml new file mode 100644 index 00000000000..90f15bde428 --- /dev/null +++ b/.github/workflows/docs-ci.yaml @@ -0,0 +1,55 @@ +name: Docs CI + +on: + pull_request: + paths: + - "docs/**" + - "api/v4/source/**" + - "api/playbooks/**" + push: + branches: + - master + paths: + - "docs/**" + - "api/v4/source/**" + - "api/playbooks/**" + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-24.04 + + steps: + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Node + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version-file: docs/site/.nvmrc + cache: "npm" + cache-dependency-path: docs/site/package-lock.json + + - name: Set up Go + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + with: + go-version-file: api/server/go.mod + + - name: Install docs dependencies + working-directory: docs/site + run: npm ci + + - name: Typecheck + working-directory: docs/site + run: npm run typecheck + + - name: Build docs site (includes OpenAPI prebuild) + working-directory: docs/site + run: npm run build + env: + ALGOLIA_APP_ID: ${{ vars.ALGOLIA_APP_ID }} + ALGOLIA_SEARCH_API_KEY: ${{ vars.ALGOLIA_SEARCH_API_KEY }} diff --git a/.gitignore b/.gitignore index 8ca39077996..0a83ff20332 100644 --- a/.gitignore +++ b/.gitignore @@ -187,3 +187,9 @@ docs/site/node_modules/ docs/api/reference/ docs/pdf/build/ docs/pdf/node_modules/ +docs/site/openapi/ + +# OpenAPI make build artifacts +api/v4/html/static/mattermost-openapi-v4.yaml +api/v4/html/index.html +api/node_modules/ diff --git a/docs/site/README.md b/docs/site/README.md index 30f70658369..defd37e1300 100644 --- a/docs/site/README.md +++ b/docs/site/README.md @@ -1,38 +1,111 @@ -# Mattermost Docs Site +# Mattermost Documentation Site -Built with [Docusaurus](https://docusaurus.io/). +Docusaurus workspace for [docs.mattermost.com](https://docs.mattermost.com), +living in the [mattermost/mattermost](https://github.com/mattermost/mattermost) +monorepo at `docs/site/`. + +## Content layout + +| Directory | Route | Description | +|---|---|---| +| `docs/main/` | `/` | User and admin documentation | +| `docs/develop/` | `/developers` | Developer documentation | +| `docs/api/` | `/api` | API reference intro + generated OpenAPI pages | + +Paths are relative to the repository root. The Docusaurus site reads them +via the relative paths `../main`, `../develop`, `../api` (from `docs/site/`). + +## Prerequisites + +- Node.js ≥ 20 — use `nvm use` inside `docs/site/` to pick up `.nvmrc` +- Go and `make` (required only for the OpenAPI prebuild step — see below) +- Vale ≥ 3 (for content linting) ## Local development -```bash -# 1. Install dependencies -cd docs/site && npm ci - -# 2. Generate the OpenAPI YAML bundle (reads api/v4/source/*.yaml) -node scripts/build-openapi.mjs - -# 3. Generate the documentation and developer sidebars -# These produce sidebars/documentation.generated.json and -# sidebars/developers.generated.json, which are .gitignored and must be -# regenerated locally after adding or removing doc pages. -# TODO: move these steps into the CI/CD build pipeline so they run automatically. -node scripts/gen-documentation-sidebar.mjs -node scripts/gen-developer-sidebar.mjs - -# 4. Generate the API reference MDX + sidebar (~2 min) -npx docusaurus gen-api-docs all - -# 5. Start dev server -npm start +```shell +cd docs/site +npm ci +npm start # dev server at http://localhost:3000 ``` -## Build +### Sidebar generation -```bash -npm run build +The `documentation` and `developers` sidebars are generated from the content +directories (`sidebars/documentation.generated.json` / +`developers.generated.json`, both gitignored) by `npm run build:sidebars`. +Docusaurus imports these files directly, so **they must exist before +`docusaurus start` or `docusaurus build` runs** — on a fresh checkout there's +no other source for them. This is wired automatically via the `prestart` and +`prebuild` npm lifecycle hooks, so plain `npm start` / `npm run build` just +work. + +(`sidebars/active-redirects.json`, by contrast, *is* committed — it's +regenerated and checked in manually via `node scripts/gen-active-redirects.mjs` +when the legacy redirect map changes, not on every build.) + +The API reference section (`docs/api/reference/`, also gitignored) has the +same requirement: `docusaurus-plugin-openapi-docs` needs `docusaurus +gen-api-docs mattermost` run before it has any pages to render. `prestart` +handles this too — using the existing OpenAPI spec if present, only falling +back to the slow `make -C api build` spec rebuild if it's missing. + +### Full production build + +The production build also includes an OpenAPI prebuild step (`npm run +build:openapi`, wired to run automatically before `npm run build` via the +same `prebuild` hook) that invokes `make -C api build`. This requires Go and +takes ~2 minutes. + +```shell +cd docs/site +npm ci +npm run build # runs build:sidebars + build:openapi (via prebuild), then Docusaurus build ``` -## Notes +To skip the OpenAPI rebuild during iterative content work: -- `sidebars/documentation.generated.json` and `sidebars/developers.generated.json` are generated by the sidebar scripts and are not committed. Re-run step 3 whenever you add or remove pages under `docs/` or `develop/`. -- `scripts/migrate-*.mjs` are one-time migration scripts kept locally only; they are not committed. +```shell +cd docs/site +npm run build -- --no-minify # still runs build:sidebars + build:openapi first +``` + +If you need to bypass the prebuild step entirely (e.g., all generated +artifacts already exist and are current), run: + +```shell +cd docs/site +npm run docusaurus build # calls docusaurus directly, skips prebuild +``` + +### Algolia search + +There's a single Algolia DocSearch app for `docs.mattermost.com` — credentials +aren't distributed to individual developers. They're set as repository +variables (`vars.ALGOLIA_APP_ID`, `vars.ALGOLIA_SEARCH_API_KEY`) and injected +only in CI/CD. Local builds simply run without them: the site builds cleanly +and the search bar is omitted (see the conditional in +`docusaurus.config.ts`). + +If you need to test search locally, export the same two variables in your +shell before running `npm start`/`npm run build`. + +## Scripts + +| Command | Description | +|---|---| +| `npm start` | Dev server with hot reload (runs `build:sidebars` + `build:openapi:docs` first via `prestart`) | +| `npm run build` | Production build to `build/` (runs `build:sidebars` + `build:openapi` first via `prebuild`) | +| `npm run build:sidebars` | Regenerate the documentation + developer sidebar JSON | +| `npm run build:openapi:spec` | Regenerate the OpenAPI spec only (slow — invokes `make -C api build`) | +| `npm run build:openapi:docs` | Regenerate the API reference MDX pages from the existing spec (fast) | +| `npm run build:openapi` | Full OpenAPI pipeline: spec then docs | +| `npm run serve` | Serve the `build/` output locally | +| `npm run typecheck` | TypeScript type check | +| `node scripts/gen-active-redirects.mjs` | Regenerate legacy redirect map (committed to git; run manually when it changes) | + +## Content linting + +```shell +vale main develop api +``` diff --git a/docs/site/docusaurus.config.ts b/docs/site/docusaurus.config.ts index fb99e30ae11..c9051b72549 100644 --- a/docs/site/docusaurus.config.ts +++ b/docs/site/docusaurus.config.ts @@ -12,6 +12,25 @@ import activeRedirects from './sidebars/active-redirects.json'; // /api → API Reference (OpenAPI-generated) sources: ../api // See PLAN.md §3.1 for the IA, §3.2 for design tokens. +// Docusaurus's Algolia schema rejects an empty `appId`/`apiKey`, so the +// block is only included when both are set. Without credentials the search +// bar is simply omitted (rather than rendered as an inert element), which +// keeps local and CI builds green. +const algoliaAppId = process.env.ALGOLIA_APP_ID; +const algoliaApiKey = process.env.ALGOLIA_SEARCH_API_KEY; +const algoliaThemeConfig = + algoliaAppId && algoliaApiKey + ? { + algolia: { + appId: algoliaAppId, + apiKey: algoliaApiKey, + indexName: 'mattermost-docs', + contextualSearch: true, + searchPagePath: 'search', + }, + } + : {}; + const config: Config = { title: 'Mattermost Documentation', tagline: 'Mission in Motion', @@ -23,6 +42,7 @@ const config: Config = { url: 'https://docs.mattermost.com', baseUrl: '/', + trailingSlash: false, organizationName: 'mattermost', projectName: 'mattermost', @@ -113,6 +133,8 @@ const config: Config = { redirects: activeRedirects.redirects, }, ], + // Generates API reference pages from the OpenAPI bundle produced by + // build-openapi.mjs [ 'docusaurus-plugin-openapi-docs', { @@ -213,6 +235,7 @@ const config: Config = { ], copyright: `Copyright © ${new Date().getFullYear()} Mattermost, Inc. All rights reserved.`, }, + ...algoliaThemeConfig, prism: { theme: prismThemes.github, darkTheme: prismThemes.dracula, diff --git a/docs/site/package.json b/docs/site/package.json index 67aa4c572f0..3e810a6f11a 100644 --- a/docs/site/package.json +++ b/docs/site/package.json @@ -6,6 +6,12 @@ "docusaurus": "docusaurus", "start": "docusaurus start", "build": "docusaurus build", + "build:sidebars": "node scripts/gen-documentation-sidebar.mjs && node scripts/gen-developer-sidebar.mjs", + "build:openapi:spec": "node scripts/build-openapi.mjs", + "build:openapi:docs": "docusaurus gen-api-docs mattermost", + "build:openapi": "npm run build:openapi:spec && npm run build:openapi:docs", + "prestart": "npm run build:sidebars && ( [ -f openapi/mattermost-openapi-v4.yaml ] || npm run build:openapi:spec ) && npm run build:openapi:docs", + "prebuild": "npm run build:sidebars && npm run build:openapi", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", "clear": "docusaurus clear", diff --git a/docs/site/scripts/build-openapi.mjs b/docs/site/scripts/build-openapi.mjs index 5ebe1608b35..72dbd9348a6 100644 --- a/docs/site/scripts/build-openapi.mjs +++ b/docs/site/scripts/build-openapi.mjs @@ -1,75 +1,30 @@ #!/usr/bin/env node -/* - * Bundles the Mattermost OpenAPI fragments into a single YAML document. +/** + * Builds the merged OpenAPI spec by delegating to the canonical api/Makefile, + * then sanitizes the output for MDX compatibility. * - * Canonical source: mattermost/mattermost/api/v4/source/. The upstream - * Makefile uses naive `cat` concatenation which produces *invalid* YAML - * when fragments declare the same path key (currently - * /api/v4/sharedchannels/{channel_id}/remotes lives in both - * channels.yaml and sharedchannels.yaml). This script does a real - * YAML parse + merge with last-wins semantics so the bundle validates. + * Sanitization (description / summary / title strings): + * 1) Embedded "..." breaks docusaurus-plugin-openapi-docs frontmatter quoting. + * Replace with curly quotes (“ / ”). + * 2) Markdown autolinks like are parsed as JSX closing tags by MDX. + * Escape bare < not followed by a letter or ! to <. * - * Skips: - * - The Go-based x-codeSamples extractor (we use the plugin's - * auto-generated curl/Go/Node/Python samples for now). - * - The Playbooks merge (separate spec; integrate later if needed). - * - * Usage: node docs-site/scripts/build-openapi.mjs - * Output: docs-site/openapi/mattermost-openapi-v4.yaml + * Usage: node scripts/build-openapi.mjs (from docs/site/) + * Output: docs/site/openapi/mattermost-openapi-v4.yaml */ -import {readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync} from 'node:fs'; -import {dirname, join, resolve} from 'node:path'; +import {execSync} from 'node:child_process'; +import {readFileSync, writeFileSync, mkdirSync, existsSync} from 'node:fs'; +import {dirname, resolve} from 'node:path'; import {fileURLToPath} from 'node:url'; import {parse, stringify} from 'yaml'; -const HERE = dirname(fileURLToPath(import.meta.url)); -const SITE_ROOT = resolve(HERE, '..'); -// docs/site/ → docs/ → mattermost/ (monorepo root where api/v4/source lives) -const REPO_ROOT = resolve(SITE_ROOT, '../..'); - -const PRE_MERGE_PATH = join(REPO_ROOT, 'sources/mattermost-api-source/api/v4/source'); -const POST_MERGE_PATH = join(REPO_ROOT, 'api/v4/source'); -const SOURCE_DIR = (existsSync(POST_MERGE_PATH) && readdirSync(POST_MERGE_PATH).some((f) => f.endsWith('.yaml'))) - ? POST_MERGE_PATH - : PRE_MERGE_PATH; - -const OUT = join(SITE_ROOT, 'openapi/mattermost-openapi-v4.yaml'); - -// Order matches the upstream Makefile build-v4 target. Order is significant -// because the openapi-docs plugin renders sidebar groups in tag order, and -// tags are first-seen in the file order. -const PATH_FRAGMENTS = [ - 'users', 'status', 'teams', 'channels', 'posts', 'preferences', 'files', - 'recaps', 'ai', 'uploads', 'jobs', 'system', 'emoji', 'webhooks', 'saml', - 'compliance', 'ldap', 'groups', 'cluster', 'brand', 'commands', 'oauth', - 'elasticsearch', 'bleve', 'dataretention', 'plugins', 'roles', 'schemes', - 'service_terms', 'remoteclusters', 'sharedchannels', 'reactions', 'actions', - 'bots', 'cloud', 'usage', 'permissions', 'imports', 'exports', 'ip_filters', - 'bookmarks', 'views', 'reports', 'limits', 'logs', - 'outgoing_oauth_connections', 'metrics', 'scheduled_post', - 'custom_profile_attributes', 'audit_logging', 'access_control', - 'content_flagging', 'agents', 'properties', -]; - -function loadYaml(name) { - const file = join(SOURCE_DIR, `${name}.yaml`); - if (!existsSync(file)) { - console.warn(`[openapi] skip (missing): ${name}.yaml`); - return null; - } - return parse(readFileSync(file, 'utf8')); -} - -function mergePaths(base, fragment, fragmentName) { - if (!fragment || typeof fragment !== 'object') return; - for (const [pathKey, pathItem] of Object.entries(fragment)) { - if (base[pathKey]) { - console.warn(`[openapi] duplicate path "${pathKey}" — overwritten by ${fragmentName}.yaml`); - } - base[pathKey] = pathItem; - } -} +const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); // docs/site/scripts +const DOCS_SITE_DIR = resolve(SCRIPT_DIR, '..'); // docs/site +const MONOREPO_ROOT = resolve(SCRIPT_DIR, '../../..'); // mattermost/ +const API_ROOT = resolve(MONOREPO_ROOT, 'api'); // mattermost/api +const RAW_SPEC_PATH = resolve(API_ROOT, 'v4/html/static/mattermost-openapi-v4.yaml'); // make's own output +const SANITIZED_SPEC_PATH = resolve(DOCS_SITE_DIR, 'openapi/mattermost-openapi-v4.yaml'); // what Docusaurus reads function walkStrings(node, fn, key) { if (typeof node === 'string') return fn(node, key); @@ -84,64 +39,27 @@ function walkStrings(node, fn, key) { return node; } -function deepMerge(target, source) { - for (const [k, v] of Object.entries(source ?? {})) { - if (v && typeof v === 'object' && !Array.isArray(v) && target[k] && typeof target[k] === 'object' && !Array.isArray(target[k])) { - deepMerge(target[k], v); - } else { - target[k] = v; - } - } -} - function main() { - if (!existsSync(SOURCE_DIR)) { - console.error(`OpenAPI source not found at ${SOURCE_DIR}`); + if (!existsSync(API_ROOT)) { + console.error(`[openapi] api/ directory not found at ${API_ROOT}`); + console.error('[openapi] Ensure you are running from within the mattermost monorepo.'); process.exit(1); } - console.log(`[openapi] source: ${SOURCE_DIR}`); + console.log(`[openapi] Building OpenAPI spec via make -C ${API_ROOT} build`); + execSync(`make -C ${API_ROOT} build`, {stdio: 'inherit'}); - const intro = loadYaml('introduction'); - if (!intro) { - console.error('introduction.yaml is required as the bundle base'); + if (!existsSync(RAW_SPEC_PATH)) { + console.error(`[openapi] Expected make output not found: ${RAW_SPEC_PATH}`); process.exit(1); } - // introduction.yaml ends with `paths:` (open). After parsing it yields - // a doc whose paths key is null — initialize as empty object so we can - // merge fragments into it. - intro.paths = intro.paths ?? {}; - console.log(`[openapi] base: introduction.yaml (info, tags=${(intro.tags ?? []).length}, servers=${(intro.servers ?? []).length})`); - let endpointCount = 0; - for (const name of PATH_FRAGMENTS) { - const frag = loadYaml(name); - if (!frag) continue; - const before = Object.keys(intro.paths).length; - mergePaths(intro.paths, frag, name); - const added = Object.keys(intro.paths).length - before; - endpointCount += Object.keys(frag).length; - console.log(`[openapi] ${name.padEnd(28)} +${added.toString().padStart(3)} paths (${Object.keys(frag).length} declared, ${Object.keys(frag).length - added} duplicates)`); - } + console.log('[openapi] Sanitizing for MDX compatibility ...'); + const doc = parse(readFileSync(RAW_SPEC_PATH, 'utf8')); - const defs = loadYaml('definitions'); - if (defs) { - deepMerge(intro, defs); - console.log(`[openapi] merged definitions.yaml (components.schemas: ${Object.keys(intro.components?.schemas ?? {}).length})`); - } - - // Sanitize description text so docusaurus-plugin-openapi-docs writes - // valid MDX/YAML. - // 1) Embedded double-quotes break the plugin's `description: "..."` - // frontmatter (it discards the closing quote of `("")`). - // → replace inner `"..."` with curly quotes. - // 2) Markdown autolinks like `` break MDX (` { + let quoteFixes = 0; + let autolinkFixes = 0; + walkStrings(doc, (value, key) => { if (key !== 'description' && key !== 'summary' && key !== 'title') return value; let v = value; if (v.includes('"')) { @@ -154,21 +72,14 @@ function main() { } return v; }); - console.log(`[openapi] sanitized: quotes=${quoteFixes}, autolinks=${autolinkFixes}`); - const totalPaths = Object.keys(intro.paths).length; - const totalOperations = Object.values(intro.paths) - .flatMap((p) => Object.keys(p ?? {})) - .filter((k) => ['get', 'post', 'put', 'patch', 'delete', 'head', 'options'].includes(k)) - .length; + console.log(`[openapi] Sanitized: quotes=${quoteFixes}, autolinks=${autolinkFixes}`); - const out = stringify(intro, {lineWidth: 0}); - mkdirSync(dirname(OUT), {recursive: true}); - writeFileSync(OUT, out); + mkdirSync(dirname(SANITIZED_SPEC_PATH), {recursive: true}); + writeFileSync(SANITIZED_SPEC_PATH, stringify(doc, {lineWidth: 0})); - const sizeMb = (out.length / 1024 / 1024).toFixed(2); - console.log(`[openapi] wrote ${OUT}`); - console.log(`[openapi] ${sizeMb} MB · ${totalPaths} unique paths · ${totalOperations} operations`); + const sizeMb = (readFileSync(SANITIZED_SPEC_PATH).length / 1024 / 1024).toFixed(2); + console.log(`[openapi] Wrote ${sizeMb} MB → ${SANITIZED_SPEC_PATH}`); } main(); diff --git a/docs/site/scripts/gen-active-redirects.mjs b/docs/site/scripts/gen-active-redirects.mjs index d08ab197b92..ad051ae536c 100644 --- a/docs/site/scripts/gen-active-redirects.mjs +++ b/docs/site/scripts/gen-active-redirects.mjs @@ -21,7 +21,7 @@ import {fileURLToPath} from 'node:url'; const HERE = dirname(fileURLToPath(import.meta.url)); const SITE_ROOT = resolve(HERE, '..'); const REPO_ROOT = resolve(SITE_ROOT, '..'); -const DOCS = join(REPO_ROOT, 'docs'); +const DOCS = join(REPO_ROOT, 'main'); const SRC = join(SITE_ROOT, 'scripts', 'migrate-main-docs', 'redirects.json'); const OUT = join(SITE_ROOT, 'sidebars', 'active-redirects.json'); diff --git a/docs/site/scripts/gen-documentation-sidebar.mjs b/docs/site/scripts/gen-documentation-sidebar.mjs index 69f3d222046..8a474264374 100644 --- a/docs/site/scripts/gen-documentation-sidebar.mjs +++ b/docs/site/scripts/gen-documentation-sidebar.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node // Generate the Documentation sidebar from the migrated content tree under -// docs/. Output: docs-site/sidebars/documentation.generated.json +// main/. Output: docs-site/sidebars/documentation.generated.json // // Mirrors gen-developer-sidebar.mjs in structure. Only differences are // the source directory and the top-level section list (per PLAN.md 3.1). @@ -14,7 +14,7 @@ import {fileURLToPath} from 'node:url'; const HERE = dirname(fileURLToPath(import.meta.url)); const SITE_ROOT = resolve(HERE, '..'); const REPO_ROOT = resolve(SITE_ROOT, '..'); -const SRC = join(REPO_ROOT, 'docs'); +const SRC = join(REPO_ROOT, 'main'); const OUT = join(SITE_ROOT, 'sidebars', 'documentation.generated.json'); const TOP_LEVEL = [ @@ -528,7 +528,7 @@ function buildOverviewSidebar(autoCat) { } function main() { - if (!existsSync(SRC)) { console.error(`docs/ not found at ${SRC}`); process.exit(1); } + if (!existsSync(SRC)) { console.error(`SRC not found at ${SRC}`); process.exit(1); } const sidebar = []; for (const {dir, label} of TOP_LEVEL) {