@@ -204,26 +204,142 @@ if Code.ensure_loaded?(Sourceror) do
204204 end
205205
206206 defp de_paren_section ( body , section , extensions , opts ) do
207- locals_without_parens = Keyword . get ( opts , :locals_without_parens , [ ] )
207+ lwp = Keyword . get ( opts , :locals_without_parens , [ ] )
208+ process_section_body ( body , section , extensions , lwp , [ section . name ] )
209+ end
208210
209- builders = all_entity_builders ( [ section ] , extensions ) ++ locals_without_parens
211+ defp process_section_body ( args , section , extensions , lwp , path ) do
212+ entities = section_entities_at_path ( section , extensions , path )
213+ builders = section_level_builders ( section , entities ) ++ lwp
214+ children = section_children ( section , entities )
215+ find_and_process_do_blocks ( args , builders , children , extensions , lwp , path )
216+ end
210217
211- Macro . prewalk ( body , fn
212- { func , meta , body } = node when is_atom ( func ) ->
213- count = Enum . count ( List . wrap ( body ) )
218+ defp process_entity_body ( args , entity , extensions , lwp ) do
219+ nested = all_nested_entities ( entity )
220+ builders = entity_level_builders ( entity , nested ) ++ lwp
221+ children = entity_children ( nested )
222+ find_and_process_do_blocks ( args , builders , children , extensions , lwp , [ ] )
223+ end
214224
215- builders = Keyword . get_values ( builders , func )
225+ defp find_and_process_do_blocks ( args , builders , children , extensions , lwp , path )
226+ when is_list ( args ) do
227+ Enum . map ( args , fn
228+ kw when is_list ( kw ) ->
229+ Enum . map ( kw , fn
230+ { { :__block__ , bm , [ :do ] } , { :__block__ , body_meta , body_exprs } } ->
231+ { { :__block__ , bm , [ :do ] } ,
232+ { :__block__ , body_meta ,
233+ Enum . map (
234+ body_exprs ,
235+ & de_paren_at_level ( & 1 , builders , children , extensions , lwp , path )
236+ ) } }
237+
238+ { { :__block__ , bm , [ :do ] } , single_expr } ->
239+ { { :__block__ , bm , [ :do ] } ,
240+ de_paren_at_level ( single_expr , builders , children , extensions , lwp , path ) }
241+
242+ other ->
243+ other
244+ end )
216245
217- if Enum . any? ( builders , & ( & 1 in [ count , count - 1 ] ) ) &&
218- Keyword . keyword? ( meta ) &&
219- meta [ :closing ] do
220- { func , Keyword . delete ( meta , :closing ) , body }
221- else
222- node
223- end
246+ other ->
247+ other
248+ end )
249+ end
250+
251+ defp find_and_process_do_blocks ( args , _ , _ , _ , _ , _ ) , do: args
252+
253+ defp de_paren_at_level ( { func , meta , args } , builders , children , extensions , lwp , path )
254+ when is_atom ( func ) do
255+ count = Enum . count ( List . wrap ( args ) )
256+ matched = Keyword . get_values ( builders , func )
257+
258+ meta =
259+ if Enum . any? ( matched , & ( & 1 in [ count , count - 1 ] ) ) &&
260+ Keyword . keyword? ( meta ) &&
261+ meta [ :closing ] do
262+ Keyword . delete ( meta , :closing )
263+ else
264+ meta
265+ end
266+
267+ args =
268+ case Map . get ( children , func ) do
269+ { :section , subsection } ->
270+ process_section_body ( args , subsection , extensions , lwp , path ++ [ subsection . name ] )
271+
272+ { :entity , entity } ->
273+ process_entity_body ( args , entity , extensions , lwp )
274+
275+ nil ->
276+ args
277+ end
278+
279+ { func , meta , args }
280+ end
281+
282+ defp de_paren_at_level ( node , _ , _ , _ , _ , _ ) , do: node
283+
284+ defp section_entities_at_path ( section , extensions , path ) do
285+ patched =
286+ extensions
287+ |> Enum . flat_map ( & & 1 . dsl_patches ( ) )
288+ |> Enum . filter ( fn
289+ % Spark.Dsl.Patch.AddEntity { section_path: ^ path } -> true
290+ _ -> false
291+ end )
292+ |> Enum . map ( & & 1 . entity )
293+
294+ section . entities ++ patched
295+ end
296+
297+ defp section_level_builders ( section , entities ) do
298+ section_option_builders ( section ) ++
299+ Enum . flat_map ( entities , fn entity ->
300+ arg_count = Enum . count ( entity . args )
301+ non_optional = Enum . count ( entity . args , & is_atom / 1 )
302+
303+ Enum . flat_map ( non_optional .. arg_count , fn n ->
304+ [ { entity . name , n } , { entity . name , n + 1 } ]
305+ end )
306+ end )
307+ end
308+
309+ defp entity_level_builders ( entity , nested_entities ) do
310+ entity_args_to_drop = Spark.Dsl.Entity . required_arg_names ( entity )
311+
312+ option_builders =
313+ entity . schema
314+ |> Keyword . drop ( entity_args_to_drop )
315+ |> Enum . map ( fn { key , _ } -> { key , 1 } end )
316+
317+ nested_builders =
318+ Enum . flat_map ( nested_entities , fn nested ->
319+ arg_count = Enum . count ( nested . args )
320+ non_optional = Enum . count ( nested . args , & is_atom / 1 )
321+
322+ Enum . flat_map ( non_optional .. arg_count , fn n ->
323+ [ { nested . name , n } , { nested . name , n + 1 } ]
324+ end )
325+ end )
326+
327+ option_builders ++ nested_builders
328+ end
329+
330+ defp section_children ( section , entities ) do
331+ entity_map = Map . new ( entities , & { & 1 . name , { :entity , & 1 } } )
332+ section_map = Map . new ( section . sections , & { & 1 . name , { :section , & 1 } } )
333+ Map . merge ( entity_map , section_map )
334+ end
335+
336+ defp entity_children ( nested_entities ) do
337+ Map . new ( nested_entities , & { & 1 . name , { :entity , & 1 } } )
338+ end
224339
225- node ->
226- node
340+ defp all_nested_entities ( entity ) do
341+ Enum . flat_map ( entity . entities , fn { _ , nested } ->
342+ List . wrap ( nested )
227343 end )
228344 end
229345
0 commit comments