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
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@ jobs:
set -euo pipefail
node scripts/pin-workspace-deps.mjs
tag="${{ inputs.npm_tag || 'latest' }}"
for pkg in core cli wire-lang; do
for pkg in core cli browser markdown wire-lang; do
( cd "packages/$pkg" && npm publish --provenance --access public --tag "$tag" )
done
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to Wire Lang will be documented in this file.

## Unreleased

- Added `@wire-lang/browser` for asynchronous rendering after HTML loads, with
source preservation, repeatable discovery, and per-block errors.
- Added `@wire-lang/markdown` with remark, rehype, and MDX plugins that preserve
`wire` fences by default and render inline SVG with `{ mode: "static" }`.

## 0.3.1

- Fixed dense connections between facing IC pin banks so each net uses a clear,
Expand Down
44 changes: 39 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,38 @@ import { renderSvg } from "wire-lang";
const svg = renderSvg(source);
```

Write the same source inside a Markdown or MDX fence:

````markdown
```wire
schematic
component R1 Resistor value=220ohm
component D1 LED color=red
connect R1.1, D1.A
```
````

```bash
npm install @wire-lang/browser
```

Initialize the renderer in your site's browser entry point:

```js
import wire from "@wire-lang/browser";

const { errors } = await wire.initialize();
for (const { error } of errors) console.error(error);
```

The default workflow renders diagrams asynchronously after HTML is ready.
Your Markdown processor must preserve `pre > code.language-wire` blocks. See
the [browser guide](./packages/browser) for setup and client navigation.

For ahead-of-time rendering with no browser runtime, use `remarkWire` or
`rehypeWire` from `@wire-lang/markdown` with `{ mode: "static" }`. See the
[Markdown/MDX guide](./packages/markdown) for complete build configuration.

## How it compares

Think **[Mermaid Charts](https://github.com/mermaid-js/mermaid), but for electronic schematics**: text goes in, documentation-
Expand Down Expand Up @@ -171,11 +203,13 @@ symbol art; it does not claim formal IEC/IEEE compliance. See

### Packages & development

| Package | Role |
| ------------------------------------ | ---------------------------------------------------------- |
| [`wire-lang`](./packages/wire-lang) | User-facing aggregate package and the `wire` binary |
| [`@wire-lang/core`](./packages/core) | Parser, compiler, schematic model, layout engine, renderer |
| [`@wire-lang/cli`](./packages/cli) | `wire check`, `wire render`, `wire watch` |
| Package | Role |
| -------------------------------------------- | ----------------------------------------------------------- |
| [`wire-lang`](./packages/wire-lang) | User-facing aggregate package and the `wire` binary |
| [`@wire-lang/core`](./packages/core) | Parser, compiler, schematic model, layout engine, renderer |
| [`@wire-lang/cli`](./packages/cli) | `wire check`, `wire render`, `wire watch` |
| [`@wire-lang/browser`](./packages/browser) | Asynchronous rendering after HTML loads |
| [`@wire-lang/markdown`](./packages/markdown) | Markdown and MDX integration with optional static rendering |

```bash
pnpm install
Expand Down
14 changes: 11 additions & 3 deletions docs/CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ The public happy-path API that turns a **Source Document** or **Schematic Model*
_Avoid_: CLI command, simulation API

**DOM Auto Render**:
A post-MVP browser integration that finds Wire Lang source blocks in the DOM and replaces or augments them with rendered schematics.
The `@wire-lang/browser` integration that asynchronously finds source blocks after HTML loads, hides successfully rendered source, and inserts sibling SVG containers. This is the default documentation workflow.
_Avoid_: MVP command-line rendering, manual API usage

**DOM Source Block**:
Expand Down Expand Up @@ -420,6 +420,12 @@ _Avoid_: ASCII-only source
A fenced code block tagged as `wire` for documentation systems that integrate Wire Lang.
_Avoid_: DOM source block, wire file

**Markdown Integration**:
The `@wire-lang/markdown` plugins that preserve a **Markdown Fence** for
**DOM Auto Render** by default. Explicit static mode replaces it with inline SVG
ahead of time through remark, rehype, or MDX.
_Avoid_: raw HTML passthrough, Mermaid plugin

**VS Code Extension**:
A future editor integration for Wire Lang syntax highlighting, diagnostics, and authoring feedback.
_Avoid_: MVP core library, SVG renderer
Expand Down Expand Up @@ -819,7 +825,7 @@ Terminals are user-defined through recommended `pins: ic-pin-list` written as `p
> **Domain expert:** "No. The **Developer CLI** should show **Human Diagnostic Output** by default and provide **Machine Diagnostic Output** with JSON for agents and scripts."
>
> **Dev:** "How does browser auto-render find Wire Lang diagrams?"
> **Domain expert:** "After the MVP, **DOM Auto Render** should find **DOM Source Blocks** matching `pre.wire-lang` and `code.wire-lang`."
> **Domain expert:** "**DOM Auto Render** finds **DOM Source Blocks** matching `pre > code.language-wire`, `pre.wire-lang`, and `code.wire-lang`."
>
> **Dev:** "Should auto-render destroy the original source block?"
> **Domain expert:** "No. It should preserve the **DOM Source Block** and insert a separate **DOM Render Container** for the SVG."
Expand Down Expand Up @@ -880,7 +886,9 @@ Terminals are user-defined through recommended `pins: ic-pin-list` written as `p
- Standard symbols use an IEC-style **Symbol Style Profile** where practical, but the project does not claim formal standards compliance in the MVP.
- The default file extension for a **Wire File** is `.wire`.
- **Wire Files** are UTF-8; Unicode is allowed in values, labels, and annotations.
- The recommended **Markdown Fence** tag is `wire`, but direct Markdown integration is outside the core MVP.
- The recommended **Markdown Fence** tag is `wire`. Direct integration is
outside the core MVP. **DOM Auto Render** is the default; the
`@wire-lang/markdown` **Markdown Integration** package also offers static rendering.
- Syntax highlighting and editor extensions are outside the MVP; a **Headless Language Server** and **VS Code Extension** are high-priority post-MVP follow-ups.
- A **Wire File** contains exactly one **Source Document** in the MVP.
- The MVP supports `//` **Line Comments** and does not need block comments.
Expand Down
66 changes: 53 additions & 13 deletions docs/MVP.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ The main product reference is Mermaid: a text-first documentation workflow where
- No polished end-user CLI beyond minimal check, render, and watch commands.
- No preview server command in the MVP.
- No browser auto-render in the MVP.
- No headless language server, Markdown processor, or VS Code extension in the MVP.
- No headless language server, Markdown processor, or VS Code extension in the
MVP. Markdown integration is provided separately as a post-MVP package.
- No formal IEC 60617, IEEE 315, or other standards compliance claim.

## Source Format
Expand Down Expand Up @@ -362,9 +363,14 @@ Initial MVP packages:
- `@wire-lang/core`: parser, validators, compiler, schematic model, layout model, and SVG renderer
- `@wire-lang/cli`: `wire check`, `wire render`, and `wire watch`

Implemented post-MVP packages:

- `@wire-lang/browser`: asynchronous DOM discovery and rendering after HTML loads
- `@wire-lang/markdown`: remark, rehype, and MDX plugins that preserve `wire`
fences by default and render SVG ahead of time with `{ mode: "static" }`

Post-MVP packages:

- `@wire-lang/browser`
- `@wire-lang/language-server`
- editor integrations such as a VS Code extension

Expand Down Expand Up @@ -609,19 +615,54 @@ Standard symbols use an IEC-style visual profile where practical. Wire Lang does

## Post-MVP Browser Auto Render

Browser auto-render is outside the MVP. The planned post-MVP browser integration finds source blocks by default:
`@wire-lang/browser` implements the default documentation workflow after HTML
is ready. It exports asynchronous `initialize()`, `run()`, and `render(source)`
functions and a default object containing those functions. Imports have no DOM
side effects. `initialize()` defaults to `startOnLoad: true`, waits for
`DOMContentLoaded` when necessary, and runs once. `startOnLoad: false` leaves
rendering to explicit `run()` calls.

Default discovery matches:

```css
pre.wire-lang, code.wire-lang
pre > code.language-wire, pre.wire-lang, code.wire-lang
```

`run()` should preserve the original source block and insert a separate rendered container. It should be idempotent by default:

```ts
await run()
await run() // does not duplicate output
await run({ force: true }) // may re-render explicitly
```
`run({ root?, selector?, force? })` reads source as text, hides successfully
rendered source blocks, and inserts a sibling `div.wire-lang-diagram` with SVG.
It preserves the original source. Repeated and concurrent calls do not duplicate
output. Changed source or `force: true` triggers rendering again. A supplied root
is included if it matches. Discovery does not cross shadow roots automatically.

Calls resolve to `{ rendered, errors }`; errors retain the source element and
original exception. Invalid blocks remain available as source with a
`data-wire-error` attribute, while other diagrams continue. Failed rerenders
remove stale SVG and restore the source's previous hidden state. Invalid
selectors or missing DOM context reject the call. Applications decide how to
present returned errors and call `run()` after navigation or DOM updates. MDX
applications must run after hydration to avoid competing with the framework.

`render(source)` asynchronously returns the same SVG string as core's
`renderSvg(source)`. Work yields to the event loop before each diagram, but
compilation and layout of an individual diagram remain on the main thread.
The standalone browser ESM bundle includes core and needs no import map.

## Post-MVP Markdown and MDX Integration

`@wire-lang/markdown` provides `remarkWire` and `rehypeWire`, accepting
`{ mode?: "browser" | "static" }`. Browser mode is the default and preserves
source nodes for the browser runtime. Standard Markdown HTML already contains
`pre > code.language-wire`, so that workflow needs no Wire Markdown plugin.

Static mode renders source with core and replaces the fence with structured
inline SVG nodes. It requires no Wire JavaScript in the generated page and works
in builds or server requests. Static `rehypeWire` also works as an MDX plugin.
Fatal diagnostics fail static processing and map back into the Markdown VFile.
Range endpoints account for the prefix removed from each original content line.
If VFile text is missing or no longer matches, columns fall back to the opening
fence indentation. Browser diagnostics are relative to the source block instead.

See [ADR 0020](./adr/0020-browser-default-static-opt-in.md) for the default change.

## Post-MVP Roadmap

Expand All @@ -631,10 +672,8 @@ High-priority follow-ups:
`anchor`, and `side` for components and groups, plus group-aware layout (today
these emit `render.not-yet-honored` / `group.not-yet-honored` warnings).
Per-component `orientation` is now honored.
- browser auto-render for `pre.wire-lang` and `code.wire-lang`
- headless language server using a Langium grammar and the existing validators
- VS Code extension with syntax highlighting, diagnostics, and authoring feedback
- Markdown/MDX integrations using the `wire` fenced code tag
- custom component libraries passed through the JavaScript API

Later extensions:
Expand Down Expand Up @@ -667,3 +706,4 @@ Later extensions:
- [ADR 0015](./adr/0015-no-preview-server-in-mvp.md) records the MVP preview decision.
- [ADR 0016](./adr/0016-browser-auto-render-post-mvp.md) records the browser auto-render scope decision.
- [ADR 0017](./adr/0017-esm-only-node-20.md) records the runtime and module-format decision.
- [ADR 0019](./adr/0019-build-time-markdown-integration.md) records the original static Markdown integration, superseded in part by ADR 0020.
4 changes: 4 additions & 0 deletions docs/adr/0016-browser-auto-render-post-mvp.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Browser Auto Render Post-MVP

Wire Lang's MVP will not ship browser auto-render or `@wire-lang/browser`; the first release focuses on the core library and developer CLI feedback loop. We chose this over including Mermaid-style `run()` immediately because the initial user workflow is coding-agent driven: write `.wire`, run `wire check`, run `wire render`, and inspect the SVG file; browser auto-render remains a high-priority post-MVP integration once the language, diagnostics, layout, and renderer stabilize.

The post-MVP integration is now implemented. See
[ADR 0020](./0020-browser-default-static-opt-in.md) for the browser default and
static rendering alternative.
50 changes: 50 additions & 0 deletions docs/adr/0019-build-time-markdown-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# ADR 0019: Build-time Markdown integration with structured inline SVG

## Status

Superseded in part by [ADR 0020](./0020-browser-default-static-opt-in.md).
Structured SVG and static diagnostic mapping are retained; browser rendering
is now the default and static mode is explicit.

## Context

Wire Lang's Mermaid-style documentation workflow needs fenced code blocks tagged
`wire` to render inside Markdown and MDX. The integration could render in the
browser at page load, during each server request, or while the document is
built. It also needs to compose with both sides of the unified ecosystem:
remark's Markdown AST and rehype's HTML AST.

Emitting generated SVG as raw HTML would require downstream processors to opt
into dangerous/raw HTML handling and would make plugin ordering and sanitizing
harder to reason about.

## Decision

Publish `@wire-lang/markdown` with two build-time plugins:

- `remarkWire` replaces Markdown `code` nodes whose language is exactly `wire`.
- `rehypeWire` replaces standard `pre > code.language-wire` HAST blocks and is
the direct MDX integration.

Both render with `@wire-lang/core`, parse the renderer-owned SVG into structured
HAST, and insert the `<svg>` element in place of the source block. Fatal Wire
diagnostics fail the document build as VFile messages mapped to the fence's
location in the containing document.

Build time is the documented default because it ships no compiler JavaScript to
the browser and catches invalid diagrams before deployment. Request-time server
processing may use the same plugins. Browser auto-render remains a separate
future `@wire-lang/browser` concern; applications that need it immediately can
call `renderSvg` and manage DOM insertion themselves.

## Consequences

- Markdown, rehype, and MDX users share one package and one `wire` fence
convention.
- Generated SVG is visible to later HAST plugins without enabling arbitrary raw
HTML.
- Sanitizers can run before `rehypeWire`; a sanitizer after `remarkWire` needs an
SVG-aware schema.
- Rendering is synchronous and adds Wire compilation work to document builds or
server requests.
- Client-side updates are not automatic and remain outside this package.
43 changes: 43 additions & 0 deletions docs/adr/0020-browser-default-static-opt-in.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# ADR 0020: Browser rendering by default with static rendering opt-in

## Status

Accepted. Supersedes the build-time default in ADR 0019 and implements the
post-MVP browser scope from ADR 0016.

## Context

Authors want to place `wire` fences in Markdown and have a site render them
after HTML loads, following Mermaid's browser integration style. Static output
remains useful for pages that need diagrams without client JavaScript.

## Decision

Provide `@wire-lang/browser` with asynchronous `initialize`, `run`, and `render`
APIs. Initialization waits for HTML readiness and discovers standard Markdown
code blocks plus explicit `wire-lang` blocks. Preserve source in hidden elements
and insert separate rendered containers. Serialize discovery calls so overlapping
initialization and manual calls cannot duplicate output. Report individual block
errors without stopping the remaining diagrams.

Keep core's synchronous, DOM-independent renderer. The browser wrapper yields
before rendering each diagram and bundles core into standalone ESM. This makes
script-tag imports possible without a bundler, but does not move layout work
into a worker. Imports do not initialize automatically.

Markdown plugins default to browser mode and preserve source nodes. Users opt
into ahead-of-time SVG with `{ mode: "static" }`. Retain structured SVG insertion
and original Markdown diagnostic mapping for that static path.

## Consequences

- Browser mode requires site initialization and downloads the renderer. Without
JavaScript, source blocks remain visible.
- Ordinary Markdown processors need no Wire plugin when they retain standard
`language-wire` blocks. Plugin configuration alone never injects a script.
- Applications call `run()` after navigation or content updates, and after
framework hydration. Mutation observation and framework lifecycle adapters
are not included.
- Static mode adds compilation work during the build and needs no client runtime.
- Source errors surface during browser rendering by default, or during the build
in static mode. The underlying SVG drawing is identical in both modes.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"docs:format": "prettier --write \".github/**/*.yml\" \".github/*.md\" \"README.md\" \"CHANGELOG.md\" \"docs/EXAMPLES.md\" \"docs/brand/README.md\" \"packages/*/README.md\"",
"skill:check": "skills add ./skills/wire-lang --list",
"skill:publish": "skills add eduardozf/wire-lang --skill wire-lang --agent codex --global --copy --yes",
"pack:dry-run": "pnpm --filter @wire-lang/core pack --dry-run && pnpm --filter @wire-lang/cli pack --dry-run && pnpm --filter wire-lang pack --dry-run",
"pack:dry-run": "pnpm --filter @wire-lang/core pack --dry-run && pnpm --filter @wire-lang/cli pack --dry-run && pnpm --filter @wire-lang/browser pack --dry-run && pnpm --filter @wire-lang/markdown pack --dry-run && pnpm --filter wire-lang pack --dry-run",
"package:smoke": "node scripts/package-smoke-test.mjs",
"release:check": "pnpm lint && pnpm docs:check && pnpm typecheck && pnpm test && pnpm build && pnpm audit --prod && pnpm pack:dry-run && pnpm package:smoke",
"examples:update": "node scripts/update-examples.mjs",
Expand Down
21 changes: 21 additions & 0 deletions packages/browser/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Ferraz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading