alef 0.23.34

Opinionated polyglot binding generator for Rust libraries
Documentation
impl {{ wrapper_name }} {
    /// Create a new bridge wrapping a NAPI Object.
    ///
    /// Validates that the object provides all required methods.
    pub fn new(env: napi::Env, js_obj: napi::bindgen_prelude::Object<'_>) -> napi::Result<Self> {
{%- for method in required_methods %}
        if !js_obj.has_named_property("{{ method.name }}").unwrap_or(false)
            && !js_obj.has_named_property("{{ method.snake_case_name }}").unwrap_or(false) {
            return Err(napi::Error::new(
                napi::Status::GenericFailure,
                format!("Object missing required method: {}", "{{ method.name }}")
            ));
        }
{%- endfor %}
{%- if requires_plugin_name %}
        if !js_obj.has_named_property("name").unwrap_or(false) {
            return Err(napi::Error::new(
                napi::Status::GenericFailure,
                "Object missing required method: name".to_string()
            ));
        }
{%- endif %}

        // Cache the plugin name before wrapping in Reference.
        // Try function form first, then string property.
        let cached_name = js_obj
            .get_named_property::<napi::bindgen_prelude::Function<(), String>>("name")
            .and_then(|f| f.call(()))
            .or_else(|_| js_obj.get_named_property::<String>("name"))
{%- if requires_plugin_name %}
            .map_err(|e| napi::Error::new(
                napi::Status::GenericFailure,
                format!("Object missing required method: name ({e})")
            ))?;
{%- else %}
            .unwrap_or_default();
{%- endif %}

        // Wrap the JS object in a Reference to safely pin it to the V8 heap
        // across method calls. References are tied to the Node.js runtime
        // and cannot be garbage collected while held.
        let inner = env.create_reference(js_obj)?;

        Ok(Self {
            inner,
            cached_name,
        })
    }

    /// Extract napi::Env from the stored Reference.
    fn env(&self) -> napi::Result<napi::Env> {
        // get_napi_env() is available on napi::Reference
        self.inner.get_napi_env()
    }
}

// SAFETY: The bridge holds an napi::Reference which is thread-safe within
// the Node.js runtime. All access occurs on the event loop thread.
// Send+Sync are required by the Plugin trait.
unsafe impl Send for {{ wrapper_name }} {}
unsafe impl Sync for {{ wrapper_name }} {}