Skip to content

Commit 52d4856

Browse files
committed
Unify macro arg parsing
The `generate_types` macro didn't use `parse_macro_input!` to parse its arguments, unlike other macros. This unifies arg parsing across macros, making it easier to add a field to all macros.
1 parent 27c1d73 commit 52d4856

File tree

1 file changed

+57
-24
lines changed
  • shopify_function_macro/src

1 file changed

+57
-24
lines changed

shopify_function_macro/src/lib.rs

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use convert_case::{Case, Casing};
22
use std::io::Write;
33
use std::path::Path;
44

5-
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
5+
use proc_macro2::{Ident, Span, TokenStream};
66
use quote::{quote, ToTokens};
77
use syn::{self, parse::Parse, parse::ParseStream, parse_macro_input, Expr, FnArg, LitStr, Token};
88

@@ -164,6 +164,49 @@ impl Parse for ShopifyFunctionTargetArgs {
164164
}
165165
}
166166

167+
#[derive(Clone, Default)]
168+
struct GenerateTypeArgs {
169+
query_path: Option<LitStr>,
170+
schema_path: Option<LitStr>,
171+
input_stream: Option<Expr>,
172+
output_stream: Option<Expr>,
173+
}
174+
175+
impl GenerateTypeArgs {
176+
fn parse<K: syn::parse::Parse, V: syn::parse::Parse>(
177+
input: &ParseStream<'_>,
178+
) -> syn::Result<V> {
179+
input.parse::<K>()?;
180+
input.parse::<Token![=]>()?;
181+
let value: V = input.parse()?;
182+
if input.lookahead1().peek(Token![,]) {
183+
input.parse::<Token![,]>()?;
184+
}
185+
Ok(value)
186+
}
187+
}
188+
189+
impl Parse for GenerateTypeArgs {
190+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
191+
let mut args = Self::default();
192+
while !input.is_empty() {
193+
let lookahead = input.lookahead1();
194+
if lookahead.peek(kw::query_path) {
195+
args.query_path = Some(Self::parse::<kw::query_path, LitStr>(&input)?);
196+
} else if lookahead.peek(kw::schema_path) {
197+
args.schema_path = Some(Self::parse::<kw::schema_path, LitStr>(&input)?);
198+
} else if lookahead.peek(kw::input_stream) {
199+
args.input_stream = Some(Self::parse::<kw::input_stream, Expr>(&input)?);
200+
} else if lookahead.peek(kw::output_stream) {
201+
args.output_stream = Some(Self::parse::<kw::output_stream, Expr>(&input)?);
202+
} else {
203+
return Err(lookahead.error());
204+
}
205+
}
206+
Ok(args)
207+
}
208+
}
209+
167210
fn extract_shopify_function_return_type(ast: &syn::ItemFn) -> Result<&syn::Ident, syn::Error> {
168211
use syn::*;
169212

@@ -302,22 +345,6 @@ pub fn shopify_function_target(
302345
.into()
303346
}
304347

305-
fn extract_attr(attrs: &TokenStream, attr: &str) -> String {
306-
let attrs: Vec<TokenTree> = attrs.clone().into_iter().collect();
307-
let attr_index = attrs
308-
.iter()
309-
.position(|item| match item {
310-
TokenTree::Ident(ident) => ident.to_string().as_str() == attr,
311-
_ => false,
312-
})
313-
.unwrap_or_else(|| panic!("No attribute with name {} found", attr));
314-
let value = attrs
315-
.get(attr_index + 2)
316-
.unwrap_or_else(|| panic!("No value given for {} attribute", attr))
317-
.to_string();
318-
value.as_str()[1..value.len() - 1].to_string()
319-
}
320-
321348
const OUTPUT_QUERY_FILE_NAME: &str = ".output.graphql";
322349

323350
/// Generate the types to interact with Shopify's API.
@@ -338,13 +365,19 @@ const OUTPUT_QUERY_FILE_NAME: &str = ".output.graphql";
338365
/// hope we can avoid creating this file at some point in the future.
339366
#[proc_macro]
340367
pub fn generate_types(attr: proc_macro::TokenStream) -> proc_macro::TokenStream {
341-
let params = TokenStream::from(attr);
342-
343-
let query_path = extract_attr(&params, "query_path");
344-
let schema_path = extract_attr(&params, "schema_path");
345-
346-
let input_struct = generate_struct("Input", &query_path, &schema_path);
347-
let output_struct = generate_struct("Output", OUTPUT_QUERY_FILE_NAME, &schema_path);
368+
let args = parse_macro_input!(attr as GenerateTypeArgs);
369+
370+
let query_path = args
371+
.query_path
372+
.expect("No value given for query_path")
373+
.value();
374+
let schema_path = args
375+
.schema_path
376+
.expect("No value given for schema_path")
377+
.value();
378+
379+
let input_struct = generate_struct("Input", query_path.as_str(), schema_path.as_str());
380+
let output_struct = generate_struct("Output", OUTPUT_QUERY_FILE_NAME, schema_path.as_str());
348381
let output_query =
349382
"mutation Output($result: FunctionResult!) {\n handleResult(result: $result)\n}\n";
350383

0 commit comments

Comments
 (0)