22
33use std:: collections:: HashSet ;
44
5- use crate :: schema:: v2:: { self , AppManifest , ComponentSpec , KebabId } ;
5+ use crate :: schema:: v2:: { AppManifest , ComponentSpec , KebabId } ;
66
7- /// Extracts each `ComponentSpec::Inline` into `AppManifest::component`s,
8- /// replacing it with a `ComponentSpec::Reference`.
9- pub fn normalize_inline_components ( manifest : & mut AppManifest ) {
7+ /// Normalizes some optional [`AppManifest`] features into a canonical form:
8+ /// - Inline components in trigger configs are moved into top-level
9+ /// components and replaced with a reference.
10+ /// - Any triggers without an ID are assigned a generated ID.
11+ pub fn normalize_manifest ( manifest : & mut AppManifest ) {
12+ normalize_trigger_ids ( manifest) ;
13+ normalize_inline_components ( manifest) ;
14+ }
15+
16+ fn normalize_inline_components ( manifest : & mut AppManifest ) {
17+ // Normalize inline components
1018 let components = & mut manifest. components ;
11- for trigger in & mut manifest. triggers . values_mut ( ) . flatten ( ) {
19+
20+ for trigger in manifest. triggers . values_mut ( ) . flatten ( ) {
1221 let trigger_id = & trigger. id ;
13- let component_specs = trigger. component . iter_mut ( ) . chain (
14- trigger
15- . components
16- . values_mut ( )
17- . flat_map ( |specs| specs. 0 . iter_mut ( ) ) ,
18- ) ;
22+
23+ let component_specs = trigger
24+ . component
25+ . iter_mut ( )
26+ . chain (
27+ trigger
28+ . components
29+ . values_mut ( )
30+ . flat_map ( |specs| specs. 0 . iter_mut ( ) ) ,
31+ )
32+ . collect :: < Vec < _ > > ( ) ;
33+ let multiple_components = component_specs. len ( ) > 1 ;
1934
2035 let mut counter = 1 ;
2136 for spec in component_specs {
2237 if !matches ! ( spec, ComponentSpec :: Inline ( _) ) {
2338 continue ;
2439 } ;
2540
26- // Generate an unused component ID
27- let inline_id = loop {
28- let id =
29- KebabId :: try_from ( format ! ( "{trigger_id}-inline-component{counter}" ) ) . unwrap ( ) ;
30- if !components. contains_key ( & id) {
31- break id;
41+ let inline_id = {
42+ // Try a "natural" component ID...
43+ let mut id = KebabId :: try_from ( format ! ( "{trigger_id}-component" ) ) ;
44+ // ...falling back to a counter-based component ID
45+ if multiple_components
46+ || id. is_err ( )
47+ || components. contains_key ( id. as_ref ( ) . unwrap ( ) )
48+ {
49+ id = Ok ( loop {
50+ let id = KebabId :: try_from ( format ! ( "inline-component{counter}" ) ) . unwrap ( ) ;
51+ if !components. contains_key ( & id) {
52+ break id;
53+ }
54+ counter += 1 ;
55+ } ) ;
3256 }
33- counter += 1 ;
57+ id . unwrap ( )
3458 } ;
3559
3660 // Replace the inline component with a reference...
@@ -44,23 +68,32 @@ pub fn normalize_inline_components(manifest: &mut AppManifest) {
4468 }
4569}
4670
47- /// Generates IDs for any [`Trigger`]s without one.
48- pub fn normalize_trigger_ids ( typed_triggers : & mut v2 :: Map < String , Vec < v2 :: Trigger > > ) {
49- let mut trigger_ids = typed_triggers
71+ fn normalize_trigger_ids ( manifest : & mut AppManifest ) {
72+ let mut trigger_ids = manifest
73+ . triggers
5074 . values ( )
5175 . flatten ( )
5276 . cloned ( )
5377 . map ( |t| t. id )
5478 . collect :: < HashSet < _ > > ( ) ;
55- for ( trigger_type, triggers) in typed_triggers {
79+ for ( trigger_type, triggers) in & mut manifest . triggers {
5680 let mut counter = 1 ;
5781 for trigger in triggers {
5882 if !trigger. id . is_empty ( ) {
5983 continue ;
6084 }
61- // Generate an unused trigger ID
85+ // Try to assign a "natural" ID to this trigger
86+ if let Some ( ComponentSpec :: Reference ( component_id) ) = & trigger. component {
87+ let candidate_id = format ! ( "{component_id}-{trigger_type}-trigger" ) ;
88+ if !trigger_ids. contains ( & candidate_id) {
89+ trigger. id = candidate_id. clone ( ) ;
90+ trigger_ids. insert ( candidate_id) ;
91+ continue ;
92+ }
93+ }
94+ // Fall back to assigning a counter-based trigger ID
6295 trigger. id = loop {
63- let id = format ! ( "{trigger_type}-{counter}" ) ;
96+ let id = format ! ( "{trigger_type}-trigger {counter}" ) ;
6497 if !trigger_ids. contains ( & id) {
6598 trigger_ids. insert ( id. clone ( ) ) ;
6699 break id;
0 commit comments