Skip to content

Commit d70e02b

Browse files
committed
fix: only de-paren sections and entities that have builders at the current level, not nested levels
1 parent 27f58e6 commit d70e02b

File tree

1 file changed

+131
-15
lines changed

1 file changed

+131
-15
lines changed

lib/spark/formatter.ex

Lines changed: 131 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)