66
77use super :: ParserPlugin ;
88use crate :: component_registry:: Component ;
9- use crate :: Result ;
9+ use crate :: { CssStrategy , Result } ;
1010
1111/// Information about a tracked component for `<f-template>` generation.
1212struct TrackedComponent {
@@ -25,6 +25,8 @@ struct TrackedComponent {
2525pub struct FastParserPlugin {
2626 /// Components tracked during parsing, in discovery order.
2727 components : Vec < TrackedComponent > ,
28+ /// CSS delivery strategy for f-templates.
29+ css_strategy : CssStrategy ,
2830}
2931
3032impl FastParserPlugin {
@@ -33,9 +35,15 @@ impl FastParserPlugin {
3335 pub fn new ( ) -> Self {
3436 Self {
3537 components : Vec :: new ( ) ,
38+ css_strategy : CssStrategy :: Link ,
3639 }
3740 }
3841
42+ /// Set the CSS delivery strategy for generated f-templates.
43+ pub fn set_css_strategy ( & mut self , strategy : CssStrategy ) {
44+ self . css_strategy = strategy;
45+ }
46+
3947 /// Take the individual component f-template strings, keyed by tag name.
4048 ///
4149 /// Each value is a complete `<f-template name="tag-name">...</f-template>` string
@@ -50,6 +58,7 @@ impl FastParserPlugin {
5058 & comp. tag_name ,
5159 & comp. html_content ,
5260 comp. css_content . as_deref ( ) ,
61+ self . css_strategy ,
5362 ) ;
5463 ( comp. tag_name . clone ( ) , tmpl)
5564 } )
@@ -116,6 +125,7 @@ pub fn generate_f_template(
116125 tag_name : & str ,
117126 html_content : & str ,
118127 css_content : Option < & str > ,
128+ css_strategy : CssStrategy ,
119129) -> String {
120130 let mut output = String :: with_capacity ( 256 ) ;
121131 output. push_str ( "<f-template name=\" " ) ;
@@ -125,24 +135,38 @@ pub fn generate_f_template(
125135 let converted = convert_btr_to_fast ( html_content) ;
126136 let trimmed = minify_inter_tag_whitespace ( converted. trim ( ) ) ;
127137
138+ // Build the CSS injection string based on the configured strategy
139+ let css_injection = match css_strategy {
140+ CssStrategy :: Link => css_content. map ( |_| {
141+ let mut s = String :: with_capacity ( 40 + tag_name. len ( ) ) ;
142+ s. push_str ( "<link rel=\" stylesheet\" href=\" /" ) ;
143+ s. push_str ( tag_name) ;
144+ s. push_str ( ".css\" >" ) ;
145+ s
146+ } ) ,
147+ CssStrategy :: Style => css_content. map ( |css| {
148+ let mut s = String :: with_capacity ( 15 + css. len ( ) ) ;
149+ s. push_str ( "<style>" ) ;
150+ s. push_str ( css. trim ( ) ) ;
151+ s. push_str ( "</style>" ) ;
152+ s
153+ } ) ,
154+ } ;
155+
128156 if trimmed. starts_with ( "<template" ) {
129157 if let Some ( close_pos) = trimmed. find ( '>' ) {
130158 output. push_str ( & trimmed[ ..=close_pos] ) ;
131- if css_content. is_some ( ) {
132- output. push_str ( "<link rel=\" stylesheet\" href=\" /" ) ;
133- output. push_str ( tag_name) ;
134- output. push_str ( ".css\" >" ) ;
159+ if let Some ( ref injection) = css_injection {
160+ output. push_str ( injection) ;
135161 }
136162 output. push_str ( & trimmed[ close_pos + 1 ..] ) ;
137163 } else {
138164 output. push_str ( & trimmed) ;
139165 }
140166 } else {
141167 output. push_str ( "<template>" ) ;
142- if css_content. is_some ( ) {
143- output. push_str ( "<link rel=\" stylesheet\" href=\" /" ) ;
144- output. push_str ( tag_name) ;
145- output. push_str ( ".css\" >" ) ;
168+ if let Some ( ref injection) = css_injection {
169+ output. push_str ( injection) ;
146170 }
147171 output. push_str ( & trimmed) ;
148172 output. push_str ( "</template>" ) ;
@@ -692,6 +716,26 @@ mod tests {
692716 assert ! ( html. contains( "<span>text</span>" ) ) ;
693717 }
694718
719+ #[ test]
720+ fn component_template_css_strategy_style ( ) {
721+ let mut plugin = FastParserPlugin :: new ( ) ;
722+ plugin. set_css_strategy ( crate :: CssStrategy :: Style ) ;
723+ let comp = make_component ( "my-comp" , "<div>hello</div>" , Some ( "div { color: red; }" ) ) ;
724+ plugin. on_parse_component ( "my-comp" , & comp) . unwrap ( ) ;
725+
726+ let templates = plugin. take_component_templates ( ) ;
727+ assert_eq ! ( templates. len( ) , 1 ) ;
728+ let ( _, html) = & templates[ 0 ] ;
729+ assert ! (
730+ html. contains( "<style>div { color: red; }</style>" ) ,
731+ "Style strategy should inline CSS, got: {html}"
732+ ) ;
733+ assert ! (
734+ !html. contains( "<link" ) ,
735+ "Style strategy should not emit <link> tags"
736+ ) ;
737+ }
738+
695739 #[ test]
696740 fn component_template_multiple_components ( ) {
697741 let mut plugin = FastParserPlugin :: new ( ) ;
0 commit comments