#![feature(proc_macro_span)]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, LitStr};
use std::env;
use std::path::{Path, PathBuf};
#[proc_macro]
pub fn include_css_module(input: TokenStream) -> TokenStream {
if input.is_empty() {
parse_macro_input!(input as LitStr);
unreachable!();
}
let out_dir = env::var("OUT_DIR")
.expect("Please set up CSS Modules in your build script.");
let out_dir = Path::new(&out_dir);
let input_path = input.clone();
let input_path = parse_macro_input!(input_path as LitStr).value();
let mut path = out_dir.join(
strip_manifest_dir(
replace_file_name(
token_stream_source_file(input),
input_path
)
)
);
if let Some(extension) = path.extension() {
path = path.with_extension(format!("{}.rs", extension.to_str().unwrap()));
} else {
path = path.with_extension("rs");
}
let path = path.to_str();
TokenStream::from(quote! {
{
use css_modules::CssModuleBuilder;
include!(#path)
}
})
}
fn token_stream_source_file(input: TokenStream) -> PathBuf {
let file = input.into_iter().next().unwrap().span().source_file();
if !file.is_real() {
panic!("Must be called from a file.");
}
file.path().canonicalize().unwrap()
}
fn strip_manifest_dir(path: PathBuf) -> PathBuf {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
path.strip_prefix(manifest_dir).unwrap().into()
}
fn strip_file_name(path: PathBuf) -> PathBuf {
path.parent().unwrap().into()
}
fn replace_file_name(path: PathBuf, file_name: String) -> PathBuf {
strip_file_name(path).join(file_name)
}