$ show madonoharu/tsify
tsify is a Rust library that generates TypeScript type declarations from Rust types, primarily for the wasm-bindgen ecosystem. The core mechanism is a `#[derive(Tsify)]` proc macro that produces a `Tsify` trait impl whose `DECL` constant is emitted into the wasm-bindgen `typescript_custom_section`, so `wasm-pack` automatically appends the generated `.d.ts` alongside the JS output. It maps Rust structs, enums, and type aliases to TypeScript interfaces, type aliases, namespaces, and unions, respecting serde attributes (`rename`, `tag`, `untagged`, `flatten`, `skip`, `default`, `transparent`) and offering tsify-specific overrides (`type`, `type_params`, `type_prefix`/`type_suffix`, `rename`, `namespace`, and serializer options like `missing_as_null` / `hashmap_as_object` / `large_number_types_as_bigints`). A second runtime type, `Ts<T>`, provides a memory-safe alternative to the deprecated `into_wasm_abi`/`from_wasm_abi` attributes by deferring deserialization out of the infallible ABI boundary into the function body, avoiding the destructor-skipping `throw_str` leak path.
The LLM identified 5 files worth highlighting for reuse:
The Ts<T> wrapper is a #[repr(transparent)] type that keeps the wasm ABI boundary infallible by forwarding only the raw JsValue across it and performing serde conversion inside the function body as an ordinary Result. It delegates every wasm-bindgen conversion trait (IntoWasmAbi, FromWasmAbi, OptionIntoWasmAbi/FromWasmAbi, RefFromWasmAbi, LongRefFromWasmAbi, VectorIntoWasmAbi/VectorFromWasmAbi, WasmDescribe, WasmDescribeVector) to the inner JsType, with careful ManuallyDrop anchoring for borrowed arguments and an explicit decision not to clone the JS handle table slot when crossing as a reference. This is a directly reusable pattern for any Rust-to-JS library that needs fallible serialization without memory leaks.
A resumable, idempotent release orchestrator for the dual-crate (root + proc-macro) workspace. It verifies that a published crate actually came from the exact current HEAD by downloading the crates.io tarball and reading .cargo_vcs_info.json, rejecting dirty-tree or foreign-commit provenance; checks that the root manifest's tsify-macros version floor matches the release version (the mechanism 0.5.7 almost shipped broken); validates feature forwarding; runs cargo publish --dry-run; and waits for the sparse index to propagate before tagging. Notable craft includes two-bucket failure classification, phase reporting via trap, and comments marking every non-obvious shell behavior as 'measured:'.
A shared extraction routine (include!d by both build.rs and an integration test) that pulls the README's Rust quickstart block out of a Markdown section and compiles that exact block as the e2e crate, while a companion test asserts the generated .d.ts equals the TypeScript block the README prints beneath it. The documentation example physically cannot drift from the code without failing CI. It handles CRLF checkouts via normalization and validates section boundaries so a renamed fence or a block in a later section fails loudly. This 'compile the docs' pattern is reusable for any project that promises runnable examples.
The Rust-to-TypeScript type mapper, notable for arity-guarded special cases: Range/RangeInclusive only render as {start; end} when they carry exactly one type argument, so a user-defined type named Range is not silently replaced; ByteBuf, HashMap, Option, Result, Duration, SystemTime and the Fn family are likewise guarded, and the output shape respects feature flags and per-container serializer config (undefined vs null, Map vs Record, bigint vs number). The non-obvious insight — builtin mappings must match on the full generic signature, not just the terminal identifier — is exactly the fix that prevents the name-collision class of bugs documented in tests-e2e/test_name_collision1.
A self-contained harness that creates a temp crate on the fly with a path dependency on the crate under test, runs cargo check --offline against it, then asserts each expected rustc diagnostic appears with the exact error message and source location, normalizing Windows path separators so the same fixture passes on both platforms. It validates ten invalid attribute combinations (duplicate rename, invalid identifiers, conflicting with prefix/suffix) in one cargo invocation. This is a reusable pattern for testing proc-macro diagnostics end-to-end without a trybuild dependency.