Expand description
§rkyv-js-codegen
TypeScript codec-binding generator for rkyv types, targeting the rkyv-js runtime.
The generator parses Rust sources with syn,
extracts every type marked with #[derive(Archive)] (or a custom marker),
and emits one export const Archived{Name} = ... codec per type.
TypeScript types are always derived from the codecs via r.Infer<typeof Archived{Name}>.
§build.rs
use rkyv_js_codegen::CodeGenerator;
fn main() -> Result<(), rkyv_js_codegen::Error> {
CodeGenerator::new()
.add_source_file("src/lib.rs")?
.write_to_file("generated/bindings.ts")?;
println!("cargo:rerun-if-changed=src/lib.rs");
Ok(())
}§Source extraction
add_source_file,
add_source_dir (recursive), and
add_source_str all extract every type carrying the marker derive.
use imports are resolved to fully-qualified paths — aliases and globs included —
so registry lookups never depend on local names:
use rkyv_js_codegen::CodeGenerator;
let mut generator = CodeGenerator::new();
generator.add_source_str(r#"
use rkyv::Archive;
#[derive(Archive)]
pub struct Point { pub x: f64, pub y: f64 }
"#)?;
assert_eq!(generator.archived_name_of("Point").as_deref(), Some("ArchivedPoint"));#[derive(Archive)] must be resolvable — through use rkyv::Archive, an
alias, a use rkyv::* glob, or an extra marker registered with
add_marker_path.
§Output options
| Method | Effect |
|---|---|
set_header | Replace the generated file’s header comment |
set_archived_name | Override an export name, matching #[rkyv(archived = Name)] |
set_direction | Emit full, decode-only, or encode-only bindings |
set_format | Target a non-default rkyv wire format |
set_jit | Wrap every export in the direction-matched rkyv-js/jit compile function |
set_field_casing | Rewrite field names, e.g. Rust’s snake_case to JavaScript’s camelCase |
set_variant_casing | Rewrite enum variant tags |
allow_typescript_syntax | Drop export type lines, emitting plain JavaScript |
on_unknown_type | Fail, or warn and omit, on unmappable types |
use rkyv_js_codegen::{Casing, CodeGenerator, Direction};
let mut generator = CodeGenerator::new();
generator
.set_direction(Direction::Decode) // imports become `rkyv-js/decode`
.set_format("big", 64, true) // mirrors rkyv's feature flags
.set_field_casing(Casing::Camel) // `created_at` is emitted as `createdAt`
.allow_typescript_syntax(false);Casing is a pure relabelling: rkyv structs are laid out positionally,
so the keys of an emitted r.struct({ ... }) never affect the wire bytes.
Direction rewrites only the rkyv-js import specifiers.
Factory names and type exports are unchanged, and modules registered through
register_external are left alone,
so one schema can produce direction-matched bundles for a browser client and a Rust-facing service.
Emission is deterministic: dependency-ordered, alphabetical within ties, so generated files diff cleanly.
§Expressions instead of format strings
Codec expressions are a typed tree (CodecExpr) with builders that mirror the runtime combinators (codec):
use rkyv_js_codegen::{CodeGenerator, codec};
let mut generator = CodeGenerator::new();
generator.add_struct("Person", [
("name", codec::string()),
("age", codec::u32()),
("email", codec::option(codec::string())),
]);
let code = generator.generate()?;
assert!(code.contains("email: r.option(r.string),"));§Extending the registry
External crate types are registered by fully-qualified Rust path:
use rkyv_js_codegen::{CodeGenerator, CodecExpr, ExternalType, WithWrapper};
let mut generator = CodeGenerator::new();
// `my_crate::MyVec<T>` → `myVec(T)` from a custom module.
generator.register_external(
"my_crate::MyVec",
ExternalType::generic1(|t| {
CodecExpr::call(CodecExpr::import_from("my-package/codecs", "myVec"), [t])
}),
);
// `#[rkyv(with = AsJson)]` fields → a hand-written codec.
generator.register_with(
"AsJson",
WithWrapper::replace(CodecExpr::import_from("./custom.ts", "asJson")),
);§Error handling
Parse failures surface immediately from add_source_*; everything else is validated in CodeGenerator::generate,
which aggregates all Diagnostics into a single Error::Codegen.
Set OnUnknown::SkipContainingType to emit cargo:warnings and omit affected types instead of failing.
Modules§
- codec
- Builders mirroring the
rkyv-jsruntime combinators.
Structs§
- Code
Generator - Collects type definitions — from Rust sources or programmatically — and
generates TypeScript codec bindings for the
rkyv-jsruntime. - Diagnostic
- A single code-generation problem with optional provenance.
- External
Type - A codec template for an external Rust type.
- Import
- A named import contributed by a
CodecExpr::Importnode. - Source
Location - A position in a parsed source file.
- With
Wrapper - A handler for a
#[rkyv(with = W)]field wrapper.
Enums§
- Casing
- The identifier casing of emitted field and variant names.
- Codec
Expr - A TypeScript codec expression.
- Diagnostic
Kind - The kinds of code-generation diagnostics.
- Direction
- Which half of the codec surface the generated bindings target.
- Enum
Variant - An enum variant for
CodeGenerator::add_enum. - Error
- Top-level error type for the code generator.
- OnUnknown
- How to handle a field whose type cannot be mapped to a codec.
Functions§
- generate_
import_ block - Generate the import block for a set of expressions.