wasmbind_js_file_macro/
lib.rs

1use quote::quote;
2use proc_macro2::Span;
3use proc_macro::TokenStream;
4use syn::{
5    parse::{Parse, ParseStream},
6    Ident,
7    Token,
8    LitStr,
9    Result as SynResult,
10    parse_macro_input,
11};
12
13use std::{path::PathBuf, fs::read_to_string, env};
14
15#[derive(Clone)]
16struct PathOption {
17    span: Span,
18    path: PathBuf,
19}
20
21impl PathOption {
22    fn contents(&self) -> LitStr {
23        let contents = read_to_string(&self.path).unwrap_or_else(|err| {
24            if cfg!(any(doc, docsrs)) {
25                return String::from("(() => {})();");
26            }
27
28            match env::var_os("DOCS_RS") {
29                Some(v) if v == "1" => String::from("(() => {})();"),
30                _ => panic!("Failed to read file {}: {err}", self.path.display()),
31            }
32        });
33
34        LitStr::new(&contents, self.span.clone())
35    }
36}
37
38impl Parse for PathOption {
39    fn parse(input: ParseStream) -> SynResult<Self> {
40        let span = input.span();
41        let option_name = input.parse::<Ident>()?;
42        if option_name != "path" {
43            return Err(input.error("Expected `path` option"));
44        }
45
46        input.parse::<Token![=]>()?;
47
48        let path_str = input.parse::<LitStr>()?.value();
49        let mut path = PathBuf::from(&path_str);
50
51        const PREFIX: &'static str = "${outDir}/";
52        if path_str.starts_with(PREFIX) {
53            let out_dir = env::var("OUT_DIR").map_err(|_| input.error("OUT_DIR environment variable not found"))?;
54
55            path = PathBuf::from(out_dir);
56            path.extend(PathBuf::from(&path_str[PREFIX.len()..]).iter());
57        }
58
59        Ok(Self {
60            span,
61            path,
62        })
63    }
64}
65
66/**
67Procedural macro for generating the `#[wasm_bindgen]` attribute with parameter `inline_js`.
68The parameter `inline_js` will be filled by this macro with the content of the file
69that the path is passed as the argument `path` of this macro.
70The path can contain `$out_dir` placeholders which is the value of the `OUT_DIR` environment variable.
71*/
72#[proc_macro_attribute]
73pub fn wasmbind_dump_js_file_as_inline(attr: TokenStream, item: TokenStream) -> TokenStream {
74    let item = proc_macro2::TokenStream::from(item);
75    let path_option = parse_macro_input!(attr as PathOption);
76    let contents = path_option.contents();
77
78    let output = quote! {
79        #[wasm_bindgen(inline_js = #contents)]
80        #item
81    };
82
83    output.into()
84}