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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,15 @@ jobs:
run: cargo +stable llvm-cov --all-features --locked --fail-under-lines 90 --fail-under-functions 95 --fail-under-regions 90
- name: Build release binary
run: cargo +stable build --release --locked
- name: Validate rendered SVG
run: python3 scripts/validate-render.py
- name: Smoke test command metadata
run: |
./target/release/stack --help
./target/release/stack --version
./target/release/stack check --help
./target/release/stack fmt --help
./target/release/stack render --help
- name: Verify repository files
run: |
test -s README.md
Expand All @@ -70,6 +75,7 @@ jobs:
test -s Cargo.lock
test -s src/main.rs
test -s tests/specification-revision
test -s tests/fixtures/render.stack

msrv:
name: Minimum supported Rust
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

`stack-sh/cli` is the private source repository for the native Rust `stack` command.

The repository contains native validation and formatting commands. The CLI is not yet distributed as a supported external binary and its interface remains pre-release.
The repository contains native validation, formatting, and rendering commands. The CLI is not yet distributed as a supported external binary and its interface remains pre-release.

## Commands

Expand All @@ -11,24 +11,22 @@ stack check arch.stack
stack fmt arch.stack
stack fmt --check arch.stack
stack fmt -
stack render arch.stack
stack render arch.stack -o arch.svg
```

`stack check` reads the file as bytes and runs the full compiler, theme, layout, and routing validation pipeline without changing the source. Diagnostics are written to standard error in source order. Standard output remains empty.

`stack fmt` uses the engine formatter and preserves comments. File mode replaces changed source atomically through a temporary file in the same directory; unchanged files are not replaced. Syntax, encoding, and host I/O failures leave the original file untouched. `stack fmt -` reads bytes from standard input and writes only canonical source to standard output. `--check` never writes source and exits with status `1` when formatting is required.

`stack render` uses the same engine pipeline to produce deterministic standalone SVG. Without `-o`, standard output contains only SVG. With `-o`, the output is written atomically in the destination directory. Diagnostics remain on standard error, warnings preserve SVG, and Stack errors never create or replace output.

| Result | Exit status |
| --- | ---: |
| No error diagnostics, including warning-only input | `0` |
| One or more Stack error diagnostics, or `fmt --check` finds a difference | `1` |
| Invalid arguments, host I/O failure, or engine operational failure | `2` |

The remaining planned command is:

```text
stack render arch.stack -o arch.svg
```

The CLI will link `stack-engine` as a native Rust dependency. It owns filesystem and standard-stream behavior, process exit codes, configuration discovery, and command presentation. It must not duplicate compiler, formatter, layout, or SVG-rendering logic.

Future authenticated theme delivery may add a client for short-lived, scope-limited Stack tokens and entitlement-aware theme downloads. Credentials and downloaded paid-theme contents must never be committed to this repository.
Expand Down
29 changes: 29 additions & 0 deletions scripts/validate-render.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
from pathlib import Path
import subprocess
import xml.etree.ElementTree as ET


ROOT = Path(__file__).resolve().parent.parent
BINARY = ROOT / "target" / "release" / "stack"
FIXTURE = ROOT / "tests" / "fixtures" / "render.stack"


completed = subprocess.run(
[BINARY, "render", FIXTURE],
check=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
if completed.returncode != 0:
raise SystemExit(completed.stderr.decode("utf-8", errors="replace"))
if completed.stderr:
raise SystemExit("render smoke emitted unexpected diagnostics")

root = ET.fromstring(completed.stdout)
if root.tag != "{http://www.w3.org/2000/svg}svg":
raise SystemExit("render output is not an SVG root element")
if not root.attrib.get("viewBox"):
raise SystemExit("render output has no viewBox")

print("validated CLI standalone SVG")
Loading