MishkaCmsCore.Runtime.PageBuilder.CodeReads (Mishka CMS Core v0.0.1)

Copy Markdown View Source

What a snippet reads, what it calls and what it assigns, read off the parsed code.

The sibling of MishkaCmsCore.Runtime.PageBuilder.CodeFlags, which answers a different question the same way: parse it, walk it, and let the shape of the tree say what a thing is. An assign is the node {:@, meta, [{name, meta, context}]} — so @flash inside a string, inside a comment, or written out in a code sample is not one, and neither is @moduledoc "…", whose context is the text rather than an atom.

iex> alias MishkaCmsCore.Runtime.PageBuilder.CodeReads
iex> CodeReads.assigns(~S|[@size, "@colour is not one"]|) |> MapSet.to_list()
["size"]

For a template rather than a snippet, MishkaCmsCore.Runtime.PageBuilder.Markup.expressions/1 gives the expressions to hand here.

What it does with code it cannot parse

Nothing found. An author is mid-sentence in a box they are typing into, and CodeCheck is what tells them the code will not compile — a half-typed line is not this module's news to break.

assigned/1 is the exception: its caller decides from the answer that an assign is NOT written, so code it cannot read is :unknown.

Summary

Functions

Every assign a snippet may write, by name — or :unknown when it writes one whose name it works out at runtime, or when it does not parse.

Every assign a snippet reads, by name and without the @.

Every call a snippet makes by a bare name, as {name, arguments} with the arguments still quoted.

Functions

assigned(code)

@spec assigned(String.t() | nil) :: {:ok, MapSet.t(String.t())} | :unknown

Every assign a snippet may write, by name — or :unknown when it writes one whose name it works out at runtime, or when it does not parse.

A write is:

  • assign/2,3, assign_new/3, assign_async/3,4 and update/3, bare, piped or on any module but Map;
  • on Map, put/3, put_new/3, put_new_lazy/3, replace/3, replace!/3, update/4, update!/3 and merge/2,3;
  • a map update, %{map | key: value};

  • put_in, update_in, get_and_update_in and pop_in on a path through assigns, which is :unknown.

A key given as anything but an atom — a variable, a call, a keyword list or map that is not written out — is :unknown. On Map and in a map update it is :unknown only when the map is assigns or socket.assigns; any other map there is ordinary data. assign(socket, assigns) writes nothing new: it hands the component what it was handed.

Unlike assigns/1, code that does not parse is :unknown rather than nothing.

iex> MishkaCmsCore.Runtime.PageBuilder.CodeReads.assigned(
...>   "socket |> assign(:page, 1) |> assign(loading: true)"
...> )
{:ok, MapSet.new(["loading", "page"])}

iex> MishkaCmsCore.Runtime.PageBuilder.CodeReads.assigned("assign(socket, key, 1)")
:unknown

assigns(code)

@spec assigns(String.t() | nil) :: MapSet.t(String.t())

Every assign a snippet reads, by name and without the @.

iex> MishkaCmsCore.Runtime.PageBuilder.CodeReads.assigns("@a <> @b") |> MapSet.to_list()
["a", "b"]

calls(code)

@spec calls(String.t() | nil) :: [{atom(), [Macro.t()]}]

Every call a snippet makes by a bare name, as {name, arguments} with the arguments still quoted.

Bare-name and nothing else: String.trim(x) is a call on a module and is not one of these, which is what makes this the right question to ask about a component's own helpers.