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
extern crate proc_macro;
mod attributes;
use failure::ResultExt;
use graphql_client_codegen::{
generate_module_token_stream, CodegenMode, GraphQLClientCodegenOptions,
};
use std::path::{Path, PathBuf};
use proc_macro2::TokenStream;
#[proc_macro_derive(GraphQLQuery, attributes(graphql))]
pub fn derive_graphql_query(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
match graphql_query_derive_inner(input) {
Ok(ts) => ts,
Err(err) => panic!(
"{}",
err.iter_chain()
.fold(String::new(), |mut acc, item| {
acc.push_str(&format!("{}\n", item));
acc
})
.trim_end_matches('\n')
),
}
}
fn graphql_query_derive_inner(
input: proc_macro::TokenStream,
) -> Result<proc_macro::TokenStream, failure::Error> {
let input = TokenStream::from(input);
let ast = syn::parse2(input).context("Derive input parsing.")?;
let (query_path, schema_path) = build_query_and_schema_path(&ast)?;
let options = build_graphql_client_derive_options(&ast, query_path.to_path_buf())?;
Ok(
generate_module_token_stream(query_path, &schema_path, options)
.map(Into::into)
.context("Code generation failed.")?,
)
}
fn build_query_and_schema_path(
input: &syn::DeriveInput,
) -> Result<(PathBuf, PathBuf), failure::Error> {
let cargo_manifest_dir = ::std::env::var("CARGO_MANIFEST_DIR")
.context("Checking that the CARGO_MANIFEST_DIR env variable is defined.")?;
let query_path =
attributes::extract_attr(input, "query_path").context("Extracting query path.")?;
let query_path = format!("{}/{}", cargo_manifest_dir, query_path);
let query_path = Path::new(&query_path).to_path_buf();
let schema_path =
attributes::extract_attr(input, "schema_path").context("Extracting schema path.")?;
let schema_path = Path::new(&cargo_manifest_dir).join(schema_path);
Ok((query_path, schema_path))
}
fn build_graphql_client_derive_options(
input: &syn::DeriveInput,
query_path: PathBuf,
) -> Result<GraphQLClientCodegenOptions, failure::Error> {
let response_derives = attributes::extract_attr(input, "response_derives").ok();
let mut options = GraphQLClientCodegenOptions::new(CodegenMode::Derive);
options.set_query_file(query_path);
if let Some(response_derives) = response_derives {
options.set_additional_derives(response_derives);
};
if let Ok(deprecation_strategy) = attributes::extract_deprecation_strategy(input) {
options.set_deprecation_strategy(deprecation_strategy);
};
options.set_struct_ident(input.ident.clone());
options.set_module_visibility(input.vis.clone());
options.set_operation_name(input.ident.to_string());
Ok(options)
}