Skip to content

Frank-III/convex-rescript-codegen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

convex-rescript-codegen

Generate type-safe ReScript bindings from your Convex backend functions. This tool parses your Convex TypeScript code using the TypeScript AST and generates idiomatic ReScript modules with proper types and React hooks.

✨ Features

  • 🎯 Type-safe bindings - Generates fully typed ReScript modules from Convex functions
  • πŸ”„ React hooks - Ready-to-use useQuery and useMutation hooks
  • πŸ“¦ Schema support - Parses Convex schema to generate document types
  • πŸ” AST-based parsing - Uses TypeScript compiler API for accurate parsing
  • ⚑ Blazing fast - Powered by Bun runtime (10x faster than Node.js)
  • πŸ‘οΈ Watch mode - Auto-regenerate on file changes with @parcel/watcher
  • 🎨 Idiomatic ReScript - Generates clean, idiomatic ReScript code
  • πŸ›‘οΈ Edge case handling - Handles reserved keywords, polymorphic variants

πŸ“¦ Installation

This package is designed to run with Bun for best performance:

# Recommended: Install with Bun
bun add -D convex-rescript-codegen

# Also works with npm/yarn/pnpm (requires Bun runtime)
npm install -D convex-rescript-codegen

Note: This package requires Bun runtime to be installed on your system.

πŸš€ Quick Start

  1. Install Bun if you haven't already:
curl -fsSL https://bun.sh/install | bash
  1. Add to your package.json scripts:
{
  "scripts": {
    "codegen": "bunx convex-rescript",
    "codegen:watch": "bunx convex-rescript --watch"
  }
}
  1. Run the generator:
bun run codegen
# or directly with
bunx convex-rescript
  1. Use the generated bindings:
// Your generated bindings are in src/bindings/generated/
open ConvexTypes

@react.component
let make = () => {
  // Use generated query hook
  let users = Convex_users.Query_list.use(~limit=Some(JSON.Encode.int(10)))
  
  // Use generated mutation hook
  let createUser = Convex_users.Mutation_create.use()
  
  // Type-safe function calls
  let handleCreate = async () => {
    let userId = await createUser({
      name: "Alice",
      email: "alice@example.com"
    })
    Console.log2("Created:", userId)
  }
  
  // Render your UI...
}

πŸ“ Generated File Structure

src/bindings/generated/
β”œβ”€β”€ ConvexTypes.res       # Document types from schema
β”œβ”€β”€ ConvexBindings.res    # Core Convex React bindings
β”œβ”€β”€ ConvexGenerated.res   # Module exports
β”œβ”€β”€ Convex_users.res      # Bindings for users.ts
β”œβ”€β”€ Convex_rooms.res      # Bindings for rooms.ts
└── Convex_messages.res   # Bindings for messages.ts

πŸ”§ Configuration

Command Line Options

convex-rescript [options]

Options:
  -i, --input <path>    Input directory (default: ./convex)
  -o, --output <path>   Output directory (default: ./src/bindings/generated)
  -w, --watch           Watch for changes
  -v, --verbose         Verbose output
  -h, --help            Show help

Examples

# Basic usage (uses defaults)
convex-rescript

# Watch mode
convex-rescript --watch

# Custom paths
convex-rescript -i ./backend/convex -o ./frontend/src/bindings

# Verbose output for debugging
convex-rescript --verbose

πŸ“ Type Mappings

Convex Type ReScript Type
v.string() string
v.number() float
v.boolean() bool
v.null() unit
v.id("table") tableId (e.g., usersId)
v.optional(...) option<...>
v.array(...) array<...>
v.object(...) JSON.t
v.any() JSON.t
v.union(...) Polymorphic variants
v.literal(...) Polymorphic variants

🎯 Generated Code Examples

Query with no arguments

module Query_list = {
  type output = array<usersDoc>
  
  @module("convex/react")
  external useQuery: ('api, unit) => option<output> = "useQuery"
  
  let use = () => {
    useQuery(api["users"]["list"], ())
  }
}

Query with arguments

module Query_getById = {
  type input = {
    userId: usersId,
  }
  type output = option<usersDoc>
  
  @module("convex/react")
  external useQuery: ('api, input) => option<output> = "useQuery"
  
  let use = (~userId) => {
    useQuery(api["users"]["getById"], {
      userId: userId
    })
  }
}

Mutation

module Mutation_create = {
  type input = {
    name: string,
    email: string,
    avatar: option<string>,
  }
  type t = input => promise<usersId>
  
  @module("convex/react")
  external useMutation: 'api => t = "useMutation"
  
  let use = () => {
    useMutation(api["users"]["create"])
  }
}

Document Types from Schema

type usersDoc = {
  @as("_id") id: usersId,
  @as("_creationTime") creationTime: float,
  name: string,
  email: string,
  avatar: option<string>,
  status: [| #online | #offline | #away],
  lastSeen: float,
  createdAt: float,
}

πŸ›‘οΈ Edge Case Handling

Reserved Keywords

The generator automatically escapes ReScript reserved keywords:

  • type β†’ type_ with @as("type")
  • private β†’ #"private" in polymorphic variants

Polymorphic Variants

Convex string unions are converted to ReScript polymorphic variants:

// Convex
status: v.union(
  v.literal("online"),
  v.literal("offline"),
  v.literal("away")
)
// ReScript
status: [| #online | #offline | #away]

🀝 Requirements

  • Bun runtime 1.0+ (required) - Install Bun
  • ReScript v11+ (tested with v12 RC)
  • Convex backend with TypeScript functions
  • React project (for the generated hooks)

πŸ› Known Limitations

  1. Complex nested types - Very complex nested object types default to JSON.t
  2. Function return types - Currently infers common patterns, not all return types
  3. Convex validators - Complex validator compositions may not be fully supported
  4. Actions - Limited support for Convex actions (treated similar to mutations)

🚧 Roadmap

  • Full return type inference from function implementations
  • Support for Convex HTTP endpoints
  • Custom type mapping configuration
  • Generate mock data for testing
  • VS Code extension for instant generation
  • Support for convex-helpers library patterns

πŸ“„ License

MIT

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ™ Acknowledgments

  • Built for the ReScript and Convex communities
  • Inspired by GraphQL Code Generator and similar tools
  • Uses ts-morph for robust TypeScript AST parsing

πŸ“š Resources


Made with ❀️ for type-safe full-stack development

About

Generate type-safe ReScript bindings from Convex backend functions

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published