Skip to main content

haste_macro_loads/
lib.rs

1use std::path::Path;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{Lit, parse_macro_input};
6use walkdir::WalkDir;
7
8/// Loads all JSON artifacts from the specified directory.
9///
10/// # Panics
11///
12/// Panics if:
13/// - the macro call site does not have a local source file.
14/// - the source file has no parent directory.
15/// - an input literal cannot be parsed as a literal.
16/// - an input literal is not a string literal.
17/// - a directory entry cannot be accessed.
18/// - a discovered JSON file path cannot be converted to UTF-8.
19/// - the call site's parent path cannot be converted to UTF-8.
20#[proc_macro]
21pub fn load_artifacts(input: TokenStream) -> TokenStream {
22    let mut token_include_paths = Vec::new();
23    for token_tree in input {
24        let literal_stream: TokenStream = token_tree.into();
25        let literal = parse_macro_input!(literal_stream as Lit);
26
27        // call site location.
28        let span = proc_macro::Span::call_site();
29        // get the path from the call site.
30        let source_file = span.local_file().unwrap();
31        let source_file_path = source_file.as_path();
32        let parent_path = source_file_path.parent().unwrap();
33
34        match literal {
35            Lit::Str(lit_str) => {
36                let directory = lit_str.value();
37                let path = Path::new(&directory);
38
39                let location = parent_path.join(path);
40
41                for entry in WalkDir::new(location) {
42                    let path = entry.as_ref().unwrap().path();
43                    if !path.is_dir() && path.extension().is_some_and(|ext| ext == "json") {
44                        let entry_path = path.to_str().unwrap();
45                        token_include_paths.push(entry_path.replace(
46                            (parent_path.to_str().unwrap().to_string() + "/").as_str(),
47                            "",
48                        ));
49                    }
50                }
51            }
52            _ => {
53                panic!("Invalid literal for macro.")
54            }
55        }
56    }
57
58    quote! {
59        &[ #(include_str!(#token_include_paths)),* ]
60    }
61    .into()
62}