Skip to content

Commit 49bc551

Browse files
author
damon
committed
feat: extract batdoc-core library crate from CLI binary
Split the single-binary crate into a Cargo workspace so other Rust projects (e.g. Rummage MCP server) can depend on document extraction as a library without pulling in bat/terminal dependencies. - New batdoc-core crate with 8-item public API: Format, BatdocError, Result, detect_format, extract_plain, extract_markdown, to_plain, to_markdown - 13 source modules moved to batdoc-core/src/ (git history preserved) - CLI rewritten as thin wrapper using batdoc_core::* - bat and is-terminal remain CLI-only dependencies - 257 unit tests pass, clippy clean
1 parent f8e4947 commit 49bc551

20 files changed

Lines changed: 271 additions & 126 deletions

Cargo.lock

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
[workspace]
2+
members = [".", "batdoc-core"]
3+
14
[package]
25
name = "batdoc"
3-
version = "1.3.1"
6+
version = "1.4.0"
47
edition = "2021"
58
description = "cat(1) for doc, docx, xls, xlsx, pptx, and pdf -- renders to markdown with bat"
69
license = "MIT"
@@ -15,15 +18,9 @@ name = "batdoc"
1518
path = "src/main.rs"
1619

1720
[dependencies]
18-
base64 = "0.22"
21+
batdoc-core = { path = "batdoc-core" }
1922
bat = { version = "0.26.1", default-features = false, features = ["regex-fancy", "paging"] }
20-
cfb = "0.13"
21-
encoding_rs = "0.8"
2223
is-terminal = "0.4"
23-
quick-xml = "0.37"
24-
pdf-extract = "0.10"
25-
thiserror = "2"
26-
zip = { version = "2", default-features = false, features = ["deflate"] }
2724

2825
[build-dependencies]
2926
man = "0.3"

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,28 @@ and for formats without OOXML image support (`.doc`, `.xls`, `.pdf`).
114114

115115
## Dependencies
116116

117-
Eight crates, no C, no system libs: `base64`, `bat`, `cfb`, `encoding_rs`,
118-
`pdf-extract`, `quick-xml`, `zip`, `is-terminal`.
117+
The CLI binary depends on `batdoc-core` (document extraction library),
118+
`bat` (syntax highlighting), and `is-terminal` (tty detection).
119+
120+
The `batdoc-core` library depends on `cfb`, `encoding_rs`, `quick-xml`,
121+
`zip`, `pdf-extract`, `base64`, and `thiserror`. No C, no system libs.
122+
123+
## Library
124+
125+
The extraction engine is available as a standalone Rust library for
126+
programmatic use — no CLI or terminal dependencies:
127+
128+
```toml
129+
[dependencies]
130+
batdoc-core = { git = "https://github.com/daemonp/batdoc" }
131+
```
132+
133+
```rust
134+
let data = std::fs::read("report.docx")?;
135+
let markdown = batdoc_core::to_markdown(&data, false)?;
136+
```
137+
138+
See [batdoc-core/README.md](batdoc-core/README.md) for the full API.
119139

120140
## History
121141

batdoc-core/Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "batdoc-core"
3+
version = "1.4.0"
4+
edition = "2021"
5+
description = "Document text extraction library — DOCX, XLSX, PPTX, DOC, XLS, PDF to plain text or Markdown"
6+
license = "MIT"
7+
repository = "https://github.com/daemonp/batdoc"
8+
readme = "README.md"
9+
10+
[lib]
11+
name = "batdoc_core"
12+
path = "src/lib.rs"
13+
14+
[dependencies]
15+
base64 = "0.22"
16+
cfb = "0.13"
17+
encoding_rs = "0.8"
18+
pdf-extract = "0.10"
19+
quick-xml = "0.37"
20+
thiserror = "2"
21+
zip = { version = "2", default-features = false, features = ["deflate"] }

batdoc-core/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# batdoc-core
2+
3+
Document text extraction library for Rust. Converts `.doc`, `.docx`, `.xls`,
4+
`.xlsx`, `.pptx`, and `.pdf` files to plain text or Markdown.
5+
6+
Format detection is by magic bytes, not file extension — works on raw byte
7+
buffers without filesystem access, which makes it suitable for email
8+
attachments, HTTP uploads, and other contexts where filenames are unreliable.
9+
10+
## Usage
11+
12+
```toml
13+
[dependencies]
14+
batdoc-core = { git = "https://github.com/daemonp/batdoc" }
15+
```
16+
17+
```rust
18+
use batdoc_core::{detect_format, extract_markdown, extract_plain, to_markdown, Format};
19+
20+
// One-shot: detect format and extract in a single call
21+
let data: Vec<u8> = std::fs::read("report.docx").unwrap();
22+
let markdown = batdoc_core::to_markdown(&data, false).unwrap();
23+
let plain = batdoc_core::to_plain(&data).unwrap();
24+
25+
// Two-step: detect first, then extract (useful for logging or branching)
26+
let format = batdoc_core::detect_format(&data).unwrap();
27+
println!("Detected format: {format}");
28+
let text = batdoc_core::extract_plain(&data, format).unwrap();
29+
```
30+
31+
## Public API
32+
33+
```rust
34+
pub enum Format { Doc, Xls, Docx, Xlsx, Pptx, Pdf }
35+
pub enum BatdocError { Io, Zip, Document, Render }
36+
pub type Result<T> = std::result::Result<T, BatdocError>;
37+
38+
pub fn detect_format(data: &[u8]) -> Result<Format>;
39+
pub fn extract_plain(data: &[u8], format: Format) -> Result<String>;
40+
pub fn extract_markdown(data: &[u8], format: Format, images: bool) -> Result<String>;
41+
pub fn to_plain(data: &[u8]) -> Result<String>;
42+
pub fn to_markdown(data: &[u8], images: bool) -> Result<String>;
43+
```
44+
45+
`extract_markdown` with `images: true` embeds images from DOCX/XLSX/PPTX as
46+
base64 data URIs. Has no effect on DOC, XLS, or PDF.
47+
48+
## Supported formats
49+
50+
| Format | Detection | Parser |
51+
|--------|-----------|--------|
52+
| `.doc` | OLE2 magic + `/WordDocument` stream | Binary Word 97+ (BIFF-like) |
53+
| `.xls` | OLE2 magic + `/Workbook` stream | BIFF8 (Excel 97+) |
54+
| `.docx` | ZIP magic + `word/document.xml` | OOXML |
55+
| `.xlsx` | ZIP magic + `xl/workbook.xml` | OOXML |
56+
| `.pptx` | ZIP magic + `ppt/presentation.xml` | OOXML |
57+
| `.pdf` | `%PDF-` header | pdf-extract |
58+
59+
## License
60+
61+
MIT
File renamed without changes.
File renamed without changes.

src/error.rs renamed to batdoc-core/src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
/// All errors that can occur during document parsing and rendering.
77
#[derive(Debug, thiserror::Error)]
8-
pub(crate) enum BatdocError {
8+
pub enum BatdocError {
99
/// I/O error (file read, stream read, OLE2 compound file).
1010
#[error("{0}")]
1111
Io(#[from] std::io::Error),
@@ -24,4 +24,4 @@ pub(crate) enum BatdocError {
2424
}
2525

2626
/// Convenience alias used throughout the crate.
27-
pub(crate) type Result<T> = std::result::Result<T, BatdocError>;
27+
pub type Result<T> = std::result::Result<T, BatdocError>;

0 commit comments

Comments
 (0)