//! Plugin factory: how `folk-builder`'s generated `main.rs` constructs each plugin.
//!
//! The convention is: every plugin crate exports
//!
//! ```rust,ignore
//! pub fn folk_plugin_factory() -> Box<dyn folk_api::PluginFactory> {
//!     Box::new(MyPluginFactory)
//! }
//! ```
//!
//! The builder calls `crate_name::folk_plugin_factory()` for each plugin
//! and registers the result. There is no other naming convention; the
//! function name is fixed.

use anyhow::Result;
use serde_json::Value as JsonValue;

use crate::plugin::Plugin;

/// Constructs a [`Plugin`] from runtime configuration.
pub trait PluginFactory: Send + Sync + 'static {
    /// Construct a plugin from its config section (JSON from `folk.toml`).
    ///
    /// # Contract: empty config must be accepted
    ///
    /// `folk-builder` compiles every selected plugin into the extension
    /// unconditionally and passes `{}` (an empty JSON object) for any plugin
    /// whose section is absent from `folk.toml`. Implementations **must**
    /// succeed on `create(json!({}))` and apply sensible defaults — an absent
    /// section is not the same as a disabled plugin.
    ///
    /// Every plugin crate should include a regression test:
    /// ```rust,ignore
    /// #[test]
    /// fn factory_accepts_empty_config() {
    ///     assert!(folk_plugin_factory().create(serde_json::json!({})).is_ok());
    /// }
    /// ```
    fn create(&self, config: JsonValue) -> Result<Box<dyn Plugin>>;
}
