uniffi-bindgen-js 0.2.1

TypeScript/JavaScript bindings generator for UniFFI
Documentation
// ---------------------------------------------------------------------------
// Internal IR types for bindings generation
// ---------------------------------------------------------------------------

use uniffi_bindgen::interface::{DefaultValue, Literal, Type};

/// The crate name sentinel used when parsing UDL via `ComponentInterface::from_webidl`.
/// All local types will have a `module_path` whose first `::` segment equals this value.
/// External types declared with `[External="crate_name"]` will differ.
pub(super) const LOCAL_CRATE_SENTINEL: &str = "crate_name";

#[derive(Debug)]
pub(super) struct FnDef {
    pub name: String,
    pub args: Vec<ArgDef>,
    pub return_type: Option<Type>,
    pub throws_type: Option<Type>,
    pub is_async: bool,
    pub docstring: Option<String>,
}

#[derive(Debug)]
pub(super) struct ArgDef {
    pub name: String,
    pub type_: Type,
    pub default: Option<DefaultValue>,
}

/// A variant field (used in rich error variants and data enum variants),
/// or a record field (used in dictionary declarations).
#[derive(Debug)]
pub(super) struct FieldDef {
    pub name: String,
    pub type_: Type,
    pub docstring: Option<String>,
    pub default: Option<DefaultValue>,
}

/// One variant of an enum or error type.
#[derive(Debug)]
pub(super) struct VariantDef {
    pub name: String,
    /// Empty for flat variants (no associated data).
    pub fields: Vec<FieldDef>,
    pub docstring: Option<String>,
    /// Explicit discriminant value (e.g. `= 10`), if declared.
    pub discr: Option<Literal>,
}

/// A [Error] enum — generates a TypeScript error class.
#[derive(Debug)]
pub(super) struct ErrorDef {
    pub name: String,
    pub variants: Vec<VariantDef>,
    pub is_flat: bool,
    pub is_non_exhaustive: bool,
    pub docstring: Option<String>,
    /// Methods declared on the error enum.
    pub methods: Vec<MethodDef>,
    /// Constructors declared on the error enum (proc-macro only).
    pub constructors: Vec<CtorDef>,
}

/// A plain enum or [Enum] interface — generates a TypeScript union type.
#[derive(Debug)]
pub(super) struct EnumDef {
    pub name: String,
    pub variants: Vec<VariantDef>,
    /// true ↔ all variants are unit variants (no fields); serialises as a string.
    pub is_flat: bool,
    pub is_non_exhaustive: bool,
    pub docstring: Option<String>,
    /// Methods declared on the enum (from `impl` blocks).
    pub methods: Vec<MethodDef>,
    /// Constructors declared on the enum (proc-macro only).
    pub constructors: Vec<CtorDef>,
    /// Synthesised trait methods.
    pub traits: SynthesisedTraits,
}

/// Synthesised trait methods (Display, Debug, Eq, Hash, Ord).
#[derive(Debug, Default)]
pub(super) struct SynthesisedTraits {
    /// Method name for Display::fmt (produces `toString()`).
    pub display: Option<String>,
    /// Method name for Debug::fmt (produces `toDebugString()`).
    pub debug: Option<String>,
    /// Method name for PartialEq::eq (produces `equals(other)`).
    pub eq: Option<String>,
    /// Method name for Hash::hash (produces `hashCode()`).
    pub hash: Option<String>,
    /// Method name for Ord::cmp (produces `compareTo(other)`).
    pub ord: Option<String>,
}

/// A `dictionary` declaration — generates a TypeScript interface.
#[derive(Debug)]
pub(super) struct RecordDef {
    pub name: String,
    pub fields: Vec<FieldDef>,
    pub docstring: Option<String>,
    /// Methods declared on the record (from `impl` blocks, proc-macro only).
    pub methods: Vec<MethodDef>,
    /// Constructors declared on the record (proc-macro only).
    pub constructors: Vec<CtorDef>,
    /// Synthesised trait methods.
    pub traits: SynthesisedTraits,
}

/// A constructor of an `interface` object.
#[derive(Debug)]
pub(super) struct CtorDef {
    /// Exported name in JS.  Usually "new".
    pub name: String,
    pub args: Vec<ArgDef>,
    pub throws_type: Option<Type>,
    pub is_async: bool,
    pub docstring: Option<String>,
}

/// A method on an `interface` object.
#[derive(Debug)]
pub(super) struct MethodDef {
    pub name: String,
    pub args: Vec<ArgDef>,
    pub return_type: Option<Type>,
    pub throws_type: Option<Type>,
    pub is_async: bool,
    pub docstring: Option<String>,
}

/// An `interface` declaration — generates a TypeScript class.
#[derive(Debug)]
pub(super) struct ObjectDef {
    pub name: String,
    pub constructors: Vec<CtorDef>,
    pub methods: Vec<MethodDef>,
    pub docstring: Option<String>,
    /// True when this object is used as a `[Throws=...]` error type.
    pub is_error: bool,
    /// True for `[Trait]` interfaces (abstract, no direct constructors).
    pub is_trait: bool,
    /// Synthesised trait methods (Display, Debug, Eq, Hash, Ord).
    pub traits: SynthesisedTraits,
}

/// A `[Custom]` typedef — generates a TypeScript type alias.
#[derive(Debug)]
pub(super) struct CustomTypeDef {
    /// The custom type name (e.g. `Url`).
    pub name: String,
    /// The underlying builtin type (e.g. `Type::String`).
    pub builtin: Type,
    /// The `module_path` from the source `Type::Custom` — used to detect external custom types.
    pub module_path: String,
}

/// A method on a `callback interface` — generates a method signature in a TS interface.
///
/// `throws_type` is intentionally omitted: TypeScript interfaces have no `throws`
/// annotation syntax, so there is nothing to emit. Errors flow outward from the JS
/// implementor into Rust; the TypeScript interface only describes the return type.
///
/// `is_async` IS expressible in UDL (`[Async]` on a callback method). The generator
/// emits `Promise<T>` for the method return type, which is the correct TypeScript
/// contract. The async callback is polled via the RustFuture mechanism.
#[derive(Debug)]
pub(super) struct CallbackMethodDef {
    pub name: String,
    pub args: Vec<ArgDef>,
    pub return_type: Option<Type>,
    pub is_async: bool,
    pub docstring: Option<String>,
}

/// A `callback interface` declaration — generates a TypeScript interface.
#[derive(Debug)]
pub(super) struct CallbackInterfaceDef {
    pub name: String,
    pub methods: Vec<CallbackMethodDef>,
    pub docstring: Option<String>,
}

#[derive(Debug)]
pub(super) struct BindingsMetadata {
    pub namespace: String,
    pub namespace_docstring: Option<String>,
    /// The module_path prefix for types local to this crate.
    /// For UDL mode this is `LOCAL_CRATE_SENTINEL`; for library mode it is the actual crate name.
    pub local_crate: String,
    /// The FFI namespace used in exported symbol names (`ffi_{ffi_namespace}_rustbuffer_alloc`, etc.).
    /// This is the crate name (matching `mod_path()` in `setup_scaffolding!`), NOT the user-facing
    /// namespace. Upstream uniffi-bindgen calls this `ffi_namespace` and derives it from `crate_name`.
    pub ffi_namespace: String,
    pub functions: Vec<FnDef>,
    pub errors: Vec<ErrorDef>,
    pub enums: Vec<EnumDef>,
    pub records: Vec<RecordDef>,
    pub objects: Vec<ObjectDef>,
    pub custom_types: Vec<CustomTypeDef>,
    pub callback_interfaces: Vec<CallbackInterfaceDef>,
}

impl Default for BindingsMetadata {
    fn default() -> Self {
        Self {
            namespace: String::new(),
            namespace_docstring: None,
            local_crate: LOCAL_CRATE_SENTINEL.to_string(),
            ffi_namespace: LOCAL_CRATE_SENTINEL.to_string(),
            functions: Vec::new(),
            errors: Vec::new(),
            enums: Vec::new(),
            records: Vec::new(),
            objects: Vec::new(),
            custom_types: Vec::new(),
            callback_interfaces: Vec::new(),
        }
    }
}