Linked styles
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
Ident, LitStr, Result, Token, braced,
|
||||
Expr, Ident, LitStr, Result, Token, braced,
|
||||
parse::{Parse, ParseStream},
|
||||
parse_macro_input,
|
||||
};
|
||||
@@ -92,7 +92,7 @@ pub fn assets(input: TokenStream) -> TokenStream {
|
||||
|
||||
// Generate documentation showing the original asset definition
|
||||
let doc = format!(
|
||||
"This is an `asset!`\n```notrust\n{} {{\n\tsource: \"{}\",\n\ttarget: \"{}\"\n}}\n```",
|
||||
"This is an `asset!`\n```notrust\n{} {{\n\tsource: \"{:?}\",\n\ttarget: \"{}\"\n}}\n```",
|
||||
name, source, target
|
||||
);
|
||||
|
||||
@@ -106,7 +106,7 @@ pub fn assets(input: TokenStream) -> TokenStream {
|
||||
const URL_PREFIX: &'static str = #prefix;
|
||||
const URL_POSTFIX: &'static str = #target;
|
||||
const URL: &'static str = concat!(#prefix, #target);
|
||||
const BYTES: &'static [u8] = include_bytes!(#source);
|
||||
const BYTES: &'static [u8] = #source;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -115,9 +115,20 @@ pub fn assets(input: TokenStream) -> TokenStream {
|
||||
let router_fn = if let Some(router_name) = &input.router {
|
||||
let route_definitions = input.assets.iter().map(|asset| {
|
||||
let name = &asset.name;
|
||||
|
||||
let headers = asset
|
||||
.headers
|
||||
.as_ref()
|
||||
.map(|x| quote! { #x })
|
||||
.unwrap_or(quote! { [] });
|
||||
|
||||
quote! {
|
||||
.route(#name::URL_POSTFIX, ::axum::routing::get(|| async {
|
||||
(::axum::http::StatusCode::OK, #name::BYTES)
|
||||
(
|
||||
::axum::http::StatusCode::OK,
|
||||
#headers,
|
||||
#name::BYTES
|
||||
)
|
||||
}))
|
||||
}
|
||||
});
|
||||
@@ -159,8 +170,9 @@ struct AssetsInput {
|
||||
/// Represents a single asset definition within the macro
|
||||
struct AssetDefinition {
|
||||
name: Ident,
|
||||
source: String,
|
||||
source: Expr,
|
||||
target: String,
|
||||
headers: Option<Expr>,
|
||||
}
|
||||
|
||||
impl Parse for AssetsInput {
|
||||
@@ -214,26 +226,60 @@ impl Parse for AssetDefinition {
|
||||
let content;
|
||||
braced!(content in input);
|
||||
|
||||
// Parse "source:"
|
||||
let _source_ident: Ident = content.parse()?;
|
||||
let _colon1: Token![:] = content.parse()?;
|
||||
let source_lit: LitStr = content.parse()?;
|
||||
let source = source_lit.value();
|
||||
let _comma1: Token![,] = content.parse()?;
|
||||
// Parse fields in any order
|
||||
let mut source: Option<Expr> = None;
|
||||
let mut target: Option<String> = None;
|
||||
let mut headers: Option<Expr> = None;
|
||||
|
||||
// Parse "target:"
|
||||
let _target_ident: Ident = content.parse()?;
|
||||
let _colon2: Token![:] = content.parse()?;
|
||||
let target_lit: LitStr = content.parse()?;
|
||||
let target = target_lit.value();
|
||||
while !content.is_empty() {
|
||||
// Parse field name
|
||||
let field_name: Ident = content.parse()?;
|
||||
let _colon: Token![:] = content.parse()?;
|
||||
|
||||
// Optional trailing comma
|
||||
let _ = content.parse::<Token![,]>();
|
||||
// Parse field value based on name
|
||||
match field_name.to_string().as_str() {
|
||||
"source" => {
|
||||
if source.is_some() {
|
||||
return Err(syn::Error::new(field_name.span(), "duplicate 'source' field"));
|
||||
}
|
||||
source = Some(content.parse()?);
|
||||
}
|
||||
"target" => {
|
||||
if target.is_some() {
|
||||
return Err(syn::Error::new(field_name.span(), "duplicate 'target' field"));
|
||||
}
|
||||
let target_lit: LitStr = content.parse()?;
|
||||
target = Some(target_lit.value());
|
||||
}
|
||||
"headers" => {
|
||||
if headers.is_some() {
|
||||
return Err(syn::Error::new(field_name.span(), "duplicate 'headers' field"));
|
||||
}
|
||||
headers = Some(content.parse()?);
|
||||
}
|
||||
_ => {
|
||||
return Err(syn::Error::new(
|
||||
field_name.span(),
|
||||
format!("unknown field '{}', expected 'source', 'target', or 'headers'", field_name)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse comma if not at end
|
||||
if !content.is_empty() {
|
||||
content.parse::<Token![,]>()?;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
let source = source.ok_or_else(|| syn::Error::new(name.span(), "missing required field 'source'"))?;
|
||||
let target = target.ok_or_else(|| syn::Error::new(name.span(), "missing required field 'target'"))?;
|
||||
|
||||
Ok(AssetDefinition {
|
||||
name,
|
||||
source,
|
||||
target,
|
||||
headers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user