| Crates.io | blocks |
| lib.rs | blocks |
| version | 0.1.0 |
| created_at | 2025-07-17 02:56:59.237577+00 |
| updated_at | 2025-12-19 18:22:04.22072+00 |
| description | A high-performance Rust library for block-based content editing with JSON, Markdown, and HTML support |
| homepage | |
| repository | https://github.com/brenogonzaga/blocks |
| max_upload_size | |
| id | 1757011 |
| size | 322,288 |
A high-performance Rust library for block-based content editing with bidirectional conversion between JSON, Markdown, HTML, and Plain Text.
Blocks is designed as a backend engine for block-based content editors (like Notion, Editor.js, or TinyMCE). It provides a type-safe, validated block system with efficient conversions and advanced features like diff/merge, statistics, history management, and content sanitization.
Add to your Cargo.toml:
[dependencies]
blocks = "0.1.0"
use blocks::{Document, Block, BlockType};
// Create a document
let mut doc = Document::with_title("My Document".to_string());
doc.add_block(Block::new(BlockType::Text, "Hello, world!".to_string()));
// Convert to different formats
let json = doc.to_json()?; // JSON
let markdown = doc.to_markdown()?; // Markdown
let html = doc.to_html()?; // HTML
let plain = doc.to_plain_text()?; // Plain text
// Parse from formats
let doc = Document::from_json(&json)?;
let doc = Document::from_markdown(&markdown)?;
let doc = Document::from_html(&html)?;
use blocks::{DocumentBuilder, BlockBuilder};
let doc = DocumentBuilder::new("My Article")
.with_block(BlockBuilder::header(1, "Introduction")?.build())
.with_block(BlockBuilder::text("Welcome!").build())
.with_block(BlockBuilder::code("fn main() {}", Some("rust".to_string())).build())
.with_metadata("author", "John Doe")
.build();
use blocks::{Document, Block};
// Parse JSON from frontend
let doc = Document::from_json(r#"{"title":"Doc","blocks":[...]}"#)?;
// Process and return
let response = doc.to_json_pretty()?;
// Single block operations
let block = Block::from_json(r#"{"block_type":"Text",...}"#)?;
let result = block.to_json()?;
// Batch operations
let blocks = blocks::Converter::blocks_from_json("[...]")?;
| Block Type | Description | Example |
|---|---|---|
Text |
Plain text paragraph | Regular content |
Header |
Headers (levels 1-6) | # Title |
List |
Ordered/unordered lists | Bullet points |
Code |
Code blocks with syntax | fn main() {} |
Quote |
Blockquotes | > Quote |
Link |
Hyperlinks with title | [text](url) |
Image |
Images with alt/caption |  |
Table |
Tables with headers | Rows and columns |
Divider |
Horizontal rule | --- |
Embed |
YouTube, Vimeo, iframes | Media embeds |
Button |
Action buttons | CTA buttons |
Callout |
Info/warning boxes | Alerts |
Columns |
Multi-column layout | Side-by-side |
Details |
Collapsible sections | Accordions |
| From/To | JSON | Markdown | HTML | Plain Text |
|---|---|---|---|---|
| JSON | โ | โ | โ | โ |
| Markdown | โ | โ | โ | โ |
| HTML | โ | โ | โ | โ |
| Blocks | โ | โ | โ | โ |
| Operation | Time | Throughput |
|---|---|---|
| Block Creation | ~800ns | 1.25M ops/s |
| Validation | ~1-4ns | 250M-1B ops/s |
| Markdown Conversion | ~70-400ns | 2.5-14M ops/s |
| HTML Conversion | ~90-440ns | 2.3-11M ops/s |
| JSON Serialization | ~670ns | 1.5M ops/s |
| JSON Deserialization | ~1.1ยตs | 900K ops/s |
use blocks::DocumentStats;
let stats = DocumentStats::from_document(&doc);
println!("Words: {}", stats.total_words);
println!("Reading time: {:.1} min", stats.reading_time_mins);
println!("Complexity: {}/100", stats.complexity_score);
use blocks::{BlockPipeline, block_middlewares};
let pipeline = BlockPipeline::new()
.add_middleware(block_middlewares::trim_content())
.add_middleware(block_middlewares::lowercase())
.add_middleware(block_middlewares::max_length(100));
let mut block = Block::new(BlockType::Text, " HELLO ".to_string());
pipeline.process(&mut block)?;
use blocks::{HistoryManager, DocumentOperation};
let mut history = HistoryManager::new(50);
history.record(DocumentOperation::AddBlock { block, index: 0 });
if let Some(op) = history.undo() {
// Apply undo operation
}
use blocks::DocumentDiffer;
let diff = DocumentDiffer::diff(&doc1, &doc2);
println!("Changes: {}", diff.changes.len());
blocks/
โโโ src/
โ โโโ lib.rs # Entry point and re-exports
โ โโโ block.rs # Block types and validation
โ โโโ document.rs # Document container
โ โโโ converters.rs # Format converters (MD, HTML, JSON, PlainText)
โ โโโ error.rs # Error handling
โ โโโ builders.rs # Fluent builder API
โ โโโ sanitizer.rs # XSS prevention & sanitization
โ โโโ history.rs # Undo/redo functionality
โ โโโ cache.rs # Conversion caching
โ โโโ plugins.rs # Plugin system
โ โโโ pipeline.rs # Middleware processing
โ โโโ diff.rs # Document comparison
โ โโโ stats.rs # Document statistics
โโโ examples/
โ โโโ file_ops.rs # File I/O operations
โ โโโ json_api.rs # Backend API patterns
โโโ testdata/
โ โโโ sample.json # Sample JSON document
โ โโโ sample.md # Sample Markdown document
โ โโโ sample.html # Sample HTML document
โโโ benches/
โโโ conversion_bench.rs # Performance benchmarks
| Crate | Version | Purpose |
|---|---|---|
serde |
1.0 | JSON serialization |
serde_json |
1.0 | JSON parsing |
uuid |
1.0 | Unique identifiers |
thiserror |
2.0 | Error handling |
html-escape |
0.2 | HTML escaping |
pulldown-cmark |
0.13 | Markdown parser |
scraper |
0.23 | HTML parser |
regex |
1.10 | Pattern matching |
proptestRun tests:
cargo test
Run benchmarks:
cargo bench
Generate documentation:
cargo doc --open
Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
See CHANGELOG.md for version history and changes.