Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,25 @@ jobs:
node-version: 22.14.0
cache: npm

- name: Read pinned CLI documentation contract
id: cli
run: |
node --input-type=module -e 'import { documentationContract } from "./scripts/docs-validation.config.mjs"; console.log(`revision=${documentationContract.cli.revision}`)' >> "$GITHUB_OUTPUT"

- name: Check out pinned Stack CLI
uses: actions/checkout@v7
with:
repository: stack-sh/cli
ref: ${{ steps.cli.outputs.revision }}
path: .stack-cli
persist-credentials: false

- name: Install minimum supported Rust
run: rustup toolchain install 1.85.0 --profile minimal

- name: Build pinned Stack CLI
run: cargo +1.85.0 build --manifest-path .stack-cli/Cargo.toml --locked

- name: Install dependencies
run: npm ci

Expand All @@ -36,6 +55,11 @@ jobs:
- name: Run tests
run: npm test

- name: Smoke test documentation CLI examples
env:
STACK_CLI_BIN: ${{ github.workspace }}/.stack-cli/target/debug/stack
run: npm run docs:smoke

- name: Build playground
run: npm run build

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ docs/.vitepress/cache
*.local
.wrangler
.dev.vars*
.stack-cli

# Editor directories and files
.vscode/*
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ The WebAssembly adapter and editor language assets are installed from the exact
```sh
npm run dev
npm run docs:dev
npm run docs:check
npm run docs:test
npm run format
npm run format:check
npm run lint
Expand All @@ -38,6 +40,12 @@ npm run docs:preview

Formatting and linting use Oxfmt and Oxlint. The production build compiles the React playground into `dist/`, validates the English, Japanese, Simplified Chinese, and Korean documentation sets, and builds VitePress with a `/docs/` base into `dist/docs/`.

## Documentation contract

`npm run docs:check` validates that all four locales have the same page inventory, heading structure, and canonical code blocks. It also rejects broken internal links and anchors, unsafe external links, malformed code fences, and Stack examples that fail against the exact `@stack-sh/engine` version in `package.json`. `npm run docs:test` exercises the corresponding positive and negative fixtures.

CI additionally builds the Stack CLI revision pinned in [`scripts/docs-validation.config.mjs`](./scripts/docs-validation.config.mjs) with its minimum supported Rust version, then runs `npm run docs:smoke` through `STACK_CLI_BIN`. This checks the documented version, help surface, and safe executable examples without adding Rust to normal Web builds. Intentional locale or execution differences must be declared in the same configuration with a non-empty reason; the validator rejects stale exceptions.

## Brand mark

[`public/favicon.svg`](./public/favicon.svg) is the canonical Stack logo mark for Web surfaces. The Playground uses it as its favicon and header mark; VitePress uses the identical [`docs/public/favicon.svg`](./docs/public/favicon.svg) copy for its favicon, navigation, and localized home pages. The documentation validator rejects the build if the two public-root copies differ.
Expand Down
43 changes: 9 additions & 34 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { defineConfig } from "vitepress"
import type { LanguageRegistration } from "@shikijs/core"
import type { DefaultTheme } from "vitepress"

import { documentationContract } from "../../scripts/docs-validation.config.mjs"

const require = createRequire(import.meta.url)
const stackGrammar = require("@stack-sh/language/grammar") as LanguageRegistration
const siteOrigin = "https://stack-diagram.com"
Expand Down Expand Up @@ -92,40 +94,13 @@ type Labels = {
}

function sidebar(prefix: string, labels: Labels): DefaultTheme.SidebarItem[] {
return [
{
text: labels.guide,
items: [
{ text: labels.introduction, link: `${prefix}/guide/what-is-stack` },
{ text: labels.gettingStarted, link: `${prefix}/guide/getting-started` },
{ text: labels.playground, link: `${prefix}/guide/playground` },
{ text: labels.providerIcons, link: `${prefix}/guide/provider-icons` },
],
},
{
text: labels.language,
items: [
{ text: labels.syntax, link: `${prefix}/language/syntax` },
{ text: labels.nodesAndGroups, link: `${prefix}/language/nodes-and-groups` },
{ text: labels.edgesAndLayout, link: `${prefix}/language/edges-and-layout` },
{ text: labels.themesAndIcons, link: `${prefix}/language/themes-and-icons` },
{ text: labels.formatting, link: `${prefix}/language/formatting` },
],
},
{
text: labels.reference,
items: [
{
text: labels.diagnosticsAndLimits,
link: `${prefix}/reference/diagnostics-and-limits`,
},
{
text: labels.versioningAndSafety,
link: `${prefix}/reference/versioning-and-safety`,
},
],
},
]
return documentationContract.navigation.map((section) => ({
text: labels[section.label as keyof Labels],
items: section.items.map((item) => ({
text: labels[item.label as keyof Labels],
link: `${prefix}/${item.page.replace(/\.md$/, "")}`,
})),
}))
}

function localeTheme(prefix: string, labels: Labels): DefaultTheme.Config {
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
"cloudflare:check": "wrangler deploy --dry-run",
"deploy": "npm run build && wrangler deploy",
"dev": "vite",
"docs:build": "node scripts/validate-docs.mjs && vitepress build docs && node scripts/validate-docs-output.mjs",
"docs:build": "npm run docs:check && vitepress build docs && node scripts/validate-docs-output.mjs",
"docs:check": "node scripts/validate-docs.mjs && node scripts/validate-docs-examples.mjs",
"docs:smoke": "node scripts/validate-docs-cli.mjs",
"docs:test": "node --test scripts/*.test.mjs",
"docs:dev": "vitepress dev docs",
"docs:preview": "vitepress preview docs",
"format": "oxfmt --write .",
"format:check": "oxfmt --check .",
"lint": "oxlint --deny-warnings .",
"preview": "vite preview",
"test": "vitest run",
"test": "vitest run && npm run docs:test",
"test:watch": "vitest"
},
"dependencies": {
Expand Down
Loading