1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! Generate TypeScript type definitions for Rust types. //! //! This crate allows you to produce a TypeScript module containing type //! definitions which describe the JSON serialization of Rust types. The //! intended use is to define TypeScript types for data that is serialized from //! Rust types as JSON using [`serde_json`](https://docs.rs/serde_json/) so it //! can be safely used from TypeScript without needing to maintain a parallel //! set of type definitions. //! //! One example of where this crate is useful is when working on a web //! application project with a Rust backend and a TypeScript frontend. If the //! data used to communicate between the two is defined in Rust and uses //! [`serde_json`](https://docs.rs/serde_json/) to encode/decode it for //! transmission across the network, you can use this crate to automatically //! generate a TypeScript definition file for those types in order to use them //! safely in your frontend code. This process can even be completely automated //! if you use this crate in a //! [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) //! for your server to write the definition file to your TypeScript source code //! directory. //! //! # Examples //! //! Simple example: //! ``` //! use serde::Serialize; //! use typescript_type_def::{write_definition_file, TypeDef}; //! //! #[derive(Serialize, TypeDef)] //! struct Foo { //! a: usize, //! b: String, //! } //! //! let ts_module = { //! let mut buf = Vec::new(); //! write_definition_file::<_, Foo>(&mut buf, Default::default()).unwrap(); //! String::from_utf8(buf).unwrap() //! }; //! assert_eq!( //! ts_module, //! r#"// AUTO-GENERATED by typescript-type-def //! //! export default types; //! export namespace types{ //! export type Usize=number; //! export type Foo={"a":types.Usize;"b":string;}; //! } //! "# //! ); //! //! let foo = Foo { //! a: 123, //! b: "hello".to_owned(), //! }; //! let json = serde_json::to_string(&foo).unwrap(); //! // This JSON matches the TypeScript type definition above //! assert_eq!(json, r#"{"a":123,"b":"hello"}"#); //! ``` //! //! When working with a large codebase consisting of many types, a useful //! pattern is to declare an "API" type alias which lists all the types you want //! to make definitions for. For example: //! ``` //! use serde::Serialize; //! use typescript_type_def::{write_definition_file, TypeDef}; //! //! #[derive(Serialize, TypeDef)] //! struct Foo { //! a: String, //! } //! //! #[derive(Serialize, TypeDef)] //! struct Bar { //! a: String, //! } //! //! #[derive(Serialize, TypeDef)] //! struct Baz { //! a: Qux, //! } //! //! #[derive(Serialize, TypeDef)] //! struct Qux { //! a: String, //! } //! //! // This type lists all the top-level types we want to make definitions for. //! // You don't need to list *every* type in your API here, only ones that //! // wouldn't be referenced otherwise. Note that `Qux` is not mentioned, but //! // is still emitted because it is a dependency of `Baz`. //! type Api = (Foo, Bar, Baz); //! //! let ts_module = { //! let mut buf = Vec::new(); //! write_definition_file::<_, Api>(&mut buf, Default::default()).unwrap(); //! String::from_utf8(buf).unwrap() //! }; //! assert_eq!( //! ts_module, //! r#"// AUTO-GENERATED by typescript-type-def //! //! export default types; //! export namespace types{ //! export type Foo={"a":string;}; //! export type Bar={"a":string;}; //! export type Qux={"a":string;}; //! export type Baz={"a":types.Qux;}; //! } //! "# //! ); //! ``` #![warn(rust_2018_idioms, clippy::all, missing_docs)] #![deny(clippy::correctness)] mod emit; mod impls; mod iter_refs; pub mod type_expr; pub use crate::{ emit::{write_definition_file, DefinitionFileOptions, Stats, TypeDef}, impls::Blob, }; /// A derive proc-macro for the [`TypeDef`] trait. /// /// This macro can be used on `struct`s and `enum`s which also derive /// [`serde::Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) /// and/or /// [`serde::Deserialize`](https://docs.rs/serde/latest/serde/trait.Deserialize.html), /// and will generate a [`TypeDef`] implementation which matches the shape /// of the JSON produced by using [`serde_json`](https://docs.rs/serde_json/) on /// the target type. This macro will also read and adapt to `#[serde(...)]` /// attributes on the target type's definition. /// /// This macro also reads the following attributes: /// * `#[type_def(namespace = "x.y.z")]` on the `struct`/`enum` body puts /// the TypeScript type definition under a namespace of `x.y.z`. Note /// that [`write_definition_file`] will additionally place all type /// definitions under a root namespace (by default named `types`). pub use typescript_type_def_derive::TypeDef;