@@ -90,6 +90,38 @@ class Transform(FTL.BaseNode):
9090 def __call__ (self , ctx ):
9191 raise NotImplementedError
9292
93+ @staticmethod
94+ def flatten_elements (elements ):
95+ '''Flatten a list of FTL nodes into valid Pattern's elements'''
96+ flattened = []
97+ for element in elements :
98+ if isinstance (element , FTL .Pattern ):
99+ flattened .extend (element .elements )
100+ elif isinstance (element , FTL .PatternElement ):
101+ flattened .append (element )
102+ elif isinstance (element , FTL .Expression ):
103+ flattened .append (FTL .Placeable (element ))
104+ else :
105+ raise RuntimeError (
106+ 'Expected Pattern, PatternElement or Expression' )
107+ return flattened
108+
109+ @staticmethod
110+ def prune_text_elements (elements ):
111+ '''Join adjacent TextElements and remove empty ones'''
112+ pruned = []
113+ # Group elements in contiguous sequences of the same type.
114+ for elem_type , elems in itertools .groupby (elements , key = type ):
115+ if elem_type is FTL .TextElement :
116+ # Join adjacent TextElements.
117+ text = FTL .TextElement ('' .join (elem .value for elem in elems ))
118+ # And remove empty ones.
119+ if len (text .value ) > 0 :
120+ pruned .append (text )
121+ else :
122+ pruned .extend (elems )
123+ return pruned
124+
93125
94126class Source (Transform ):
95127 """Declare the source translation to be migrated with other transforms.
@@ -157,7 +189,7 @@ def __call__(self, ctx):
157189
158190 # A list of PatternElements built from the legacy translation and the
159191 # FTL replacements. It may contain empty or adjacent TextElements.
160- parts = []
192+ elements = []
161193 tail = self .value
162194
163195 # Convert original placeables and text into FTL Nodes. For each
@@ -166,33 +198,14 @@ def __call__(self, ctx):
166198 # the placeable will be replaced with its replacement.
167199 for key in keys_in_order :
168200 before , key , tail = tail .partition (key )
169-
170- # The replacement value can be of different types.
171- replacement = replacements [key ]
172- if isinstance (replacement , FTL .Pattern ):
173- repl_elements = replacement .elements
174- elif isinstance (replacement , FTL .PatternElement ):
175- repl_elements = [replacement ]
176- elif isinstance (replacement , FTL .Expression ):
177- repl_elements = [FTL .Placeable (replacement )]
178-
179- parts .append (FTL .TextElement (before ))
180- parts .extend (repl_elements )
201+ elements .append (FTL .TextElement (before ))
202+ elements .append (replacements [key ])
181203
182204 # Dont' forget about the tail after the loop ends.
183- parts .append (FTL .TextElement (tail ))
184-
185- # Join adjacent TextElements.
186- elements = []
187- for elem_type , elems in itertools .groupby (parts , key = type ):
188- if elem_type is FTL .TextElement :
189- text = FTL .TextElement ('' .join (elem .value for elem in elems ))
190- # And remove empty ones.
191- if len (text .value ) > 0 :
192- elements .append (text )
193- else :
194- elements .extend (elems )
205+ elements .append (FTL .TextElement (tail ))
195206
207+ elements = self .flatten_elements (elements )
208+ elements = self .prune_text_elements (elements )
196209 return FTL .Pattern (elements )
197210
198211
@@ -270,34 +283,8 @@ def __init__(self, *patterns):
270283 self .patterns = list (patterns )
271284
272285 def __call__ (self , ctx ):
273- # Flatten the list of patterns of which each has a list of elements.
274- def concat_elements (acc , cur ):
275- if isinstance (cur , FTL .Pattern ):
276- acc .extend (cur .elements )
277- return acc
278- elif (isinstance (cur , FTL .TextElement ) or
279- isinstance (cur , FTL .Placeable )):
280- acc .append (cur )
281- return acc
282-
283- raise RuntimeError (
284- 'CONCAT accepts FTL Patterns, TextElements and Placeables.'
285- )
286-
287- # Merge adjecent `FTL.TextElement` nodes.
288- def merge_adjecent_text (acc , cur ):
289- if type (cur ) == FTL .TextElement and len (acc ):
290- last = acc [- 1 ]
291- if type (last ) == FTL .TextElement :
292- last .value += cur .value
293- else :
294- acc .append (cur )
295- else :
296- acc .append (cur )
297- return acc
298-
299- elements = reduce (concat_elements , self .patterns , [])
300- elements = reduce (merge_adjecent_text , elements , [])
286+ elements = self .flatten_elements (self .patterns )
287+ elements = self .prune_text_elements (elements )
301288 return FTL .Pattern (elements )
302289
303290 def traverse (self , fun ):
0 commit comments