ryo-plugin-api 0.1.0

[experimental] WebAssembly Interface Types for ryo mutation plugins
Documentation
//! # Ryo Plugin API
//!
//! WebAssembly Interface Types for ryo mutation plugins.
//!
//! ## Overview
//!
//! This crate provides the WIT-generated Rust types that define the contract
//! between the ryo host and WASM mutation plugins. Plugins act as
//! "Definition Providers" - they supply mutation metadata and transformation logic.
//!
//! ## Architecture
//!
//! ```text
//! WASM Plugin (Guest)              ryo (Host)
//! ┌─────────────────────┐          ┌─────────────────────────┐
//! │ get-manifest()      │───WIT───>│ Load mutation metadata  │
//! │ get-pattern-source()│───WIT───>│ Compile pattern matcher │
//! │ execute-transform() │───WIT───>│ Apply text edits        │
//! └─────────────────────┘          └─────────────────────────┘
//! ```
//!
//! ## Usage
//!
//! ### For Plugin Authors (Guest)
//!
//! ```rust,ignore
//! use ryo_plugin_api::*;
//!
//! wit_bindgen::generate!({
//!     world: "mutation-plugin",
//!     path: "wit",
//!     exports: {
//!         "ryo:transform/mutation": MyMutation,
//!     }
//! });
//!
//! struct MyMutation;
//!
//! impl exports::ryo::transform::mutation::Guest for MyMutation {
//!     fn get_manifest() -> MutationManifest {
//!         MutationManifest {
//!             api_version: CURRENT_API_VERSION,
//!             name: "bool-simplify".into(),
//!             description: "Simplify boolean comparisons".into(),
//!             category: MutationCategory::Idiom,
//!             tier: 1,
//!             pattern: "...".into(),
//!             transform: TransformDef::Template("{{var}}".into()),
//!         }
//!     }
//!
//!     fn get_pattern_source() -> String {
//!         String::new()
//!     }
//!
//!     fn execute_transform(
//!         _matches: Vec<MatchResult>,
//!         _context: TransformContext,
//!     ) -> Result<Vec<TextEdit>, TransformError> {
//!         // Only called if transform = WasmExecute
//!         unreachable!()
//!     }
//! }
//! ```
//!
//! ### For Host Implementation
//!
//! ```rust,ignore
//! use ryo_plugin_loader::PluginLoader;
//!
//! let loader = PluginLoader::new()?;
//! let plugin = loader.load(&wasm_bytes)?;
//!
//! // Use manifest
//! println!("Loaded mutation: {}", plugin.manifest.name);
//! ```
//!
//! ## API Versioning
//!
//! The `api_version` field in `MutationManifest` ensures compatibility:
//!
//! - Current version: **1**
//! - Host rejects plugins with mismatched versions
//! - Breaking changes increment the version number

// Generate WIT bindings
wit_bindgen::generate!({
    path: "wit",
    world: "mutation-plugin",
});

// Re-export types from WIT interfaces
pub use exports::ryo::transform::mutation::{
    Guest, MutationCategory, MutationManifest, TransformContext, TransformDef, TransformError,
};
pub use exports::ryo::transform::types::{Capture, MatchResult, NodeKind, TextEdit, TypeHint};

/// Current API version
///
/// This constant should match the version used by the host.
/// Plugins should use this in their manifest:
///
/// ```rust,ignore
/// MutationManifest {
///     api_version: ryo_plugin_api::CURRENT_API_VERSION,
///     // ...
/// }
/// ```
pub const CURRENT_API_VERSION: u32 = 1;

// =============================================================================
// Helper Functions
// =============================================================================

/// Create a template-based transform definition
///
/// Template supports `{{capture_name}}` interpolation.
///
/// # Example
/// ```rust,ignore
/// let transform = template("{{var}}");
/// // For match: `x == true` with capture @var="x"
/// // Result: `x`
/// ```
pub fn template(tmpl: &str) -> TransformDef {
    TransformDef::Template(tmpl.to_string())
}

/// Create a WASM-execute transform definition
///
/// Use this when the transform requires complex logic that can't be
/// expressed as a simple template.
pub fn wasm_execute() -> TransformDef {
    TransformDef::WasmExecute
}

/// Create a text edit
pub fn text_edit(start_byte: u64, end_byte: u64, replacement: &str) -> TextEdit {
    TextEdit {
        start_byte,
        end_byte,
        replacement: replacement.to_string(),
    }
}