Current section

Files

Jump to
rondo lib rondo tree.ex
Raw

lib/rondo/tree.ex

defmodule Rondo.Tree do
defstruct [:descriptor, :root, :children, :actions]
alias Rondo.Path
alias Rondo.Component.Pointer
alias Rondo.Store.Reference
def init(nil, descriptor, component_path, state, store) do
tree = %__MODULE__{children: %{}, actions: MapSet.new()}
init(tree, descriptor, component_path, state, store)
end
def init(tree = %{descriptor: descriptor, actions: actions}, descriptor, component_path, state, store) do
store = Enum.reduce(actions, store, fn(action, store) ->
{_, store} = put_action(action, component_path, store, state)
store
end)
{tree, store}
end
def init(tree, descriptor, component_path, state, store) do
{root, {children, actions, store}} = traverse(descriptor, component_path, state, store)
tree = %{tree | descriptor: descriptor, root: root, children: children, actions: actions}
{tree, store}
end
def traverse(descriptor, component_path, state, store) do
acc = {%{}, MapSet.new(), store}
Rondo.Traverser.postwalk(descriptor, [], acc, fn
(%Rondo.Element{type: type, props: props, children: c} = el, path, {children, actions, store}) when not is_binary(type) ->
path = Path.create_child_path(component_path, path)
children = Map.put(children, path, el)
{%Pointer{type: type, props: props, children: c, path: path}, {children, actions, store}}
(%Reference{} = ref, _path, acc) ->
ref = resolve(ref, state.children, component_path)
{ref, acc}
(%Rondo.Action{reference: nil}, _path, acc) ->
{nil, acc}
(%Rondo.Action{} = action, _path, {children, actions, store}) ->
{instance, store} = put_action(action, component_path, store, state)
actions = MapSet.put(actions, action)
{instance, {children, actions, store}}
(%Rondo.Stream.Subscription{} = sub, _path, {children, actions, store}) ->
{sub, {children, actions, store}}
(node, _, acc) ->
{node, acc}
end)
end
defp put_action(action = %{reference: reference, events: events}, component_path, store, %{children: children}) do
case resolve(reference, children, component_path) do
nil ->
{nil, store}
descriptor ->
events = resolve_events(events, component_path, children, [])
action = %{action | reference: descriptor,
events: events}
Rondo.Action.Store.put(store, action)
end
end
defp resolve_events([], _, _, acc) do
:lists.reverse(acc)
end
defp resolve_events([event = %{reference: ref} | events], component_path, children, acc) do
case resolve(ref, children, component_path) do
nil ->
resolve_events(events, component_path, children, acc)
descriptor ->
event = %{event | reference: descriptor}
resolve_events(events, component_path, children, [event | acc])
end
end
defp resolve(%Reference{} = reference, children, component_path) do
case Reference.resolve(reference, children) do
:error ->
raise Reference.Error, reference: reference, component_path: component_path
{:ok, nil} ->
nil
{:ok, descriptor} ->
descriptor
end
end
defp resolve(%Rondo.Store{} = store, _, _) do
store
end
end