use std::iter::once;
use proc_macro::TokenStream;
use quote::ToTokens;
use syn::{Block, ExprBlock};
use self::{
ast::ToCode,
ctxt::{Ctx, prepare_vars},
input::QuoteInput,
ret_type::parse_input_type,
};
mod ast;
mod builder;
#[cfg(feature = "compiler")]
mod compiler;
mod ctxt;
mod input;
mod ret_type;
mod template;
#[cfg(test)]
mod test;
#[proc_macro]
pub fn ts_quote(input: TokenStream) -> TokenStream {
match ts_quote_impl(input.into()) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}
fn ts_quote_impl(input: proc_macro2::TokenStream) -> syn::Result<proc_macro2::TokenStream> {
let QuoteInput {
src,
as_token: _,
output_type,
vars,
} = syn::parse2::<QuoteInput>(input)?;
let ret_type = parse_input_type(&src.value(), &output_type).map_err(|err| {
syn::Error::new_spanned(&src, format!("failed to parse TypeScript: {err}"))
})?;
let vars = vars.map(|v| v.1);
let (stmts, vars) = if let Some(vars) = vars {
prepare_vars(&ret_type, vars)?
} else {
Default::default()
};
let cx = Ctx { vars };
let expr_for_ast_creation = ret_type.to_code(&cx);
Ok(syn::Expr::Block(ExprBlock {
attrs: Default::default(),
label: Default::default(),
block: Block {
brace_token: Default::default(),
stmts: stmts
.into_iter()
.chain(once(syn::Stmt::Expr(expr_for_ast_creation, None)))
.collect(),
},
})
.to_token_stream())
}
#[proc_macro]
pub fn ts_template(input: TokenStream) -> TokenStream {
#[cfg(feature = "compiler")]
{
match compiler::compile_template_tokens(input.into()) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}
#[cfg(not(feature = "compiler"))]
{
match template::compile_template(input.into()) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}
}