wasmbind_js_file_macro/
lib.rs1use 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#[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}