-module(ginger). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/ginger.gleam"). -export([from_file/1, from_string/1, render/2, render_with_loops/2, new_context/0, set_variable/3, set_list/3, new_engine/1, load_template_content/2, render_template/3, render_simple_template/3, clear_cache/1, context_from_list/1]). -export_type([template/0, template_context/0, template_engine/0, template_error/0]). -type template() :: {template, binary()}. -type template_context() :: {template_context, gleam@dict:dict(binary(), binary()), gleam@dict:dict(binary(), list(binary()))}. -type template_engine() :: {template_engine, binary(), gleam@dict:dict(binary(), binary())}. -type template_error() :: {io_error, binary()} | {regex_error, binary()}. -file("src/ginger.gleam", 29). -spec from_file(binary()) -> {ok, template()} | {error, template_error()}. from_file(Path) -> case simplifile:read(Path) of {ok, Content} -> {ok, {template, Content}}; {error, _} -> {error, {io_error, <<"Failed to read file: "/utf8, Path/binary>>}} end. -file("src/ginger.gleam", 36). -spec from_string(binary()) -> template(). from_string(Content) -> {template, Content}. -file("src/ginger.gleam", 72). -spec replace_matches( binary(), list(gleam@regexp:match()), gleam@dict:dict(binary(), binary()) ) -> binary(). replace_matches(Content, Matches, Context) -> gleam@list:fold( Matches, Content, fun(Acc, Match) -> case erlang:element(3, Match) of [{some, Var_name}] -> case gleam_stdlib:map_get(Context, Var_name) of {ok, Value} -> gleam@string:replace( Acc, erlang:element(2, Match), Value ); {error, _} -> Acc end; _ -> Acc end end ). -file("src/ginger.gleam", 58). -spec render_variables(binary(), gleam@dict:dict(binary(), binary())) -> {ok, binary()} | {error, template_error()}. render_variables(Content, Context) -> case gleam@regexp:from_string(<<"\\{\\{\\s*(\\w+)\\s*\\}\\}"/utf8>>) of {ok, Re} -> Matches = gleam@regexp:scan(Re, Content), Result = replace_matches(Content, Matches, Context), {ok, Result}; {error, _} -> {error, {regex_error, <<"Failed to compile variable regex"/utf8>>}} end. -file("src/ginger.gleam", 40). -spec render(template(), gleam@dict:dict(binary(), binary())) -> {ok, binary()} | {error, template_error()}. render(Template, Context) -> {template, Content} = Template, render_variables(Content, Context). -file("src/ginger.gleam", 137). -spec replace_loop_variable(binary(), binary(), binary()) -> binary(). replace_loop_variable(Template, Var_name, Value) -> Target = <<<<"{{ "/utf8, Var_name/binary>>/binary, " }}"/utf8>>, Target_no_spaces = <<<<"{{"/utf8, Var_name/binary>>/binary, "}}"/utf8>>, _pipe = Template, _pipe@1 = gleam@string:replace(_pipe, Target, Value), gleam@string:replace(_pipe@1, Target_no_spaces, Value). -file("src/ginger.gleam", 106). -spec process_loops_recursive( binary(), template_context(), gleam@regexp:regexp() ) -> {ok, binary()} | {error, template_error()}. process_loops_recursive(Content, Context, Loop_re) -> case gleam@regexp:scan(Loop_re, Content) of [] -> {ok, Content}; [First_match | _] -> case erlang:element(3, First_match) of [{some, Var_name}, {some, List_name}, {some, Loop_body}] -> Loop_result = case gleam_stdlib:map_get( erlang:element(3, Context), List_name ) of {ok, Items} -> gleam@list:fold( Items, <<""/utf8>>, fun(Acc, Item) -> Item_content = replace_loop_variable( Loop_body, Var_name, Item ), <> end ); {error, _} -> <<""/utf8>> end, New_content = gleam@string:replace( Content, erlang:element(2, First_match), Loop_result ), process_loops_recursive(New_content, Context, Loop_re); _ -> {ok, Content} end end. -file("src/ginger.gleam", 90). -spec process_loops(binary(), template_context()) -> {ok, binary()} | {error, template_error()}. process_loops(Content, Context) -> case gleam@regexp:from_string( <<"\\{%\\s*for\\s+(\\w+)\\s+in\\s+(\\w+)\\s*%\\}([\\s\\S]*?)\\{%\\s*endfor\\s*%\\}"/utf8>> ) of {ok, Loop_re} -> process_loops_recursive(Content, Context, Loop_re); {error, _} -> {error, {regex_error, <<"Failed to compile loop regex"/utf8>>}} end. -file("src/ginger.gleam", 48). -spec render_with_loops(template(), template_context()) -> {ok, binary()} | {error, template_error()}. render_with_loops(Template, Context) -> {template, Content} = Template, gleam@result:'try'( process_loops(Content, Context), fun(Looped_content) -> render_variables(Looped_content, erlang:element(2, Context)) end ). -file("src/ginger.gleam", 150). -spec new_context() -> template_context(). new_context() -> {template_context, maps:new(), maps:new()}. -file("src/ginger.gleam", 154). -spec set_variable(template_context(), binary(), binary()) -> template_context(). set_variable(Context, Key, Value) -> {template_context, gleam@dict:insert(erlang:element(2, Context), Key, Value), erlang:element(3, Context)}. -file("src/ginger.gleam", 165). -spec set_list(template_context(), binary(), list(binary())) -> template_context(). set_list(Context, Key, Items) -> {template_context, erlang:element(2, Context), gleam@dict:insert(erlang:element(3, Context), Key, Items)}. -file("src/ginger.gleam", 176). -spec new_engine(binary()) -> template_engine(). new_engine(Template_dir) -> {template_engine, Template_dir, maps:new()}. -file("src/ginger.gleam", 180). -spec load_template_content(template_engine(), binary()) -> {ok, {template_engine(), binary()}} | {error, template_error()}. load_template_content(Engine, Name) -> case gleam_stdlib:map_get(erlang:element(3, Engine), Name) of {ok, Content} -> {ok, {Engine, Content}}; {error, _} -> Template_path = <<<<<<(erlang:element(2, Engine))/binary, "/"/utf8>>/binary, Name/binary>>/binary, ".html"/utf8>>, case simplifile:read(Template_path) of {ok, Content@1} -> New_cache = gleam@dict:insert( erlang:element(3, Engine), Name, Content@1 ), New_engine = {template_engine, erlang:element(2, Engine), New_cache}, {ok, {New_engine, Content@1}}; {error, _} -> {error, {io_error, <<"Failed to load template: "/utf8, Template_path/binary>>}} end end. -file("src/ginger.gleam", 200). -spec render_template(template_engine(), binary(), template_context()) -> {ok, {template_engine(), binary()}} | {error, template_error()}. render_template(Engine, Template_name, Context) -> gleam@result:'try'( load_template_content(Engine, Template_name), fun(_use0) -> {New_engine, Content} = _use0, Template = {template, Content}, gleam@result:'try'( render_with_loops(Template, Context), fun(Rendered) -> {ok, {New_engine, Rendered}} end ) end ). -file("src/ginger.gleam", 214). -spec render_simple_template( template_engine(), binary(), gleam@dict:dict(binary(), binary()) ) -> {ok, {template_engine(), binary()}} | {error, template_error()}. render_simple_template(Engine, Template_name, Context) -> gleam@result:'try'( load_template_content(Engine, Template_name), fun(_use0) -> {New_engine, Content} = _use0, Template = {template, Content}, gleam@result:'try'( render(Template, Context), fun(Rendered) -> {ok, {New_engine, Rendered}} end ) end ). -file("src/ginger.gleam", 228). -spec clear_cache(template_engine()) -> template_engine(). clear_cache(Engine) -> {template_engine, erlang:element(2, Engine), maps:new()}. -file("src/ginger.gleam", 232). -spec context_from_list(list({binary(), binary()})) -> template_context(). context_from_list(Variables) -> Var_dict = maps:from_list(Variables), {template_context, Var_dict, maps:new()}.