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;