1mod emitter;
7mod parser;
8
9use proc_macro::TokenStream;
10
11#[proc_macro_derive(TypeWriter, attributes(sync_to, tw))]
30pub fn derive_typewriter(input: TokenStream) -> TokenStream {
31 let input = syn::parse_macro_input!(input as syn::DeriveInput);
32
33 match typewriter_impl(&input) {
34 Ok(_) => TokenStream::new(),
35 Err(err) => err.to_compile_error().into(),
36 }
37}
38
39fn typewriter_impl(input: &syn::DeriveInput) -> syn::Result<()> {
40 let type_def = parser::parse_type_def(input)?;
42
43 let targets = parser::parse_sync_to_attr(input)?;
45
46 if targets.is_empty() {
47 return Err(syn::Error::new_spanned(
48 &input.ident,
49 "typewriter: #[sync_to(...)] attribute is required. \
50 Example: #[sync_to(typescript, python)]",
51 ));
52 }
53
54 let config = load_config();
56
57 emitter::emit_all(&type_def, &targets, &config);
59
60 Ok(())
61}
62
63fn load_config() -> typewriter_core::config::TypewriterConfig {
65 if let Ok(manifest_dir) = std::env::var("CARGO_MANIFEST_DIR") {
67 let path = std::path::Path::new(&manifest_dir);
68 for ancestor in path.ancestors() {
70 if let Ok(config) = typewriter_core::config::TypewriterConfig::load(ancestor) {
71 if config.typescript.is_some() || config.python.is_some() {
72 return config;
73 }
74 }
75 }
76 }
77 typewriter_core::config::TypewriterConfig::default()
78}