High-performance MS-DOC (.doc binary Word) parser and renderer for MoonBit, supporting JS, WASM, and WASM-GC backends with Web Worker support
| Target | Command | Output | Browser | Node.js | WASM Runtime |
|---|---|---|---|---|---|
| JS | moon build --target js --release | core.js (~375KB) | ✅ ESM | ✅ | — |
| JS Worker | moon build --target js --release worker | worker.js (~380KB) | ✅ Worker | — | — |
| WASM | moon build --target wasm --release | core.wasm (~133KB) | ✅ JS bridge | — | ✅ WASMtime |
| WASM-GC | moon build --target wasm-gc --release | core.wasm (~97KB) | ✅ JS string builtins | — | ✅ moon run |
.\build.batimport { render_ms_doc } from './_build/js/release/build/core/core.js';
const buffer = await file.arrayBuffer();
const raw = render_ms_doc(new Uint8Array(buffer));
const result = raw._0 || raw; // unwrap raise result
document.getElementById('viewer').innerHTML = `
<style>${result.css}</style>
${result.html}
`;// worker_wrapper.js — bridges postMessage to MoonBit exports
import { worker_parse, worker_render, worker_parse_to_html }
from '../_build/js/release/build/worker/worker.js';
self.onmessage = (e) => {
const { type, data, id } = e.data;
let result;
switch(type) {
case 'parse': result = worker_parse(data); break;
case 'render': result = worker_render(data); break;
case 'parseToHtml': result = worker_parse_to_html(data); break;
}
self.postMessage({ id, type, result });
};
self.postMessage({ type: 'ready' });const resp = await fetch('./_build/wasm/release/build/core/core.wasm');
const { instance } = await WebAssembly.instantiate(await resp.arrayBuffer());
const { memory, render_ms_doc } = instance.exports;
// Allocate bytes in fresh memory pages (avoids collision with MoonBit heap)
function allocBytes(data) {
const pageSize = 65536;
const headerSize = 8;
const prevPages = memory.grow(Math.ceil((headerSize + data.length) / pageSize));
const ptr = prevPages * pageSize + headerSize;
const dv = new DataView(memory.buffer);
dv.setInt32(ptr - 8, 1, true); // refcount
dv.setInt32(ptr - 4, data.length, true); // length
new Uint8Array(memory.buffer).set(data, ptr);
return ptr;
}
// Read MoonBit String from linear memory (UTF-16)
function readString(ptr) {
if (ptr <= 0) return '';
const dv = new DataView(memory.buffer);
const len = dv.getInt32(ptr - 4, true) & 0x0FFFFFFF;
let str = '';
for (let i = 0; i < len; i++) {
str += String.fromCharCode(dv.getUint16(ptr + i * 2, true));
}
return str;
}
// Read RenderResult struct { html: String, css: String }
function readRenderResult(structPtr) {
const dv = new DataView(memory.buffer);
return {
html: readString(dv.getInt32(structPtr, true)),
css: readString(dv.getInt32(structPtr + 4, true)),
};
}
// Call: returns (tag:i32, ptr:i32) — tag=1 success, tag=0 error
const inputPtr = allocBytes(uint8Array);
const [tag, resultPtr] = render_ms_doc(inputPtr);
if (tag === 1) {
const result = readRenderResult(resultPtr);
viewer.innerHTML = `<style>${result.css}</style>${result.html}`;
}const resp = await fetch('./_build/wasm-gc/release/build/core/core.wasm');
const bytes = await resp.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes, {}, {
builtins: ['js-string'], // wasm:js-string builtins (Chrome 112+)
importedStringConstants: '_' // string constant namespace
});
// Binary data passed as hex-encoded strings
const hex = uint8ArrayToHex(docBytes);
const result = instance.exports.render_ms_doc_wasm(hex);
// result is a native JS string: "CSS|||HTML"
const sep = result.indexOf('|||SEPARATOR|||');
const css = result.substring(0, sep);
const html = result.substring(sep + 15);moon run --target wasm-gc test┌─────────────┬─────────────┬──────────────────────────┐
│ refcount(i32)│ header(i32) │ data │
│ at ptr - 8 │ at ptr - 4 │ starting at ptr │
└─────────────┴─────────────┴──────────────────────────┘ptr - 8: refcount (i32)
ptr - 4: byte_length (i32)
ptr + 0: raw bytes [byte0, byte1, ...]ptr - 8: refcount (i32)
ptr - 4: char_count (i32, number of UTF-16 code units)
ptr + 0: UTF-16LE data [char0_lo, char0_hi, char1_lo, char1_hi, ...]| Feature | WASM (linear memory) | WASM-GC |
|---|---|---|
| Memory | Exported, JS-managed | Internal GC |
| String encoding | UTF-16 (2 bytes/char) | JS string (externref) |
| Object access | Direct memory read/write | Native JS string interop |
| Browser use | Via JS memory bridge | Via wasm:js-string builtins |
| FFI config | export-memory-name: "memory" | use-js-builtin-string: true |
| Browser compat | All modern | Chrome 112+, Firefox 120+, Safari 16.4+ |
| Function | Input | Returns | Notes |
|---|---|---|---|
| parse_ms_doc(bytes) | FixedArray[Byte] | MsDocParseResult | Parses .doc, returns structured data |
| render_ms_doc(bytes) | FixedArray[Byte] | RenderResult | Parses and renders to HTML+CSS |
| parse_ms_doc_to_html(bytes) | FixedArray[Byte] | String | Returns HTML only |
| Function | Input | Returns |
|---|---|---|
| render_ms_doc_wasm(hex) | hex-encoded string | "CSS\|\|\|HTML" |
| parse_ms_doc_to_html_wasm(hex) | hex-encoded string | "CSS\|\|\|HTML" |
| parse_ms_doc_wasm(hex) | hex-encoded string | text content |
| Function | Input | Returns |
|---|---|---|
| worker_parse(bytes) | FixedArray[Byte] | text string |
| worker_render(bytes) | FixedArray[Byte] | "CSS\|\|\|HTML" |
| worker_parse_to_html(bytes) | FixedArray[Byte] | "CSS\|\|\|HTML" |
.\build.bat # All targets
moon build --target js --release # JS only
moon build --target js --release worker # Worker only
moon build --target wasm --release # WASM only
moon build --target wasm-gc --release # WASM-GC only
moon test # Run testsmsdoc-viewer-moonbit/
├── core/ # Core parser + renderer (all targets)
│ ├── cfb.mbt # CFB/OLE container parser
│ ├── fib.mbt # File Information Block parser
│ ├── clx.mbt # CLX / Piece Table parser
│ ├── parser.mbt # Main MS-DOC parser
│ ├── render.mbt # HTML/CSS renderer
│ ├── wasm_bridge.mbt # WASM-GC hex-string bridge (conditional)
│ ├── moon.pkg # Multi-target exports config
│ └── ... # binary, sprm, fkp, fonts, styles, etc.
├── worker/ # Web Worker entry point
│ ├── worker_entry.mbt # MoonBit worker logic
│ ├── worker_wrapper.js # JS→MoonBit ESM bridge
│ └── moon.pkg # is-main + JS exports
├── test/ # Tests
│ ├── fixtures/ # Test .doc files (test1~test7.doc)
│ └── ... # Unit tests + WASM entry
├── demo/ # Browser demos
│ ├── index.html # Landing page
│ ├── js.html # JS target demo
│ ├── wasm.html # WASM demo
│ ├── wasm-gc.html # WASM-GC demo
│ └── worker.html # Web Worker demo
├── build.bat # Multi-target build script
└── moon.mod.json # MoonBit module confighttp://www.apache.org/licenses/LICENSE-2.0High-performance MS-DOC (.doc binary Word) parser and renderer for MoonBit, supporting JS, WASM, and WASM-GC backends with Web Worker support