cynic_proc_macros/
lib.rs

1//! Procedural macros for cynic
2
3#![allow(clippy::let_and_return)]
4#![warn(missing_docs)]
5
6// extern crate proc_macro;
7
8use darling::{ast::NestedMeta, Error};
9use proc_macro::TokenStream;
10
11use cynic_codegen::{
12    enum_derive, fragment_derive, inline_fragments_derive, input_object_derive,
13    query_variable_literals_derive, query_variables_derive, scalar_derive, schema_for_derives,
14    schema_module_attr, use_schema,
15};
16
17/// Imports a schema for use by cynic.
18///
19/// This creates all the required type markers & selection builder structures
20/// required to use cynic with a given schema.  It should usually be called
21/// in a module named schema, as the only statement in that module
22///
23/// ```rust,ignore
24/// mod schema {
25///     cynic::use_schema!("../schemas/starwars.schema.graphql");
26/// }
27/// ```
28#[proc_macro]
29pub fn use_schema(input: TokenStream) -> TokenStream {
30    let input = syn::parse_macro_input!(input as use_schema::UseSchemaParams);
31
32    let rv = use_schema::use_schema(input).unwrap().into();
33
34    //eprintln!("{}", rv);
35
36    rv
37}
38
39/// Derives `cynic::QueryFragment`
40///
41/// See [the book for usage details](https://cynic-rs.dev/derives/query-fragments.html)
42#[proc_macro_derive(QueryFragment, attributes(cynic, arguments, directives))]
43pub fn query_fragment_derive(input: TokenStream) -> TokenStream {
44    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
45
46    let rv = match fragment_derive::fragment_derive(&ast) {
47        Ok(tokens) => tokens.into(),
48        Err(e) => e.to_compile_error().into(),
49    };
50
51    //eprintln!("{}", rv);
52
53    rv
54}
55
56/// Derives `cynic::QueryVariables`
57///
58/// See [the book for usage details](https://cynic-rs.dev/derives/query-fragments.html#passing-arguments)
59#[proc_macro_derive(QueryVariables, attributes(cynic))]
60pub fn query_variables_derive(input: TokenStream) -> TokenStream {
61    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
62
63    let rv = match query_variables_derive::query_variables_derive(&ast) {
64        Ok(tokens) => tokens.into(),
65        Err(e) => e.to_compile_error().into(),
66    };
67
68    rv
69}
70
71/// Derives `cynic::QueryVariableLiterals`
72#[proc_macro_derive(QueryVariableLiterals, attributes(cynic))]
73pub fn query_variable_literals_derive(input: TokenStream) -> TokenStream {
74    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
75
76    let rv = match query_variable_literals_derive::query_variable_literals_derive(&ast) {
77        Ok(tokens) => tokens.into(),
78        Err(e) => e.to_compile_error().into(),
79    };
80
81    rv
82}
83
84/// Derives `cynic::InlineFragments`
85///
86/// See [the book for usage details](https://cynic-rs.dev/derives/inline-fragments.html)
87#[proc_macro_derive(InlineFragments, attributes(cynic))]
88pub fn inline_fragments_derive(input: TokenStream) -> TokenStream {
89    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
90
91    let rv = match inline_fragments_derive::inline_fragments_derive(&ast) {
92        Ok(tokens) => tokens.into(),
93        Err(e) => e.to_compile_errors().into(),
94    };
95
96    //eprintln!("{}", rv);
97
98    rv
99}
100
101/// Derives `cynic::Enum`
102///
103/// See [the book for usage details](https://cynic-rs.dev/derives/enums.html)
104#[proc_macro_derive(Enum, attributes(cynic))]
105pub fn enum_derive(input: TokenStream) -> TokenStream {
106    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
107
108    let rv = match enum_derive::enum_derive(&ast) {
109        Ok(tokens) => tokens.into(),
110        Err(e) => e.to_compile_error().into(),
111    };
112
113    //eprintln!("{}", rv);
114
115    rv
116}
117
118/// Derives `cynic::Scalar`
119///
120/// See [the book for usage details](https://cynic-rs.dev/derives/scalars.html)
121#[proc_macro_derive(Scalar, attributes(cynic))]
122pub fn scalar_derive(input: TokenStream) -> TokenStream {
123    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
124
125    let rv = match scalar_derive::scalar_derive(&ast) {
126        Ok(tokens) => tokens.into(),
127        Err(e) => e.to_compile_error().into(),
128    };
129
130    //eprintln!("{}", rv);
131
132    rv
133}
134
135/// Derives `InputObject`
136///
137/// See [the book for usage details](https://cynic-rs.dev/derives/input-objects.html)
138#[proc_macro_derive(InputObject, attributes(cynic))]
139pub fn input_object_derive(input: TokenStream) -> TokenStream {
140    let ast = syn::parse_macro_input!(input as syn::DeriveInput);
141
142    let rv = match input_object_derive::input_object_derive(&ast) {
143        Ok(tokens) => tokens.into(),
144        Err(e) => e.to_compile_error().into(),
145    };
146
147    //eprintln!("{}", rv);
148
149    rv
150}
151
152/// An attribute macro to automatically add schema attributes to cynic derives.
153///
154/// Most cynic derives take `schema_path` & `query_module` parameters and adding each
155/// of these to every derive can be laborious and verbose.  This attribute provides
156/// a way to avoid repeating yourself quite as much.
157///
158/// See [the book for usage details](https://cynic-rs.dev/derives/schema-for-derives.html)
159#[proc_macro_attribute]
160pub fn schema_for_derives(attrs: TokenStream, input: TokenStream) -> TokenStream {
161    let module = syn::parse_macro_input!(input as syn::ItemMod);
162    let attrs = match NestedMeta::parse_meta_list(attrs.into()) {
163        Ok(v) => v,
164        Err(e) => {
165            return TokenStream::from(Error::from(e).write_errors());
166        }
167    };
168    // let attrs = syn::parse_macro_input!(attrs as syn::AttributeArgs);
169
170    let rv: TokenStream = match schema_for_derives::add_schema_attrs_to_derives(attrs, module) {
171        Ok(tokens) => tokens.into(),
172        Err(e) => e.to_compile_error().into(),
173    };
174
175    // eprintln!("{}", rv);
176
177    rv
178}
179
180#[proc_macro_attribute]
181/// Imports a registered schema into a schema module.
182///
183/// If you have registered a schema in your build.rs, then you can apply
184/// this attribute to a module to import that schema:
185///
186/// ```rust,ignore
187/// #[cynic::schema("starwars")]
188/// mod schema {}
189/// ```
190pub fn schema(attrs: TokenStream, input: TokenStream) -> TokenStream {
191    let schema_name = syn::parse_macro_input!(attrs as syn::LitStr);
192    let mut module = syn::parse_macro_input!(input as syn::ItemMod);
193
194    let rv: TokenStream = match schema_module_attr::attribute_impl(schema_name, &mut module) {
195        Ok(tokens) => tokens.into(),
196        Err(error) => {
197            let error = error.to_compile_error();
198            quote::quote! {
199                #error
200                #module
201            }
202            .into()
203        }
204    };
205
206    // eprintln!("{}", rv);
207
208    rv
209}