Current section

Files

Jump to
sprocket src sprocket@context.erl
Raw

src/sprocket@context.erl

-module(sprocket@context).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([callback_param_from_string/1, dep/1, compare_deps/2, new/5, prepare_for_reconciliation/1, fetch_or_init_hook/2, update_hook/3, push_event_handler/2, get_event_handler/2, dispatch_event/4, provider/3]).
-export_type([callback_param/0, identifiable_handler/0, attribute/0, element/0, updater/1, dispatcher/0, hook_trigger/0, effect_result/0, callback_result/0, memo_result/0, hook/0, compared/1, component_wip/0, context/0]).
-type callback_param() :: {callback_string, binary()}.
-type identifiable_handler() :: {identifiable_handler,
sprocket@internal@utils@unique:unique(),
fun((gleam@option:option(callback_param())) -> nil)}.
-type attribute() :: {attribute, binary(), gleam@dynamic:dynamic_()} |
{event, binary(), identifiable_handler()} |
{client_hook, sprocket@internal@utils@unique:unique(), binary()}.
-type element() :: {element, binary(), list(attribute()), list(element())} |
{component,
fun((context(), gleam@dynamic:dynamic_()) -> {context(), element()}),
gleam@dynamic:dynamic_()} |
{fragment, list(element())} |
{debug, binary(), gleam@option:option(gleam@dynamic:dynamic_()), element()} |
{keyed, binary(), element()} |
{ignore_update, element()} |
{provider, binary(), gleam@dynamic:dynamic_(), element()} |
{text, binary()}.
-type updater(IAW) :: {updater, fun((IAW) -> {ok, nil} | {error, nil})}.
-type dispatcher() :: {dispatcher,
fun((binary(), binary(), gleam@option:option(binary())) -> {ok, nil} |
{error, nil})}.
-type hook_trigger() :: on_mount |
on_update |
{with_deps, list(gleam@dynamic:dynamic_())}.
-type effect_result() :: {effect_result,
gleam@option:option(fun(() -> nil)),
gleam@option:option(list(gleam@dynamic:dynamic_()))}.
-type callback_result() :: {callback_result,
gleam@option:option(list(gleam@dynamic:dynamic_()))}.
-type memo_result() :: {memo_result,
gleam@option:option(list(gleam@dynamic:dynamic_()))}.
-type hook() :: {callback,
sprocket@internal@utils@unique:unique(),
fun(() -> nil),
gleam@option:option(callback_result())} |
{memo,
sprocket@internal@utils@unique:unique(),
gleam@dynamic:dynamic_(),
gleam@option:option(memo_result())} |
{effect,
sprocket@internal@utils@unique:unique(),
fun(() -> gleam@option:option(fun(() -> nil))),
hook_trigger(),
gleam@option:option(effect_result())} |
{handler,
sprocket@internal@utils@unique:unique(),
fun((gleam@option:option(callback_param())) -> nil)} |
{reducer,
sprocket@internal@utils@unique:unique(),
gleam@dynamic:dynamic_(),
fun(() -> nil)} |
{state, sprocket@internal@utils@unique:unique(), gleam@dynamic:dynamic_()} |
{client,
sprocket@internal@utils@unique:unique(),
binary(),
gleam@option:option(fun((binary(), gleam@option:option(gleam@dynamic:dynamic_()), fun((binary(), gleam@option:option(binary())) -> {ok,
nil} |
{error, nil})) -> nil))}.
-type compared(IAX) :: {changed, IAX} | unchanged.
-type component_wip() :: {component_wip,
sprocket@internal@utils@ordered_map:ordered_map(integer(), hook()),
integer(),
boolean()}.
-type context() :: {context,
element(),
component_wip(),
list(identifiable_handler()),
fun(() -> nil),
fun((sprocket@internal@utils@unique:unique(), fun((hook()) -> hook())) -> nil),
fun((sprocket@internal@utils@unique:unique(), binary(), gleam@option:option(binary())) -> {ok,
nil} |
{error, nil}),
gleam@erlang@process:subject(ids@cuid:message()),
gleam@dict:dict(binary(), gleam@dynamic:dynamic_())}.
-spec callback_param_from_string(binary()) -> callback_param().
callback_param_from_string(Value) ->
{callback_string, Value}.
-spec dep(any()) -> gleam@dynamic:dynamic_().
dep(Dependency) ->
gleam@dynamic:from(Dependency).
-spec compare_deps(
list(gleam@dynamic:dynamic_()),
list(gleam@dynamic:dynamic_())
) -> compared(list(gleam@dynamic:dynamic_())).
compare_deps(Prev_deps, Deps) ->
case gleam@list:strict_zip(Prev_deps, Deps) of
{error, length_mismatch} ->
sprocket@internal@exceptions:throw_on_unexpected_deps_mismatch(
{<<"compare_deps"/utf8>>, Prev_deps, Deps}
);
{ok, Zipped_deps} ->
case gleam@list:all(
Zipped_deps,
fun(Z) ->
{A, B} = Z,
A =:= B
end
) of
true ->
unchanged;
_ ->
{changed, Deps}
end
end.
-spec new(
element(),
gleam@erlang@process:subject(ids@cuid:message()),
gleam@option:option(dispatcher()),
fun(() -> nil),
fun((sprocket@internal@utils@unique:unique(), fun((hook()) -> hook())) -> nil)
) -> context().
new(View, Cuid_channel, Dispatcher, Render_update, Update_hook) ->
{context,
View,
{component_wip, sprocket@internal@utils@ordered_map:new(), 0, true},
[],
Render_update,
Update_hook,
fun(Id, Name, Payload) -> case Dispatcher of
{some, {dispatcher, Dispatch}} ->
Dispatch(
sprocket@internal@utils@unique:to_string(Id),
Name,
Payload
);
none ->
{error, nil}
end end,
Cuid_channel,
gleam@dict:new()}.
-spec prepare_for_reconciliation(context()) -> context().
prepare_for_reconciliation(Ctx) ->
erlang:setelement(4, Ctx, []).
-spec fetch_or_init_hook(context(), fun(() -> hook())) -> {context(),
hook(),
integer()}.
fetch_or_init_hook(Ctx, Init) ->
Index = erlang:element(3, erlang:element(3, Ctx)),
Hooks = erlang:element(2, erlang:element(3, Ctx)),
case sprocket@internal@utils@ordered_map:get(Hooks, Index) of
{ok, Hook} ->
{erlang:setelement(
3,
Ctx,
erlang:setelement(3, erlang:element(3, Ctx), Index + 1)
),
Hook,
Index};
{error, nil} ->
case erlang:element(4, erlang:element(3, Ctx)) of
true ->
nil;
false ->
sprocket@internal@logger:error(
<<<<"
Hook not found for index: "/utf8,
(gleam@int:to_string(Index))/binary>>/binary,
". This indicates a hook was dynamically
created since first render which is not allowed.
"/utf8>>
),
erlang:error(#{gleam_error => panic,
message => <<"panic expression evaluated"/utf8>>,
module => <<"sprocket/context"/utf8>>,
function => <<"fetch_or_init_hook"/utf8>>,
line => 215})
end,
Hook@1 = Init(),
{erlang:setelement(
3,
Ctx,
{component_wip,
sprocket@internal@utils@ordered_map:insert(
erlang:element(2, erlang:element(3, Ctx)),
Index,
Hook@1
),
Index + 1,
erlang:element(4, erlang:element(3, Ctx))}
),
Hook@1,
Index}
end.
-spec update_hook(context(), hook(), integer()) -> context().
update_hook(Ctx, Hook, Index) ->
erlang:setelement(
3,
Ctx,
erlang:setelement(
2,
erlang:element(3, Ctx),
sprocket@internal@utils@ordered_map:update(
erlang:element(2, erlang:element(3, Ctx)),
Index,
Hook
)
)
).
-spec push_event_handler(context(), identifiable_handler()) -> {context(),
sprocket@internal@utils@unique:unique()}.
push_event_handler(Ctx, Identifiable_cb) ->
{identifiable_handler, Id, Cb} = Identifiable_cb,
{erlang:setelement(
4,
Ctx,
[{identifiable_handler, Id, Cb} | erlang:element(4, Ctx)]
),
Id}.
-spec get_event_handler(context(), sprocket@internal@utils@unique:unique()) -> {context(),
{ok, identifiable_handler()} | {error, nil}}.
get_event_handler(Ctx, Id) ->
Handler = gleam@list:find(
erlang:element(4, Ctx),
fun(H) ->
{identifiable_handler, I, _} = H,
I =:= Id
end
),
{Ctx, Handler}.
-spec dispatch_event(
context(),
sprocket@internal@utils@unique:unique(),
binary(),
gleam@option:option(binary())
) -> {ok, nil} | {error, nil}.
dispatch_event(Ctx, Id, Name, Payload) ->
(erlang:element(7, Ctx))(Id, Name, Payload).
-spec provider(binary(), any(), element()) -> element().
provider(Key, Value, Element) ->
{provider, Key, gleam@dynamic:from(Value), Element}.