-module(bt_util). -export([to_file/1, to_jsonable_term/1]). -include("bt_nodes.hrl"). %% Usage: %% --- %% bt_util:to_jsonable_term(bt_yaml_parser:parse("src/samples/trees/rackloop.yml", "single_rackloop", [{"BId", 3}])). %% io:format("~s ~n", [jsx:encode(bt_util:to_jsonable_term(bt_yaml_parser:parse("src/samples/trees/rackloop.yml", "single_rackloop", [{"BId", 3}])))]). to_jsonable_term({RootNode, BB}) -> node_to_tree(<<"null">>, RootNode, BB). to_file(ParseResult) -> Data = jsx:encode(to_jsonable_term(ParseResult)), {ok, F} = file:open("treedata.js", [write]), file:write(F, "var treeData = ["), file:write(F, Data), file:write(F, "];"), file:close(F). node_to_tree(ParentName, #sequence{name = SequenceName, children = Children, metadata = Metadata}, BB) -> Name = list_to_binary(lists:flatten(SequenceName)), Map = #{name => Name, parent => ParentName, status => get_status(Metadata), type => sequence}, case length(Children) of 0 -> Map; _ -> maps:put(children, lists:map(fun(X) -> node_to_tree(Name, X, BB) end, Children), Map) end; node_to_tree(ParentName, #decorator{name = DecoratorName, child = Child, metadata = Metadata, args = Args, module = Module}, BB) -> Name = list_to_binary(lists:flatten(DecoratorName)), Attributes = get_attributes(Args, BB), Map = #{name => Name, parent => ParentName, status => get_status(Metadata), attributes => add_module_and_exception_attributes(Attributes, Module, get_exception(Metadata)), type => decorator}, maps:put(children, [node_to_tree(Name, Child, BB)], Map); node_to_tree(ParentName, #task{name = TaskName, metadata = Metadata, args = Args, module = Module}, BB) -> Name = list_to_binary(lists:flatten(TaskName)), Attributes = get_attributes(Args, BB), #{name => Name, parent => ParentName, status => get_status(Metadata), attributes => add_module_and_exception_attributes(Attributes, Module, get_exception(Metadata)), type => task}. get_status(undefined) -> unknown; get_status(#bt_metadata{status = Status}) -> Status. get_exception(undefined) -> undefined; get_exception(#bt_metadata{exception = Exception}) -> Exception. get_attributes(Args, BB) when is_map(Args) -> ArgsProplist = maps:to_list(Args), EvalFn = fun(Value, BBTemp) -> V = bt_blackboard:eval_with_default_fn(Value, BBTemp, fun (_BBKey) -> "???" end), %% need to serialize it so its jsonable to_list(V) end, WithValues = [ %% jsx doesn't like strings ?? both keys and values? %% https://github.com/talentdeficit/jsx/issues/81 {list_to_atom(Key), list_to_atom(EvalFn(Value, BB))} || {Key, Value} <- ArgsProplist ], maps:from_list(WithValues). add_module_and_exception_attributes(AttributesMap0, Module, Exception) -> AttributesMap1 = maps:put(node, Module, AttributesMap0), case Exception of undefined -> AttributesMap1; _ -> maps:put(exception, list_to_binary(to_list(Exception)), AttributesMap1) end. to_list(Tuple) -> lists:flatten(io_lib:format("~p", [Tuple])).