   end
 
   @doc false
+  @spec encoded_expr(Macro.t()) :: Macro.t()
   def encoded_expr(expr) do
     quote @anno do
       Drab.Core.encode_js(unquote(expr))
     end
   end
 
+  @spec line_from_expr(Macro.t()) :: integer | nil
   defp line_from_expr({_, meta, _}) when is_list(meta), do: Keyword.get(meta, :line)
   defp line_from_expr(_), do: nil
 
   # @doc false
   # defp to_safe(literal), do: to_safe(literal, @anno)
 
+  @spec to_safe(Macro.t(), integer | nil) :: iodata
   defp to_safe(literal, _line) when is_binary(literal) or is_atom(literal) or is_number(literal) do
     Phoenix.HTML.Safe.to_iodata(literal)
   end

    end)
  end

  defp find_assign(
         {{:., _, [{:__aliases__, _, [:Phoenix, :HTML, :Engine]}, :fetch_assign]}, _, [_, name]}
       )

    |> String.replace(~r/\S+\s*=\s*[^'"\s]+\s+/s, "")
  end

  @spec take_at(list, integer) :: term
  defp take_at(list, index) do
    {item, _} = List.pop_at(list, index)
    item
  end

  @spec no_tags(String.t()) :: String.t()
  defp no_tags(html), do: String.replace(html, ~r/<\S+.*>/s, "")

  @spec script_tag(String.t() | []) :: [String.t()] | []
  defp script_tag([]), do: []

  defp script_tag(js) do
    ["<script drab-script>", js, "</script>\n"]
  end

  @spec assign_js(String.t(), atom) :: [String.t()]
  defp assign_js(partial, assign) do
    ["#{@jsvar}.assigns['#{partial}']['#{assign}'] = '", encoded_assign(assign), "';"]
  end

  @spec property_js(String.t(), atom, Macro.t()) :: [String.t()]
  defp property_js(ampere, property, expr) do
    ["#{@jsvar}.properties['#{ampere}']['#{property}'] = ", encoded_expr(expr), ";"]
  end

  @spec encoded_assign(atom) :: Macro.t()
  defp encoded_assign(assign) do
    assign_expr =
      quote @anno do
