ordinals-parser 0.1.0

A lightweight parser for Bitcoin Ordinals inscriptions
Documentation
//! A lightweight parser for Bitcoin Ordinals inscriptions.
//!
//! This library allows you to parse and extract Ordinals inscriptions from Bitcoin
//! transactions without requiring the full Ord codebase.
//!
//! # Features
//!
//! - Parse Ordinals inscriptions from Bitcoin transactions
//! - Support for both classic and modern inscription formats
//! - Extract content type, body, and other metadata
//! - Detect JSON in text/plain content
//! - Low dependency footprint
//!
//! # Basic Example
//!
//! ```rust
//! use ordinals_parser::{parse_inscriptions_from_transaction, Inscription};
//! use bitcoin::Transaction;
//!
//! # fn example() {
//! // Load a Bitcoin transaction
//! let transaction: Transaction = /* ... */;
//!     
//! // Parse inscriptions
//! let inscriptions = parse_inscriptions_from_transaction(&transaction);
//!     
//! for inscription in inscriptions {
//!     println!("Content type: {:?}", inscription.content_type());
//!     println!("Content length: {:?}", inscription.content_length());
//!         
//!     if let Some(body) = inscription.body() {
//!         // Work with inscription content
//!     }
//! }
//! # }
//! ```
//!
//! # Working with JSON Inscriptions
//!
//! The library can detect and parse JSON content in both `application/json` and `text/plain` inscriptions:
//!
//! ```rust
//! use ordinals_parser::{parse_inscriptions_from_transaction};
//! use bitcoin::Transaction;
//! use serde_json::Value;
//!
//! # fn example() {
//! // Load a Bitcoin transaction
//! let transaction: Transaction = /* ... */;
//! 
//! // Parse inscriptions
//! let inscriptions = parse_inscriptions_from_transaction(&transaction);
//! 
//! for inscription in inscriptions {
//!     if let (Some(content_type), Some(body)) = (inscription.content_type(), inscription.body()) {
//!         // Check if it's JSON content
//!         let is_json = content_type == "application/json" || 
//!             (content_type.starts_with("text/plain") && 
//!              if let Ok(text) = std::str::from_utf8(body) {
//!                  let trimmed = text.trim();
//!                  (trimmed.starts_with('{') && trimmed.ends_with('}')) || 
//!                  (trimmed.starts_with('[') && trimmed.ends_with(']'))
//!              } else {
//!                  false
//!              });
//!         
//!         if is_json {
//!             if let Ok(text) = std::str::from_utf8(body) {
//!                 if let Ok(json) = serde_json::from_str::<Value>(text) {
//!                     // Process BRC-20, Ordinals Collections, etc.
//!                     println!("Found JSON content: {:?}", json);
//!                 }
//!             }
//!         }
//!     }
//! }
//! # }
//! ```
//!
//! # Creating an Inscription
//!
//! ```rust
//! use ordinals_parser::InscriptionBuilder;
//!
//! # fn example() {
//! let inscription = InscriptionBuilder::new()
//!     .content_type("text/plain;charset=utf-8")
//!     .body("Hello, Ordinals!".as_bytes())
//!     .build();
//!
//! // Convert to a script (for inclusion in a Bitcoin transaction)
//! let script = inscription.to_script();
//! # }
//! ```

/// Error handling module
pub mod error;

/// Inscription envelope parsing
pub mod envelope;

/// Inscription data structure
pub mod inscription;

/// Inscription ID
pub mod inscription_id;

/// Tags used in inscriptions
pub mod tag;

// Re-export important types
pub use crate::error::{Error, Result};
pub use crate::inscription::{Inscription, InscriptionBuilder};
pub use crate::inscription_id::InscriptionId;
pub use crate::envelope::{
    parse_transaction_inscriptions,
    parse_input_inscriptions,
    is_inscription_input,
    parse_envelope,
};

/// Parse all inscriptions from a Bitcoin transaction
///
/// This function examines all inputs in the transaction and extracts any
/// inscriptions found in their witness data.
///
/// # Parameters
///
/// * `tx` - A reference to a Bitcoin transaction
///
/// # Returns
///
/// A vector of `Inscription` objects found in the transaction
///
/// # Example
///
/// ```rust
/// use ordinals_parser::parse_inscriptions_from_transaction;
/// use bitcoin::Transaction;
///
/// // Load a Bitcoin transaction
/// let transaction: Transaction = /* ... */;
///
/// // Parse all inscriptions
/// let inscriptions = parse_inscriptions_from_transaction(&transaction);
/// ```
pub fn parse_inscriptions_from_transaction(tx: &bitcoin::Transaction) -> Vec<Inscription> {
    envelope::parse_transaction_inscriptions(tx)
}

#[cfg(test)]
mod tests {
    use super::*;
    use bitcoin::consensus::deserialize;
    use hex::FromHex;

    #[test]
    fn test_parse_basic_inscription() {
        // Simplified test transaction with an inscription
        let tx_hex = "0200000000010137c361dc8bdf2c902a73c76f3059db944fc62e635ae7381aa06c79e9a1d1640b0100000000fdffffff020000000000000000296a0e6f7264010100000000000000110011018fe3bfeff84353cd5863c7c9ba48575a0cb2fb606d075f336701000000000017a914121f75e89e9b240a83b303b6e22e074d1c65dfa9870247304402205d793a28c26e568cf0601aae58a976a880f98fae56d905ab9e9e7f7342d4b3d402201b53b8f5507ac93eb7afad7e34af11c78c9b325947ad8c3f25be67700c0c0a90012103af0b2c5c872b732ac9474c576f84950e0a89ec57500507944c87f1fa4af76b9d00000000";
        let tx_bytes = Vec::from_hex(tx_hex).unwrap();
        let tx: bitcoin::Transaction = deserialize(&tx_bytes).unwrap();
        
        let inscriptions = parse_inscriptions_from_transaction(&tx);
        
        assert_eq!(inscriptions.len(), 1);
        assert_eq!(inscriptions[0].content_type(), Some("text/plain"));
        assert_eq!(inscriptions[0].body(), Some(b"Hello, world!".as_ref()));
    }
}