libgraphql_macros/lib.rs
1mod emittable_schema;
2mod graphql_schema_from_str_token_consumer;
3mod graphql_schema_token_consumer;
4mod parse_error_converter;
5mod rust_macro_graphql_token_source;
6mod span_map;
7
8#[cfg(test)]
9mod tests;
10
11use crate::graphql_schema_token_consumer::GraphQLSchemaTokenConsumer;
12use crate::graphql_schema_from_str_token_consumer::GraphQLSchemaFromStrTokenConsumer;
13
14/// Evaluates to a [`Schema`](libgraphql_core::schema::Schema) object given
15/// direct GraphQL schema document syntax.
16///
17/// This macro is effectively a compile-time version of
18/// [`SchemaBuilder::build_from_str()`](libgraphql_core::schema::SchemaBuilder::build_from_ast()),
19/// except you write GraphQL syntax in your Rust file and the macro parses it as
20/// GraphQL for you.
21///
22/// Example usage:
23///
24/// ```rust
25/// use libgraphql::macros::graphql_schema;
26///
27/// let schema = graphql_schema! {
28/// type Query {
29/// // This field always resolves the currently-authenticated `User`.
30/// me: User,
31/// }
32///
33/// type User {
34/// firstName: String,
35/// lastName: String,
36/// }
37/// };
38///
39/// let user_type =
40/// schema.defined_types()
41/// .get("User")
42/// .unwrap()
43/// .as_object()
44/// .unwrap();
45///
46/// assert_eq!(user_type.name(), "User");
47/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
48/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
49/// assert_eq!(user_type.fields().get("doesntExist").is_some(), false);
50/// ```
51///
52/// ## **⚠️ NOTE:**
53///
54/// Due to limitations downstream of how Rust macros tokenize syntax, there
55/// are a few inline GraphQL syntax edge-cases that are not supported by this
56/// macro:
57///
58/// 1) `#` cannot be used to specify GraphQL comments. Instead, you can use
59/// Rust's `//` or `/*` comment syntax.
60///
61/// So for example, this won't compile:
62///
63/// ```rust,compile_fail
64/// let schema = graphql_schema! {
65/// type Query {
66/// me: User,
67/// }
68///
69/// ## Represents a user in the system.
70/// type User {
71/// firstName: String,
72/// lastName: String,
73/// }
74/// };
75/// ```
76///
77/// But you can use rust's `//` and `/*` comment syntax instead:
78/// ```rust
79/// # use libgraphql::macros::graphql_schema;
80/// let schema = graphql_schema! {
81/// type Query {
82/// me: User,
83/// }
84///
85/// // Represents a user in the system.
86/// type User {
87/// /* The user's first name. */
88/// firstName: String,
89///
90/// /* The user's last name. */
91/// lastName: String,
92/// }
93/// };
94/// ```
95///
96/// 2) Block-quoted strings (`"""`) *are* supported, but if you need to
97/// nest a quoted string /within/ a block-quoted string, you must
98/// escape the inner quotes with `\"`. This is because Rust's
99/// tokenizer treats unescaped `"` as string delimiters, which
100/// breaks the block string recombination.
101///
102/// So for example, this won't compile:
103/// ```rust,compile_fail
104/// let schema = graphql_schema! {
105/// type Query {
106/// me: User,
107/// }
108///
109/// type User {
110/// """
111/// The user's "primary" address.
112/// """
113/// address: String,
114/// }
115/// };
116/// ```
117///
118/// But the workaround is to escape the inner quotes:
119/// ```rust
120/// # use libgraphql::macros::graphql_schema;
121/// let schema = graphql_schema! {
122/// type Query {
123/// me: User,
124/// }
125///
126/// type User {
127/// """
128/// The user's \"primary\" address.
129/// """
130/// address: String,
131/// }
132/// };
133/// ```
134#[proc_macro]
135pub fn graphql_schema(
136 input: proc_macro::TokenStream,
137) -> proc_macro::TokenStream {
138 GraphQLSchemaTokenConsumer::new(input).into()
139}
140
141/// Evaluates to a [`Schema`](libgraphql_core::schema::Schema) object given a literal
142/// Rust `str` containing GraphQL document text that represents a GraphQL
143/// schema.
144///
145/// This macro is effectively a compile-time version of
146/// [`SchemaBuilder::build_from_str()`](libgraphql_core::schema::SchemaBuilder::build_from_str()).
147///
148/// Example usage:
149///
150/// ```rust
151/// use libgraphql::macros::graphql_schema_from_str;
152///
153/// let schema = graphql_schema_from_str!(r#"
154/// type Query {
155/// me: User,
156///
157/// }
158///
159/// type User {
160/// firstName: String,
161/// lastName: String,
162/// }
163/// "#r);
164///
165/// let user_type =
166/// schema.defined_types()
167/// .get("User")
168/// .unwrap()
169/// .as_object()
170/// .unwrap();
171///
172/// assert_eq!(user_type.name(), "User");
173/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
174/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
175/// assert_eq!(user_type.fields().get("doesntExist").is_some(), false);
176/// ```
177#[proc_macro]
178pub fn graphql_schema_from_str(
179 input: proc_macro::TokenStream,
180) -> proc_macro::TokenStream {
181 GraphQLSchemaFromStrTokenConsumer::new(input).into()
182}