blocks 0.1.0

A high-performance Rust library for block-based content editing with JSON, Markdown, and HTML support
Documentation

Blocks

Crates.io Documentation License: MIT Tests

A high-performance Rust library for block-based content editing with bidirectional conversion between JSON, Markdown, HTML, and Plain Text.

Overview

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.

Key Features

  • ๐Ÿ”„ Bidirectional Conversions: JSON โ†” Markdown โ†” HTML โ†” Blocks
  • ๐Ÿ›ก๏ธ Security: XSS prevention, HTML sanitization, URL validation
  • โšก Performance: Sub-microsecond operations, zero-copy where possible
  • ๐Ÿงช Tested: 173 tests (158 unit + 15 doc), property-based testing
  • ๐Ÿ—๏ธ Builder Pattern: Fluent API for document creation
  • ๐Ÿ“Š Analytics: Word count, reading time, complexity scores
  • ๐Ÿ”€ Diff & Merge: Document comparison with merge strategies
  • โช History: Undo/redo with operation tracking
  • ๐Ÿ’พ Caching: LRU cache with TTL for conversions
  • ๐Ÿ”Œ Extensible: Plugin system for custom processing

Quick Start

Add to your Cargo.toml:

[dependencies]
blocks = "0.1.0"

Basic Usage

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)?;

Builder Pattern

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();

JSON API for Editor Backends

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("[...]")?;

Supported Block Types

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 ![alt](url)
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

Features

Features

Core Functionality

  • 14 Block Types: Text, headers, lists, code, quotes, links, images, tables, dividers, embeds, buttons, callouts, columns, details
  • Type Safety: Fully typed with Rust's type system
  • Validation: Comprehensive validation with detailed error messages
  • Metadata: Flexible key-value metadata on blocks and documents
  • UUIDs: Unique identifiers for all entities

Conversions

From/To JSON Markdown HTML Plain Text
JSON โœ“ โœ“ โœ“ โœ“
Markdown โœ“ โœ“ โœ“ โœ“
HTML โœ“ โœ“ โœ“ โœ“
Blocks โœ“ โœ“ โœ“ โœ“

Security

  • HTML Escaping: Automatic escaping of special characters
  • XSS Prevention: Content sanitizer with normal/strict modes
  • URL Validation: Safe URL checking for links and embeds
  • Script Removal: Strips dangerous HTML elements and attributes

Advanced Features

  • Builder API: Fluent interface for document creation
  • Statistics: Word count, reading time, complexity analysis
  • Diff & Merge: Compare documents, detect changes, merge strategies
  • History: Undo/redo with operation tracking
  • Caching: LRU cache with TTL for conversion results
  • Pipeline: Composable middleware for content processing
  • Plugins: Extensible system for custom validators and transformers

Performance

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

Examples

Document Statistics

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);

Pipeline Processing

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)?;

History Management

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
}

Document Diff

use blocks::DocumentDiffer;

let diff = DocumentDiffer::diff(&doc1, &doc2);
println!("Changes: {}", diff.changes.len());

Project Structure

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

Dependencies

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

Testing

  • 173 tests (158 unit + 15 doc tests)
  • Property-based testing with proptest
  • Roundtrip tests for format conversions
  • Integration tests for end-to-end workflows
  • Test data files in multiple formats

Run tests:

cargo test

Run benchmarks:

cargo bench

Generate documentation:

cargo doc --open

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

See CHANGELOG.md for version history and changes.

Links