Skip to content

Split into a Cargo workspace and add a WebAssembly binding - #61

Draft
ncoop57 wants to merge 3 commits into
mainfrom
subcrates
Draft

Split into a Cargo workspace and add a WebAssembly binding#61
ncoop57 wants to merge 3 commits into
mainfrom
subcrates

Conversation

@ncoop57

@ncoop57 ncoop57 commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Draft until Nathan has reviewed it.

The repo is now a Cargo workspace. The parser core has no host-language code, and each consumer has its own binding crate.

Changes

  • src/ remains mdhtml-crate, the published library. Its python feature, pyo3 dependency, and cdylib crate type are gone.
  • py/ is the new mdhtml-py binding crate. src/python.rs moved to py/src/lib.rs and calls the public mdhtml:: API. maturin finds it through manifest-path in pyproject.toml.
  • wasm/ is the new mdhtml-wasm binding crate plus the @answerdotai/mdhtml npm package, private until its first publish. npm run build compiles with a size-tuned wasm profile and runs wasm-bindgen into the ignored wasm/pkg/. It exposes md2mdhtml. In the browser the fragment goes straight into the DOM, and the browser does the tree construction that fast5ever does for Python.
  • The version lives once, in [workspace.package]. ship-bump keeps wasm/package.json in step through [tool.fastship].version-files. This needs Support Cargo workspace versions and version-files in Rust projects fastship#41. The dev pin is fastship>=0.1.5.
  • src/lib.rs now exports six items the Python glue needs, by name: render_inlines, plain, code_block_open, CODE_BLOCK_CLOSE, trailing_attr_span, highlight_md. Their modules stay private.
  • CI has a new wasm job. cargo publish names -p mdhtml-crate, which skips the unpublished binding crates. The uv cache keys cover py/.
  • DEV.md documents the layout, the two one-time installs (rustup target add wasm32-unknown-unknown and a matching wasm-bindgen-cli), and --workspace on the check, clippy, and test commands.

No behaviour change to the parser or the Python API.

The repository becomes a Cargo workspace. src/ stays the published mdhtml-crate library and knows nothing about Python; py/ is mdhtml-py, the PyO3 glue that was src/python.rs, built by maturin through manifest-path and never published to crates.io. The published crate loses its optional pyo3 dependency, its python and extension-module features, and its cdylib crate type.

The version lives once in [workspace.package] and both crates inherit it, so the wheel and the crate keep the same number. Six items the glue needs beyond the documented API are exported from lib.rs by name (render_inlines, plain, code_block_open, CODE_BLOCK_CLOSE, trailing_attr_span, highlight_md); the modules that hold them stay private.

uv's cache keys cover py/, and CI publishes the crate with an explicit -p so it never tries to publish a member.

Claude-Session: https://claude.ai/code/session_01KCKXyYZu5R6fnPbTx3pMmo
wasm/ is mdhtml-wasm, the wasm-bindgen glue for the browser, built the same way py/ is built for Python: it depends on the library crate by path and exports the functions JavaScript may call, starting with md2mdhtml. wasm/package.json wraps the build output as the npm package @answerdotai/mdhtml, private until its first publish. Its version field is a copy of the workspace version, listed under [tool.fastship].version-files so ship-bump keeps it in step.

`npm run build` in wasm/ compiles with a new `wasm` profile (dist at opt-level z, which brings the .wasm from 420 KB to 283 KB) and runs wasm-bindgen into the ignored wasm/pkg/. The bindgen crate is pinned exactly because the CLI must match it. CI gains a compile-only wasm job; there is no publish step yet.

Claude-Session: https://claude.ai/code/session_01KCKXyYZu5R6fnPbTx3pMmo
The clippy allow for too_many_arguments moves to [workspace.lints] so it still covers the Python glue it was written for, and edition, rust-version, license, and repository join the version in [workspace.package] so every crate inherits one source. The stale #[allow(dead_code)] on render_inlines goes.

DEV.md's commands run with --workspace, its release note names [workspace.package].version, and the wasm build paragraph is split around its command block. The CI wasm job no longer waits on the Python tests and now runs wasm-bindgen too, so a CLI and crate mismatch fails in CI rather than only locally. The npm ignores gain node_modules/ and wasm/package-lock.json, which would otherwise hold a second version copy. The fastship dev pin rises to 0.1.5, the version that keeps wasm/package.json in step on bump.

Claude-Session: https://claude.ai/code/session_01KCKXyYZu5R6fnPbTx3pMmo
@ncoop57 ncoop57 changed the title Split the Python and wasm bindings into sub-crates Split into a Cargo workspace and add a WebAssembly binding Sep 5, 2026
@ncoop57 ncoop57 added the enhancement New feature or request label Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant