@@ -262,6 +262,8 @@ pub struct CodePressTransform {
262262 use_js_metadata_map : bool ,
263263 metadata_map : HashMap < String , MetadataEntry > ,
264264 inserted_metadata_map : bool ,
265+ // Track if config (repo/branch) has been injected to window.__CODEPRESS_CONFIG__
266+ inserted_config : bool ,
265267}
266268
267269/// Metadata entry for the JS-based map (window.__CODEPRESS_MAP__)
@@ -477,6 +479,7 @@ impl CodePressTransform {
477479 use_js_metadata_map,
478480 metadata_map : HashMap :: new ( ) ,
479481 inserted_metadata_map : false ,
482+ inserted_config : false ,
480483 }
481484 }
482485
@@ -937,47 +940,9 @@ impl CodePressTransform {
937940 } )
938941 }
939942
940- fn create_repo_attr ( & self ) -> Option < JSXAttrOrSpread > {
941- self . repo_name . as_ref ( ) . map ( |repo| {
942- JSXAttrOrSpread :: JSXAttr ( JSXAttr {
943- span : DUMMY_SP ,
944- name : JSXAttrName :: Ident ( cp_ident_name ( "codepress-github-repo-name" . into ( ) ) ) ,
945- value : Some ( make_jsx_str_attr_value ( repo. clone ( ) ) ) ,
946- } )
947- } )
948- }
949-
950- fn create_branch_attr ( & self ) -> Option < JSXAttrOrSpread > {
951- self . branch_name . as_ref ( ) . map ( |branch| {
952- JSXAttrOrSpread :: JSXAttr ( JSXAttr {
953- span : DUMMY_SP ,
954- name : JSXAttrName :: Ident ( cp_ident_name ( "codepress-github-branch" . into ( ) ) ) ,
955- value : Some ( make_jsx_str_attr_value ( branch. clone ( ) ) ) ,
956- } )
957- } )
958- }
959-
960- fn has_repo_attribute ( & self , attrs : & [ JSXAttrOrSpread ] ) -> bool {
961- attrs. iter ( ) . any ( |attr| {
962- if let JSXAttrOrSpread :: JSXAttr ( jsx_attr) = attr {
963- if let JSXAttrName :: Ident ( ident) = & jsx_attr. name {
964- return ident. sym . as_ref ( ) == "codepress-github-repo-name" ;
965- }
966- }
967- false
968- } )
969- }
970-
971- fn has_branch_attribute ( & self , attrs : & [ JSXAttrOrSpread ] ) -> bool {
972- attrs. iter ( ) . any ( |attr| {
973- if let JSXAttrOrSpread :: JSXAttr ( jsx_attr) = attr {
974- if let JSXAttrName :: Ident ( ident) = & jsx_attr. name {
975- return ident. sym . as_ref ( ) == "codepress-github-branch" ;
976- }
977- }
978- false
979- } )
980- }
943+ // NOTE: create_repo_attr, create_branch_attr, has_repo_attribute, has_branch_attribute
944+ // were removed - repo/branch info is now injected via window.__CODEPRESS_CONFIG__
945+ // in inject_config() instead of as HTML attributes.
981946
982947 // ---------- binding collection & tracing ----------
983948
@@ -2138,6 +2103,64 @@ impl CodePressTransform {
21382103 self . inserted_metadata_map = true ;
21392104 }
21402105
2106+ /// Injects window.__CODEPRESS_CONFIG__ with repo and branch info.
2107+ /// This stores config in JS instead of as HTML attributes (which pollutes the DOM).
2108+ /// Only injected once per build (uses static flag to prevent duplicates across modules).
2109+ fn inject_config ( & mut self , m : & mut Module ) {
2110+ // Skip if already injected (either in this module or globally)
2111+ if self . inserted_config || GLOBAL_ATTRIBUTES_ADDED . load ( Ordering :: Relaxed ) {
2112+ return ;
2113+ }
2114+
2115+ // Only inject if we have repo info
2116+ let repo = match & self . repo_name {
2117+ Some ( r) => r. clone ( ) ,
2118+ None => return ,
2119+ } ;
2120+
2121+ let branch = self . branch_name . clone ( ) . unwrap_or_else ( || "main" . to_string ( ) ) ;
2122+
2123+ // Build the config object: window.__CODEPRESS_CONFIG__ = { repo: "...", branch: "..." }
2124+ // Uses Object.assign to avoid overwriting if somehow multiple modules try to set it
2125+ let js = format ! (
2126+ "try{{if(typeof window!=='undefined'){{window.__CODEPRESS_CONFIG__=Object.assign(window.__CODEPRESS_CONFIG__||{{}},{{repo:\" {}\" ,branch:\" {}\" }});}}}}catch(_){{}}" ,
2127+ repo. replace( '\\' , "\\ \\ " ) . replace( '"' , "\\ \" " ) ,
2128+ branch. replace( '\\' , "\\ \\ " ) . replace( '"' , "\\ \" " )
2129+ ) ;
2130+
2131+ let stmt = ModuleItem :: Stmt ( Stmt :: Expr ( ExprStmt {
2132+ span : DUMMY_SP ,
2133+ expr : Box :: new ( Expr :: Call ( CallExpr {
2134+ span : DUMMY_SP ,
2135+ callee : Callee :: Expr ( Box :: new ( Expr :: New ( NewExpr {
2136+ span : DUMMY_SP ,
2137+ callee : Box :: new ( Expr :: Ident ( cp_ident ( "Function" . into ( ) ) ) ) ,
2138+ args : Some ( vec ! [ ExprOrSpread {
2139+ spread: None ,
2140+ expr: Box :: new( Expr :: Lit ( Lit :: Str ( Str {
2141+ span: DUMMY_SP ,
2142+ value: js. into( ) ,
2143+ raw: None ,
2144+ } ) ) ) ,
2145+ } ] ) ,
2146+ type_args : None ,
2147+ #[ cfg( not( feature = "compat_0_87" ) ) ]
2148+ ctxt : SyntaxContext :: empty ( ) ,
2149+ } ) ) ) ,
2150+ args : vec ! [ ] ,
2151+ type_args : None ,
2152+ #[ cfg( not( feature = "compat_0_87" ) ) ]
2153+ ctxt : SyntaxContext :: empty ( ) ,
2154+ } ) ) ,
2155+ } ) ) ;
2156+
2157+ // Place AFTER directive prologue (e.g., "use client"; "use strict")
2158+ let insert_at = self . directive_insert_index ( m) ;
2159+ m. body . insert ( insert_at, stmt) ;
2160+ self . inserted_config = true ;
2161+ GLOBAL_ATTRIBUTES_ADDED . store ( true , Ordering :: Relaxed ) ;
2162+ }
2163+
21412164 /// Injects the CPRefreshProvider at app entry points (when use_js_metadata_map is true).
21422165 /// This enables automatic HMR without users needing to manually add the provider.
21432166 ///
@@ -3240,6 +3263,8 @@ impl VisitMut for CodePressTransform {
32403263 self . inject_graph_stmt ( m) ;
32413264 // Inject metadata map (if using JS-based metadata instead of DOM attributes)
32423265 self . inject_metadata_map ( m) ;
3266+ // Inject config (repo/branch) into window.__CODEPRESS_CONFIG__ (cleaner than DOM attributes)
3267+ self . inject_config ( m) ;
32433268 }
32443269 fn visit_mut_import_decl ( & mut self , n : & mut ImportDecl ) {
32453270 let _ = self . file_from_span ( n. span ) ;
@@ -3686,26 +3711,8 @@ impl VisitMut for CodePressTransform {
36863711 }
36873712 }
36883713
3689- // Root repo/branch once
3690- if self . repo_name . is_some ( ) && !GLOBAL_ATTRIBUTES_ADDED . load ( Ordering :: Relaxed ) {
3691- let element_name = match & node. opening . name {
3692- JSXElementName :: Ident ( ident) => ident. sym . as_ref ( ) ,
3693- _ => "" ,
3694- } ;
3695- if matches ! ( element_name, "html" | "body" | "div" ) {
3696- if !self . has_repo_attribute ( & node. opening . attrs ) {
3697- if let Some ( repo_attr) = self . create_repo_attr ( ) {
3698- node. opening . attrs . push ( repo_attr) ;
3699- }
3700- }
3701- if !self . has_branch_attribute ( & node. opening . attrs ) {
3702- if let Some ( branch_attr) = self . create_branch_attr ( ) {
3703- node. opening . attrs . push ( branch_attr) ;
3704- }
3705- }
3706- GLOBAL_ATTRIBUTES_ADDED . store ( true , Ordering :: Relaxed ) ;
3707- }
3708- }
3714+ // NOTE: repo/branch info is now injected via window.__CODEPRESS_CONFIG__ in inject_config()
3715+ // instead of as HTML attributes, to avoid polluting the DOM.
37093716
37103717 // Host vs custom
37113718 let is_host = matches ! (
0 commit comments