WASM Feasibility Report: Suture Semantic Merge Engine
1. Dependency Analysis
suture-driver (trait crate)
suture-coresuture-commonblake3, serde, thiserror — all pure Rustserde / serde_jsonthiserrorwasmtime (optional)suture-core (version control engine)
blake3zstdrusqliteed25519-dalekwasm32 supportrandwasm32 supportdirsrayonstd::thread)tempfileDriver crates (suture-driver-{json,yaml,toml,csv,xml,markdown})
suture-driver-jsonserde_jsonsuture-driver-yamlserde_yaml (0.9 / unsafe-libyaml)suture-driver-tomltoml (0.8)suture-driver-csvcsv (1.3)suture-driver-xmlroxmltree (0.20)suture-driver-markdownAll six driver crates contain zero filesystem, network, or threading calls. Their merge logic operates entirely on &str inputs and produces String / Option<String> outputs.
2. Minimal WASM Library
What can compile to WASM today
The semantic merge logic in every driver crate (diff, merge, format_diff) is pure computation on strings. None of the driver implementations use suture-core APIs at all — they only import three types from suture-driver:
use suture_driver::{DriverError, SemanticChange, SutureDriver};
The SutureDriver trait, SemanticChange enum, and DriverError type are defined in suture-driver/src/lib.rs and suture-driver/src/error.rs. They have no dependency on suture-core internals — the dependency on suture-core in suture-driver/Cargo.toml is used only by the plugin module (WASM plugin loading via wasmtime) and registry module.
What cannot compile to WASM
suture-core(SQLite, threads, filesystem)suture-driver/plugin.rs(wasmtime, filesystem plugin discovery)suture-driver/registry.rs(filesystem plugin discovery)
3. Recommendation
Architecture: Extract a suture-merge crate
Create a new crate suture-merge that re-exports only the WASM-friendly subset:
suture-merge/
Cargo.toml # depends only on serde, thiserror
src/
lib.rs # re-exports trait + types + all 6 drivers
traits.rs # SutureDriver trait + SemanticChange + DriverError
json.rs # JsonDriver (copied or symlinked from suture-driver-json)
yaml.rs # YamlDriver
toml.rs # TomlDriver
csv.rs # CsvDriver
xml.rs # XmlDriver
markdown.rs # MarkdownDriver
Alternative (less duplication): Extract the SutureDriver trait, SemanticChange, and DriverError into a zero-dependency suture-driver-traits crate. Then:
suture-driverdepends onsuture-driver-traits+suture-core(for plugin/registry)suture-driver-jsonetc. depend onsuture-driver-traitsinstead ofsuture-driversuture-mergedepends onsuture-driver-traits+ allsuture-driver-*crates
This eliminates code duplication and keeps the existing crate structure intact.
WASM API surface
#[wasm_bindgen]
pub fn merge_json(base: &str, ours: &str, theirs: &str) -> JsValue { ... }
#[wasm_bindgen]
pub fn merge_yaml(base: &str, ours: &str, theirs: &str) -> JsValue { ... }
#[wasm_bindgen]
pub fn merge_toml(base: &str, ours: &str, theirs: &str) -> JsValue { ... }
#[wasm_bindgen]
pub fn merge_csv(base: &str, ours: &str, theirs: &str) -> JsValue { ... }
#[wasm_bindgen]
pub fn merge_xml(base: &str, ours: &str, theirs: &str) -> JsValue { ... }
#[wasm_bindgen]
pub fn merge_markdown(base: &str, ours: &str, theirs: &str) -> JsValue { ... }
Return type: { merged: string | null, is_clean: boolean } (JSON-encoded Option<String>).
What would need to change
- Extract trait types into
suture-driver-traits(or inline intosuture-merge) - Update driver crates to depend on
suture-driver-traitsinstead ofsuture-driver(or keep as-is and havesuture-mergere-declare the types) - Add
wasm-bindgenwrapper insuture-merge - Add
[target.'cfg(target_arch = "wasm32")'.dependencies]if any conditional deps are needed - No changes needed to driver merge logic — it is already WASM-compatible
4. Estimated Effort
suture-driver-traits crate, move trait + typessuture-driver-traitssuture-merge crate with wasm-bindgen APIwasm-pack build pipeline + npm package generationKey question answer
Could we create a
suture-merge-wasmcrate that provides just the semantic merge function (parse + three-way merge + serialize) as a WASM module, with no filesystem or network dependencies?
Yes. The merge logic in all six drivers is already pure string-in/string-out computation with zero platform dependencies. The only obstacle is the transitive suture-driver -> suture-core dependency chain, which is trivially severed by extracting the SutureDriver trait into its own crate.