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
38 changes: 19 additions & 19 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["crates/docx-core", "crates/docx-wasm"]
members = ["crates/extend-docx", "crates/docx-wasm"]
resolver = "2"

[workspace.package]
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# react-docx

[![npm version](https://img.shields.io/npm/v/%40extend-ai%2Freact-docx)](https://www.npmjs.com/package/@extend-ai/react-docx)
[![crates.io version](https://img.shields.io/crates/v/extend-docx)](https://crates.io/crates/extend-docx)

`react-docx` is a DOCX viewer and editor for JavaScript and React applications, built as a monorepo.

Expand All @@ -23,6 +24,14 @@ pnpm add @extend-ai/react-docx

For React integrations, also install `react` and `react-dom`. The vanilla entry bundles Preact and does not require React.

For native Rust parsing, structured extraction, and serialization, use [`extend-docx`](./crates/extend-docx/README.md):

```bash
cargo add extend-docx
```

Import it as `extend_docx` in Rust. The Rust crate and npm packages have independent release versions.

## WebAssembly and Vite

DOCX parsing and export use a WebAssembly binary shipped with the package. It loads on demand, and most bundlers can resolve it automatically. To host it at a specific URL, copy the binary to your application's public directory:
Expand Down Expand Up @@ -459,6 +468,8 @@ const output = serializeDocx(model, pkg);

## Workspace Layout

- `crates/extend-docx`: the published Rust parser, document model, and serializer, `extend-docx`
- `crates/docx-wasm`: internal WebAssembly bindings for the JavaScript viewer
- `packages/react-viewer`: the main published React package, `@extend-ai/react-docx`
- `packages/ooxml-core`: OOXML package parsing and part graph handling
- `packages/doc-model`: normalized document model
Expand Down Expand Up @@ -522,11 +533,13 @@ pnpm test:docx-vs-libreoffice

## Publishing

Changesets are used for release management:
Changesets are used for npm release management:

```bash
pnpm changeset
pnpm version-packages
pnpm build
pnpm publish-packages
```

The Rust crate is released independently with `cargo publish -p extend-docx --locked`. See [Rust publishing](docs/rust-publishing.md) for validation and GitHub team ownership.
37 changes: 0 additions & 37 deletions crates/docx-core/examples/dump_doc_text.rs

This file was deleted.

4 changes: 3 additions & 1 deletion crates/docx-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ name = "docx-wasm"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Internal WebAssembly bindings for extend-docx and the React document viewer"
publish = false

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
docx-core = { path = "../docx-core" }
extend-docx = { path = "../extend-docx" }
serde.workspace = true
serde_json = { workspace = true, features = ["float_roundtrip"] }
wasm-bindgen = "0.2"
Expand Down
26 changes: 13 additions & 13 deletions crates/docx-wasm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;

use docx_core::{
use extend_docx::{
build_doc_model, model_to_document_xml, package_to_bytes, parse_document_bytes,
try_serialize_doc_model, DocModel, ImageRunNode, OoxmlPackage, OoxmlPart,
};
Expand All @@ -22,7 +22,7 @@ fn doc_model_from_json(json_str: &str) -> Result<DocModel, JsValue> {
#[wasm_bindgen]
pub fn extract_document_blocks_wasm(model_json: &str) -> Result<String, JsValue> {
let model = doc_model_from_json(model_json)?;
serde_json::to_string(&docx_core::extract_document_blocks(&model))
serde_json::to_string(&extend_docx::extract_document_blocks(&model))
.map_err(|error| JsValue::from_str(&error.to_string()))
}

Expand All @@ -35,7 +35,7 @@ pub fn extract_document_blocks_with_options_wasm(
let options = serde_json::from_str(options_json).map_err(|error| {
JsValue::from_str(&format!("Invalid block extraction options JSON: {error}"))
})?;
serde_json::to_string(&docx_core::extract_document_blocks_with_options(
serde_json::to_string(&extend_docx::extract_document_blocks_with_options(
&model, options,
))
.map_err(|error| JsValue::from_str(&error.to_string()))
Expand All @@ -44,7 +44,7 @@ pub fn extract_document_blocks_with_options_wasm(
#[wasm_bindgen]
pub fn inspect_document_source_wasm(bytes: &[u8]) -> Result<String, JsValue> {
let package = parse_document_bytes(bytes).map_err(|error| JsValue::from_str(&error))?;
serde_json::to_string(&docx_core::document_source_graph(&package))
serde_json::to_string(&extend_docx::document_source_graph(&package))
.map_err(|error| JsValue::from_str(&error.to_string()))
}

Expand Down Expand Up @@ -86,10 +86,10 @@ pub fn can_preserve_image_paint_source_wasm(
None => None,
};
let owner = owner_part_name.unwrap_or_else(|| match base.as_ref() {
Some(package) => docx_core::main_document_part_name(package),
None => docx_core::main_document_part_name(&docx_core::create_minimal_docx_package(None)),
Some(package) => extend_docx::main_document_part_name(package),
None => extend_docx::main_document_part_name(&extend_docx::create_minimal_docx_package(None)),
});
Ok(docx_core::can_preserve_image_paint_source(&image, base.as_ref(), &owner))
Ok(extend_docx::can_preserve_image_paint_source(&image, base.as_ref(), &owner))
}

fn js_bytes_to_vec(value: &JsValue, key: &str) -> Result<Vec<u8>, JsValue> {
Expand Down Expand Up @@ -273,7 +273,7 @@ pub fn serialize_docx_wasm(
base_package: Option<JsValue>,
) -> Result<Vec<u8>, JsValue> {
let doc_model = value_to_doc_model(model)?;
docx_core::table_grid::validate_collapsed_table_grids(&doc_model)
extend_docx::table_grid::validate_collapsed_table_grids(&doc_model)
.map_err(|error| JsValue::from_str(&error))?;
let base = match base_package {
Some(value) => Some(value_to_ooxml_package(&value)?),
Expand All @@ -290,7 +290,7 @@ pub fn serialize_docx_from_json_wasm(
base_package: Option<JsValue>,
) -> Result<Vec<u8>, JsValue> {
let doc_model = doc_model_from_json(model_json)?;
docx_core::table_grid::validate_collapsed_table_grids(&doc_model)
extend_docx::table_grid::validate_collapsed_table_grids(&doc_model)
.map_err(|error| JsValue::from_str(&error))?;
let base = match base_package {
Some(value) => Some(value_to_ooxml_package(&value)?),
Expand All @@ -307,13 +307,13 @@ pub fn model_to_document_xml_wasm(
base_package: Option<JsValue>,
) -> Result<String, JsValue> {
let doc_model = value_to_doc_model(model)?;
docx_core::table_grid::validate_collapsed_table_grids(&doc_model)
extend_docx::table_grid::validate_collapsed_table_grids(&doc_model)
.map_err(|error| JsValue::from_str(&error))?;
let base = match base_package {
Some(value) => Some(value_to_ooxml_package(&value)?),
None => None,
};
docx_core::validate_image_paint_bounds(&doc_model, base.as_ref())
extend_docx::validate_image_paint_bounds(&doc_model, base.as_ref())
.map_err(|error| JsValue::from_str(&error))?;
Ok(model_to_document_xml(&doc_model, base.as_ref()))
}
Expand All @@ -324,13 +324,13 @@ pub fn model_to_document_xml_from_json_wasm(
base_package: Option<JsValue>,
) -> Result<String, JsValue> {
let doc_model = doc_model_from_json(model_json)?;
docx_core::table_grid::validate_collapsed_table_grids(&doc_model)
extend_docx::table_grid::validate_collapsed_table_grids(&doc_model)
.map_err(|error| JsValue::from_str(&error))?;
let base = match base_package {
Some(value) => Some(value_to_ooxml_package(&value)?),
None => None,
};
docx_core::validate_image_paint_bounds(&doc_model, base.as_ref())
extend_docx::validate_image_paint_bounds(&doc_model, base.as_ref())
.map_err(|error| JsValue::from_str(&error))?;
Ok(model_to_document_xml(&doc_model, base.as_ref()))
}
Expand Down
12 changes: 12 additions & 0 deletions crates/extend-docx/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Changelog

## 0.1.0

Initial crates.io release of Extend's shared Rust parser, previously named `docx-core` within the repository.

- Publish the Cargo package as `extend-docx`, imported as `extend_docx`.
- Parse DOCX and Word 97–2003 binary DOC into a shared document model and structured blocks.
- Preserve source references and support DOCX serialization through the shared model.
- Support native Rust and WebAssembly, with optional native ZIP decompression enabled by default on native builds.

Page geometry requires the viewer's layout engine. Rust versions are independent of the React viewer's npm versions.
9 changes: 6 additions & 3 deletions crates/docx-core/Cargo.toml → crates/extend-docx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
[package]
name = "docx-core"
name = "extend-docx"
version.workspace = true
edition.workspace = true
license.workspace = true
description = "Shared native Rust and WebAssembly parsing for DOCX and legacy Word documents"
description = "Rust parser, document model, and serializer for DOCX and legacy Word documents"
repository = "https://github.com/extend-hq/react-docx"
documentation = "https://docs.rs/extend-docx"
keywords = ["docx", "doc", "ooxml", "parser", "wasm"]
categories = ["parser-implementations", "text-processing"]
readme = "README.md"
include = ["src/**", "examples/parse_blocks.rs", "README.md", "third-party/**", "LICENSE", "Cargo.toml"]
include = ["src/**", "examples/parse_blocks.rs", "README.md", "CHANGELOG.md", "third-party/**", "LICENSE", "Cargo.toml"]

[features]
default = ["native-deflate"]
Expand Down
File renamed without changes.
Loading
Loading