diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0359223 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,54 @@ +# Contributing + +Thank you for helping improve the Stack Engine. Keep native Rust and browser WebAssembly behavior aligned, and include regression coverage for observable changes. + +## Development setup + +The workspace uses Rust 2024 with Rust 1.85 as its minimum supported version. Browser package work also requires Node.js and `wasm-bindgen`. + +```sh +rustup target add wasm32-unknown-unknown wasm32-wasip1 +npm ci +``` + +## Quality gates + +Run the checks relevant to your change, then the full repository suite before opening a pull request: + +```sh +cargo test --workspace +STACK_SPECIFICATION_DIR=../specification cargo test -p stack-formatter --features conformance --test conformance +STACK_SPECIFICATION_DIR=../specification cargo test -p stack-engine --features conformance +python3 scripts/validate-svg.py +cargo build -p stack-engine-wasm --target wasm32-unknown-unknown +npm run layout:validate +npm run build:wasm +npm test +npm run typecheck +npm run pack:check +CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime cargo test -p stack-engine --lib --target wasm32-wasip1 cross_target_numeric_fixture +cargo fmt --check +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo doc --workspace --no-deps +``` + +CI includes the repository-only conformance corpus in its 95% line, function, and region coverage gates. Packaged crate unit tests remain independent of the repository corpus. + +## Layout changes + +The versioned layout corpus covers small, medium, and dense diagrams; groups and nested groups; authored rank and order; cross-boundary edges; labels; and caller-owned provider icons. + +```sh +cargo test -p stack-engine --test layout_corpus --locked +cargo test --release -p stack-engine --test layout_corpus layout_runtime_stays_within_budget --locked -- --ignored --nocapture +cargo test --release -p stack-engine --test language_intelligence language_intelligence_runtime_stays_within_budget --locked -- --ignored --nocapture +npm run layout:gallery +``` + +Follow the [review-first snapshot policy](./layout-corpus/README.md). Set `UPDATE_STACK_SNAPSHOTS=1` or `UPDATE_STACK_LAYOUT_SNAPSHOTS=1` only when intentionally regenerating a reviewed reference, and inspect the resulting SVGs before committing them. + +## Releases + +Public Cargo and npm artifacts are immutable and must come from an exact reviewed commit. Follow [RELEASING.md](./RELEASING.md) and the [Cargo release procedure](./docs/cargo-releasing.md); do not overwrite an existing tag or package version. + +Keep changes focused, use English commit and pull request descriptions, and do not commit credentials, tokens, customer data, signing material, build output, or downloaded runtimes. diff --git a/README.md b/README.md index dfafbf2..7282810 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,95 @@ # Stack Engine -`stack-sh/engine` is the pure Rust execution engine for Stack architecture diagrams. +`stack-sh/engine` is the shared execution engine behind the [Stack CLI](https://github.com/stack-sh/cli) and [browser Playground](https://stack-diagram.com/). It formats and validates Stack source, calculates deterministic theme-aware layouts, and renders safe standalone SVGs with the same behavior in native Rust and browser WebAssembly. -The workspace provides canonical Stack source formatting, protocol-neutral language intelligence, the pure `stack-engine` operation facade, deterministic theme-aware scene layout and orthogonal edge routing, safe standalone SVG rendering, and a typed browser WebAssembly adapter. +Use this repository when embedding Stack rendering or language intelligence in an application. If you only want to create a diagram, start with the [CLI](https://github.com/stack-sh/cli#install) or [Playground](https://stack-diagram.com/). -## Workspace +## Choose an interface -- `stack-engine`: operation/output boundary, theme and provider-aware completion catalogs, semantic hover, theme and icon fallback resolution, deterministic scene layout, edge routing, validation beyond the compiler stage, and standalone SVG rendering; -- `stack-formatter`: comment-preserving canonical formatting for Stack source files (implemented); -- `stack-engine-wasm` and npm `@stack-sh/engine`: a thin browser adapter exposing the same pure operations and portable result model. +| Environment | Package | API documentation | +| --- | --- | --- | +| Rust | [`stack-engine`](https://crates.io/crates/stack-engine) | [docs.rs](https://docs.rs/stack-engine) | +| Browser JavaScript / TypeScript | [`@stack-sh/engine`](https://www.npmjs.com/package/@stack-sh/engine) | [Package guide](./packages/engine/README.md) | -The native CLI will link the Rust engine directly. Web clients will use the WASM adapter. Shared fixtures will verify that both targets produce equivalent diagnostics, formatted source, and SVG output. +Both packages provide format, check, render, completion, and hover operations over caller-owned source. The browser package exposes the same engine through WebAssembly. -## Boundaries +## Rust quick start -The engine may depend on `stack-sh/compiler` and `stack-sh/theme`. Core operations must be deterministic and must not require filesystem, environment, clock, random, or network access. +```sh +cargo add stack-engine@0.8.0 +``` -CLI filesystem behavior, process exit codes, user authentication, billing, entitlement checks, and paid-theme delivery are outside this repository. +```rust +use stack_engine::Engine; -## Development +fn main() -> Result<(), Box> { + let source = b"stack 1.0 diagram \"API\" { node api \"API\" { icon \"api\" } }"; + let output = Engine::bundled().render(source)?; -The workspace uses Rust 2024 with Rust 1.85 as its minimum supported version. Run: + if let Some(svg) = output.svg { + std::fs::write("api.svg", svg)?; + } else { + for diagnostic in output.diagnostics { + eprintln!("{}: {}", diagnostic.code, diagnostic.message); + } + } -```sh -cargo test --workspace -STACK_SPECIFICATION_DIR=../specification cargo test -p stack-formatter --features conformance --test conformance -STACK_SPECIFICATION_DIR=../specification cargo test -p stack-engine --features conformance -python3 scripts/validate-svg.py -rustup target add wasm32-unknown-unknown wasm32-wasip1 -cargo build -p stack-engine-wasm --target wasm32-unknown-unknown -wasm-bindgen --version -npm ci -npm run layout:validate -npm run build:wasm -npm test -npm run typecheck -npm run pack:check -CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime cargo test -p stack-engine --lib --target wasm32-wasip1 cross_target_numeric_fixture -cargo fmt --check -cargo clippy --workspace --all-targets --all-features -- -D warnings -cargo doc --workspace --no-deps + Ok(()) +} ``` -The versioned representative layout corpus covers small, medium, and dense diagrams plus groups, nested groups, authored rank and order constraints, cross-boundary edges, labels, and caller-owned provider icons. Run its exact geometry comparison, release-mode performance budget, and local static review gallery with: +The crate supports Rust 1.85 or newer. + +## Browser quick start ```sh -cargo test -p stack-engine --test layout_corpus --locked -cargo test --release -p stack-engine --test layout_corpus layout_runtime_stays_within_budget --locked -- --ignored --nocapture -cargo test --release -p stack-engine --test language_intelligence language_intelligence_runtime_stays_within_budget --locked -- --ignored --nocapture -npm run layout:gallery +npm install @stack-sh/engine@0.8.0 ``` -The review-first snapshot policy and corpus contract are documented in [`layout-corpus/README.md`](./layout-corpus/README.md). +```js +import init, { render } from "@stack-sh/engine"; + +await init(); -The independent text, edge, and frame quality gates run under the `conformance` feature with the repository's source corpus. CI runs these gates explicitly and includes them in its 95% line, function, and region coverage checks. Packaged crate unit tests do not require the repository-only corpus. See the [0.8.0 release notes](./docs/releases/v0.8.0.md) for the approved layout and SVG changes. +const result = render( + 'stack 1.0 diagram "API" { node api "API" { icon "api" } }', +); -`stack-formatter` is pure and accepts source bytes or UTF-8 text. Lexical and syntax errors return diagnostics without formatted output. Syntactically valid source remains formattable when semantic diagnostics exist. +if (result.svg) { + console.log(result.svg); +} else { + console.error(result.diagnostics); +} +``` -`stack-engine` exposes byte-oriented `format`, `check`, and `render` methods plus UTF-8 `completion` and `hover` methods through an engine bound to the embedded or a caller-provided validated catalog. Language-intelligence results implement schema version 1.0 from the pinned compiler and echo the caller's document version. The Engine derives completion entries from its core theme catalog and validated provider packs, while the compiler remains the single owner of grammar, context, diagnostics, hover semantics, and text edits. `ProviderPack::new` accepts a typed user-imported manifest and caller-owned SVG strings, verifies exact asset hashes and safe SVG structure, and computes a deterministic content revision before `Engine::with_provider_packs` can resolve namespaced IDs. Every normal format, check, or render output carries engine, authored language, theme catalog version, and theme catalog revision metadata. User-source failures stay in ordered portable diagnostics. Invalid provided catalogs or provider packs, invalid language-intelligence positions, and violated normalized pipeline invariants use a separate operational-error channel. Checks and renders resolve the requested theme and provider packs, validate deterministic integer geometry, and route ordered edges outside node interiors. Missing themes and icons produce source-mapped `STK6001` and `STK5001` warnings while a fallback SVG remains available. An unsatisfied authored order hint produces `STK4001` at its source-map range; a satisfied hint does not. +Initialization loads the WebAssembly module once. Operations are synchronous afterward and accept source already held by the caller; the adapter does not read files, access the DOM, or contact a network service. -The renderer emits fixed-dimension standalone SVG with embedded catalog or provider icons, local marker references, escaped authored text, accessible title and description metadata, and no script, event handler, external URL, host font measurement, or runtime I/O. Provider artwork preserves the authored node `kind`; each render returns the exact used-asset notices and writes provider ID, icon IDs, and pack revision into SVG metadata. The bundled catalog provides 30 first-party explicit icon identifiers in every core theme: `api`, `web`, `mobile`, `desktop`, `server`, `container`, `cluster`, `cloud`, `scheduler`, `webhook`, `identity`, `observability`, `gateway`, `load-balancer`, `dns`, `cdn`, `firewall`, `network`, `event`, `stream`, `search`, `analytics`, `repository`, `pipeline`, `secret`, `document`, `task`, `chat`, `email`, and `ai`. Canonical renderer and representative-layout SVG snapshots are byte-stable and parsed by `scripts/validate-svg.py`; set `UPDATE_STACK_SNAPSHOTS=1` or `UPDATE_STACK_LAYOUT_SNAPSHOTS=1` only when intentionally regenerating the corresponding reviewed references. CI also executes one exact numeric geometry fixture in both the native suite and a WASI build. +## What the engine guarantees -The npm package exports synchronous `format`, `check`, `render`, `completion`, and `hover` functions after asynchronous module initialization, with provider-aware variants for check, render, and completion. Provider-pack operations accept JSON-compatible local manifest and SVG data; they never discover a path or initiate a request. Format, check, and render accept `string | Uint8Array`; completion and hover require a UTF-8 string plus a safe-integer document version and a `{ byteOffset, line, column }` position. Results use explicit TypeScript contracts, camel-case fields, plain-text documentation, end-exclusive UTF-8 ranges, and ordered portable diagnostics. Invalid UTF-8 remains a normal `STK1001` result for byte-oriented operations. Unsupported JavaScript input types, inconsistent positions, and internal operational failures throw at the adapter boundary. Shared fixtures exercise native and WebAssembly parity for provider resolution, contextual completion, document-version echo, multilingual positions, and hover. Artifact validation audits WebAssembly imports and package contents; browser consumers retain responsibility for module loading, stale-result suppression, and every DOM, filesystem, network, or clock interaction. +- Deterministic integer layout and orthogonal routing using versioned font metrics and themes. +- Standalone SVG with embedded icons, accessible metadata, escaped authored text, and no script or external URL. +- Ordered, source-mapped diagnostics for invalid source, missing resources, and unsatisfied layout hints. +- Exact native/WebAssembly result parity over shared fixtures. +- Caller-owned provider packs that are validated in memory and never discovered, downloaded, or stored by the engine. -Public npm releases are produced from GitHub Releases after the repository checks pass. See [RELEASING.md](./RELEASING.md) for the first-release bootstrap and subsequent trusted-publishing flow. +Every result includes engine, language, theme catalog version, and catalog revision metadata. See the [npm package guide](./packages/engine/README.md) for JavaScript types and provider-pack APIs, and [docs.rs](https://docs.rs/stack-engine) for the Rust facade. + +## Workspace + +- `stack-engine`: the pure operation facade, layout, routing, language intelligence, and SVG rendering. +- `stack-formatter`: canonical comment-preserving Stack source formatting. +- `stack-engine-wasm` and `@stack-sh/engine`: the typed browser adapter. + +The engine consumes the public [Stack compiler](https://github.com/stack-sh/compiler) and [theme catalog](https://github.com/stack-sh/theme). Language syntax and normalized IR remain owned by the [Stack specification](https://github.com/stack-sh/specification). + +Filesystem behavior, process exit codes, user authentication, billing, entitlement checks, and paid-theme delivery belong to host applications and are outside this repository. ## Architecture -- [`docs/decisions/0001-build-the-formatter-from-compiler-models.md`](./docs/decisions/0001-build-the-formatter-from-compiler-models.md) -- [`docs/decisions/0002-use-a-pure-versioned-engine-facade.md`](./docs/decisions/0002-use-a-pure-versioned-engine-facade.md) -- [`docs/decisions/0003-use-integer-ranked-scene-layout.md`](./docs/decisions/0003-use-integer-ranked-scene-layout.md) -- [`docs/decisions/0004-route-orthogonal-edges-on-a-visibility-grid.md`](./docs/decisions/0004-route-orthogonal-edges-on-a-visibility-grid.md) -- [`docs/decisions/0005-serialize-safe-standalone-svg.md`](./docs/decisions/0005-serialize-safe-standalone-svg.md) -- [`docs/decisions/0006-expose-one-typed-browser-wasm-adapter.md`](./docs/decisions/0006-expose-one-typed-browser-wasm-adapter.md) -- [`docs/decisions/0007-adapt-language-intelligence-with-engine-catalogs.md`](./docs/decisions/0007-adapt-language-intelligence-with-engine-catalogs.md) -- [`docs/decisions/0008-compose-graphs-with-reserved-label-geometry.md`](./docs/decisions/0008-compose-graphs-with-reserved-label-geometry.md) -- [`docs/dependency-audit.md`](./docs/dependency-audit.md) +The design records cover the [pure engine facade](./docs/decisions/0002-use-a-pure-versioned-engine-facade.md), [deterministic layout](./docs/decisions/0003-use-integer-ranked-scene-layout.md), [orthogonal routing](./docs/decisions/0004-route-orthogonal-edges-on-a-visibility-grid.md), [safe SVG](./docs/decisions/0005-serialize-safe-standalone-svg.md), [browser adapter](./docs/decisions/0006-expose-one-typed-browser-wasm-adapter.md), [language intelligence](./docs/decisions/0007-adapt-language-intelligence-with-engine-catalogs.md), and [label-aware graph composition](./docs/decisions/0008-compose-graphs-with-reserved-label-geometry.md). + +See [CONTRIBUTING.md](./CONTRIBUTING.md) for repository setup, quality gates, the reviewed layout corpus, and release verification. ## Licensing -This repository is licensed under the [Apache License 2.0](./LICENSE). Third-party dependencies or bundled assets must be tracked in [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md) before a distributable native or WASM artifact is published. +This repository is licensed under the [Apache License 2.0](./LICENSE). Third-party dependencies and bundled assets are recorded in [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md).