| 498 | } |
| 499 | |
| 500 | fn parse_node_fn(attr: TokenStream2, item: TokenStream2) -> syn::Result<ParsedNodeFn> { |
| 501 | let attributes = syn::parse2::<NodeFnAttributes>(attr.clone()).map_err(|e| Error::new(e.span(), format!("Failed to parse node_fn attributes:\n{e}")))?; |
| 502 | let input_fn = syn::parse2::<ItemFn>(item.clone()).map_err(|e| Error::new(e.span(), format!("Failed to parse function: {e}. Make sure it's a valid Rust function.")))?; |
| 503 | |
| 504 | let vis = input_fn.vis; |
| 505 | let fn_name = input_fn.sig.ident.clone(); |
| 506 | let struct_name = format_ident!("{}", fn_name.to_string().to_case(Case::Pascal)); |
| 507 | let mod_name = fn_name.clone(); |
| 508 | let fn_generics = input_fn.sig.generics.params.into_iter().collect(); |
| 509 | let is_async = input_fn.sig.asyncness.is_some(); |
| 510 | |
| 511 | let (input, fields) = parse_inputs(&input_fn.sig.inputs)?; |
| 512 | let output_type = parse_output(&input_fn.sig.output)?; |
| 513 | let where_clause = input_fn.sig.generics.where_clause; |
| 514 | let body = input_fn.block.to_token_stream(); |
| 515 | let description = input_fn |
| 516 | .attrs |
| 517 | .iter() |
| 518 | .filter_map(|a| { |
| 519 | if a.style != AttrStyle::Outer { |
| 520 | return None; |
| 521 | } |
| 522 | let Meta::NameValue(name_val) = &a.meta else { return None }; |
| 523 | if name_val.path.get_ident().map(|x| x.to_string()) != Some("doc".into()) { |
| 524 | return None; |
| 525 | } |
| 526 | let Expr::Lit(expr_lit) = &name_val.value else { return None }; |
| 527 | let Lit::Str(ref text) = expr_lit.lit else { return None }; |
| 528 | Some(text.value().trim().to_string()) |
| 529 | }) |
| 530 | .fold(String::new(), |acc, b| acc + &b + "\n"); |
| 531 | |
| 532 | Ok(ParsedNodeFn { |
| 533 | vis, |
| 534 | attributes, |
| 535 | fn_name, |
| 536 | struct_name, |
| 537 | mod_name, |
| 538 | fn_generics, |
| 539 | input, |
| 540 | output_type, |
| 541 | is_async, |
| 542 | fields, |
| 543 | where_clause, |
| 544 | body, |
| 545 | description, |
| 546 | }) |
| 547 | } |
| 548 | |
| 549 | fn parse_inputs(inputs: &Punctuated<FnArg, Comma>) -> syn::Result<(Input, Vec<ParsedField>)> { |
| 550 | let mut fields = Vec::new(); |