@@ -117,6 +117,72 @@ impl Report {
117117 measures. calc_matched_percent ( ) ;
118118 }
119119 }
120+
121+ /// Split the report into multiple reports based on progress categories.
122+ /// Assumes progress categories are in the format `version`, `version.category`.
123+ /// This is a hack for projects that generate all versions in a single report.
124+ pub fn split ( self ) -> Vec < ( String , Report ) > {
125+ let mut reports = Vec :: new ( ) ;
126+ // Map units to Option to allow taking ownership
127+ let mut units = self . units . into_iter ( ) . map ( Some ) . collect :: < Vec < _ > > ( ) ;
128+ for category in & self . categories {
129+ if category. id . contains ( "." ) {
130+ // Skip subcategories
131+ continue ;
132+ }
133+ fn is_sub_category ( id : & str , parent : & str , sep : char ) -> bool {
134+ id. starts_with ( parent)
135+ && id. get ( parent. len ( ) ..) . map_or ( false , |s| s. starts_with ( sep) )
136+ }
137+ let mut sub_categories = self
138+ . categories
139+ . iter ( )
140+ . filter ( |c| is_sub_category ( & c. id , & category. id , '.' ) )
141+ . cloned ( )
142+ . collect :: < Vec < _ > > ( ) ;
143+ // Remove category prefix
144+ for sub_category in & mut sub_categories {
145+ sub_category. id = sub_category. id [ category. id . len ( ) + 1 ..] . to_string ( ) ;
146+ }
147+ let mut sub_units = units
148+ . iter_mut ( )
149+ . filter_map ( |opt| {
150+ let unit = opt. as_mut ( ) ?;
151+ let metadata = unit. metadata . as_ref ( ) ?;
152+ if metadata. progress_categories . contains ( & category. id ) {
153+ opt. take ( )
154+ } else {
155+ None
156+ }
157+ } )
158+ . collect :: < Vec < _ > > ( ) ;
159+ for sub_unit in & mut sub_units {
160+ // Remove leading version/ from unit name
161+ if let Some ( name) =
162+ sub_unit. name . strip_prefix ( & category. id ) . and_then ( |s| s. strip_prefix ( '/' ) )
163+ {
164+ sub_unit. name = name. to_string ( ) ;
165+ }
166+ // Filter progress categories
167+ let Some ( metadata) = sub_unit. metadata . as_mut ( ) else {
168+ continue ;
169+ } ;
170+ metadata. progress_categories = metadata
171+ . progress_categories
172+ . iter ( )
173+ . filter ( |c| is_sub_category ( c, & category. id , '.' ) )
174+ . map ( |c| c[ category. id . len ( ) + 1 ..] . to_string ( ) )
175+ . collect ( ) ;
176+ }
177+ reports. push ( ( category. id . clone ( ) , Report {
178+ measures : category. measures ,
179+ units : sub_units,
180+ version : self . version ,
181+ categories : sub_categories,
182+ } ) ) ;
183+ }
184+ reports
185+ }
120186}
121187
122188impl Measures {
0 commit comments