77
88mod node_handlers;
99
10- use std:: collections:: HashSet ;
10+ use std:: collections:: { HashMap , HashSet } ;
1111
1212use node_handlers:: {
1313 handle_block, handle_comment, handle_doctype, handle_element, handle_fragment, handle_raw_text,
1414 handle_text,
1515} ;
1616use proc_macro:: TokenStream ;
17- use proc_macro2:: TokenStream as TokenStream2 ;
17+ use proc_macro2:: { Ident , TokenStream as TokenStream2 } ;
1818use proc_macro2_diagnostics:: Diagnostic ;
1919use quote:: quote;
2020use rstml:: { node:: Node , Parser , ParserConfig } ;
21+ use syn:: Type ;
2122
2223#[ proc_macro]
2324pub fn html ( tokens : TokenStream ) -> TokenStream {
24- html_inner ( tokens, false )
25+ html_inner ( tokens. into ( ) , None )
2526}
2627
2728#[ cfg( feature = "typed" ) ]
2829#[ proc_macro]
2930pub fn typed_html ( tokens : TokenStream ) -> TokenStream {
30- html_inner ( tokens, true )
31+ use syn:: { punctuated:: Punctuated , token:: Paren , Token } ;
32+
33+ #[ derive( syn_derive:: Parse ) ]
34+ struct ColonAndType {
35+ _colon_token : syn:: Token ![ : ] ,
36+ ty : Type ,
37+ }
38+
39+ #[ derive( syn_derive:: Parse ) ]
40+ enum MaybeColonAndType {
41+ #[ parse( peek = Token ![ : ] ) ]
42+ ColonAndType ( ColonAndType ) ,
43+ Nothing ,
44+ }
45+
46+ #[ derive( syn_derive:: Parse ) ]
47+ struct Extension {
48+ prefix : Ident ,
49+ colon_and_type : MaybeColonAndType ,
50+ }
51+
52+ #[ derive( syn_derive:: Parse ) ]
53+ struct Extensions {
54+ #[ syn( parenthesized) ]
55+ #[ allow( dead_code) ]
56+ paren_token : Paren ,
57+
58+ #[ syn( in = paren_token) ]
59+ #[ parse( Punctuated :: parse_terminated) ]
60+ extensions : Punctuated < Extension , syn:: Token ![ , ] > ,
61+ }
62+
63+ #[ derive( syn_derive:: Parse ) ]
64+ enum MaybeExtensions {
65+ #[ parse( peek = Paren ) ]
66+ Extensions ( Extensions ) ,
67+ Nothing ,
68+ }
69+
70+ #[ derive( syn_derive:: Parse ) ]
71+ struct TypedHtmlOptions {
72+ extensions : MaybeExtensions ,
73+ tokens : TokenStream2 ,
74+ }
75+
76+ let options = syn:: parse_macro_input!( tokens as TypedHtmlOptions ) ;
77+
78+ let mut extensions = match options. extensions {
79+ MaybeExtensions :: Extensions ( extensions) => extensions
80+ . extensions
81+ . into_iter ( )
82+ . map ( |extension| match extension. colon_and_type {
83+ MaybeColonAndType :: ColonAndType ( ColonAndType { ty, .. } ) => {
84+ ( extension. prefix , Some ( ty) )
85+ }
86+ MaybeColonAndType :: Nothing => ( extension. prefix , None ) ,
87+ } )
88+ . collect :: < HashMap < _ , _ > > ( ) ,
89+ MaybeExtensions :: Nothing => HashMap :: new ( ) ,
90+ } ;
91+
92+ extensions. insert ( Ident :: new ( "data" , proc_macro2:: Span :: call_site ( ) ) , None ) ;
93+ extensions. insert ( Ident :: new ( "aria" , proc_macro2:: Span :: call_site ( ) ) , None ) ;
94+
95+ html_inner ( options. tokens , Some ( & extensions) )
3196}
3297
33- fn html_inner ( tokens : TokenStream , typed : bool ) -> TokenStream {
98+ fn html_inner (
99+ tokens : TokenStream2 ,
100+ extensions : Option < & HashMap < Ident , Option < Type > > > ,
101+ ) -> TokenStream {
34102 // from: https://html.spec.whatwg.org/dev/syntax.html#void-elements
35103 let void_elements = [
36104 "area" , "base" , "br" , "col" , "embed" , "hr" , "img" , "input" , "link" , "meta" , "source" ,
@@ -50,7 +118,7 @@ fn html_inner(tokens: TokenStream, typed: bool) -> TokenStream {
50118 let parser = Parser :: new ( config) ;
51119 let ( parsed_nodes, parsing_diagnostics) = parser. parse_recoverable ( tokens) . split_vec ( ) ;
52120 let ( tokenized_nodes, tokenization_diagnostics) =
53- tokenize_nodes ( & void_elements, typed , & parsed_nodes) ;
121+ tokenize_nodes ( & void_elements, extensions , & parsed_nodes) ;
54122
55123 let node = match & * tokenized_nodes {
56124 [ node] => quote ! ( #node) ,
@@ -81,16 +149,16 @@ fn html_inner(tokens: TokenStream, typed: bool) -> TokenStream {
81149
82150fn tokenize_nodes (
83151 void_elements : & HashSet < & str > ,
84- typed : bool ,
152+ extensions : Option < & HashMap < Ident , Option < Type > > > ,
85153 nodes : & [ Node ] ,
86154) -> ( Vec < TokenStream2 > , Vec < Diagnostic > ) {
87155 let ( token_streams, diagnostics) = nodes
88156 . iter ( )
89157 . map ( |node| match node {
90158 Node :: Comment ( comment) => ( handle_comment ( comment) , vec ! [ ] ) ,
91159 Node :: Doctype ( doctype) => ( handle_doctype ( doctype) , vec ! [ ] ) ,
92- Node :: Fragment ( fragment) => handle_fragment ( void_elements, typed , fragment) ,
93- Node :: Element ( element) => handle_element ( void_elements, typed , element) ,
160+ Node :: Fragment ( fragment) => handle_fragment ( void_elements, extensions , fragment) ,
161+ Node :: Element ( element) => handle_element ( void_elements, extensions , element) ,
94162 Node :: Block ( block) => ( handle_block ( block) , vec ! [ ] ) ,
95163 Node :: Text ( text) => ( handle_text ( text) , vec ! [ ] ) ,
96164 Node :: RawText ( text) => ( handle_raw_text ( text) , vec ! [ ] ) ,
0 commit comments