schema-bridge

Crates.ioschema-bridge
lib.rsschema-bridge
version0.3.0
created_at2025-11-21 14:03:46.089657+00
updated_at2025-11-24 00:46:02.139441+00
descriptionGenerate TypeScript type definitions from Rust types - perfect for Tauri applications
homepage
repositoryhttps://github.com/ynishi/tauri-schema
max_upload_size
id1943604
size19,595
Yutaka Nishimura (ynishi)

documentation

README

schema-bridge

A minimal, practical Rust library for generating TypeScript type definitions from Rust types.

Features

  • Simple to use: Just derive SchemaBridge on your types
  • Serde compatible: Works with serde attributes
  • Minimal dependencies: No heavy tooling required
  • Workspace friendly: Organized as a clean workspace

Quick Start

Add to your Cargo.toml:

[dependencies]
schema-bridge = { path = "path/to/schema-bridge/crates/schema-bridge" }
serde = { version = "1.0", features = ["derive"] }

Define your types and export them:

use schema_bridge::{SchemaBridge, export_types};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, SchemaBridge)]
struct User {
    name: String,
    age: i32,
    email: Option<String>,
}

#[derive(Serialize, Deserialize, SchemaBridge)]
enum Status {
    Active,
    Inactive,
}

fn main() {
    // Easy export with the macro!
    export_types!("bindings.ts", User, Status).unwrap();
}

This generates bindings.ts:

// This file is auto-generated by schema-bridge

export type User = { name: string; age: number; email: string | null; };

export type Status = 'Active' | 'Inactive';

Architecture

The library is structured as a workspace with three crates:

  • schema-bridge: Main entry point (facade)
  • schema-bridge-core: Core traits and types
  • schema-bridge-macro: Procedural macro for #[derive(SchemaBridge)]

This follows the pattern used by popular libraries like serde.

Supported Types

  • Primitives: String, i32, f64, bool, etc.
  • Containers: Vec<T>, Option<T>
  • Structs with named fields
  • Enums (simple variants)
  • Newtype pattern: struct Wrapper(InnerType) - delegates to wrapped type
  • Tuple structs: struct Point(f64, f64) - generates TypeScript tuples
  • Serde attributes: #[serde(rename_all = "...")] for name transformations

Serde Attribute Support

The library respects #[serde(rename_all)] attributes on enums:

#[derive(Serialize, Deserialize, SchemaBridge)]
#[serde(rename_all = "snake_case")]
enum ConversationMode {
    Normal,      // → 'normal'
    Concise,     // → 'concise'
    Creative,    // → 'creative'
}

Supported transformations:

  • snake_case: MyVariantmy_variant
  • camelCase: MyVariantmyVariant
  • PascalCase: MyVariantMyVariant (no change)
  • SCREAMING_SNAKE_CASE: MyVariantMY_VARIANT
  • kebab-case: MyVariantmy-variant

String Conversion Support

Generate Display and FromStr implementations for easy string conversion:

#[derive(SchemaBridge)]
#[schema_bridge(string_conversion)]  // Enable Display + FromStr
#[serde(rename_all = "snake_case")]
enum TalkStyle {
    Brainstorm,
    Casual,
}

// Usage:
let style = TalkStyle::Brainstorm;
let s = style.to_string();  // "brainstorm"
let parsed: TalkStyle = "casual".parse().unwrap();  // TalkStyle::Casual

Perfect for:

  • String-based APIs
  • Command-line arguments
  • Configuration parsing
  • URL parameters

Newtype Pattern for External Types

Perfect for wrapping external types you don't control:

// Wrap an external enum
#[derive(Serialize, Deserialize, SchemaBridge)]
struct MyStatus(external_crate::Status);

// Wrap a primitive for type safety
#[derive(Serialize, Deserialize, SchemaBridge)]
struct UserId(String);  // Generates: export type UserId = string;

Use with Tauri

Perfect for Tauri applications where you need to keep Rust and TypeScript types in sync:

// In build.rs or a separate build tool
use schema_bridge::export_types;

fn main() {
    // Simple one-liner to export all your types!
    export_types!("../src/bindings.ts", AppConfig, UserData, TalkStyle).unwrap();
}

Or for more control:

use schema_bridge::{SchemaBridge, generate_ts_file};

fn main() {
    let types = vec![
        ("AppConfig", AppConfig::to_ts()),
        ("UserData", UserData::to_ts()),
    ];
    
    let ts_content = generate_ts_file(types);
    std::fs::write("../src/bindings.ts", ts_content)?;
}

License

MIT OR Apache-2.0

Commit count: 0

cargo fmt