Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created custom type Earmark.Options.options; added type specs for functions using options #481

Merged
merged 7 commits into from
Mar 4, 2024
15 changes: 11 additions & 4 deletions lib/earmark/earmark_parser_proxy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@ defmodule Earmark.EarmarkParserProxy do
@doc ~S"""
An adapter to `Earmark.Parser.as_ast/*`
"""
@spec as_ast([String.t()] | String.t(), Earmark.Options.options()) ::
{:error, binary(), [any()]} | {:ok, binary(), [map()]}
def as_ast(input, options)
def as_ast(input, options) when is_list(options) do
Earmark.Parser.as_ast(input, options |> Keyword.delete(:smartypants) |> Keyword.delete(:messages))

def as_ast(input, options) when is_list(options) do
Earmark.Parser.as_ast(
input,
options |> Keyword.delete(:smartypants) |> Keyword.delete(:messages)
)
end
def as_ast(input, options) when is_map(options) do

def as_ast(input, options) when is_map(options) do
Earmark.Parser.as_ast(input, options |> Map.delete(:smartypants) |> Map.delete(:messages))
end

end

# SPDX-License-Identifier: Apache-2.0
3 changes: 1 addition & 2 deletions lib/earmark/helpers.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
defmodule Earmark.Helpers do

@doc """
`Regex.replace` with the arguments in the correct order
"""

@spec replace(String.t(), Regex.t(), String.t(), Earmark.Options.options()) :: String.t()
def replace(text, regex, replacement, options \\ []) do
Regex.replace(regex, text, replacement, options)
end
Expand Down
18 changes: 12 additions & 6 deletions lib/earmark/internal.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
defmodule Earmark.Internal do

@moduledoc ~S"""
All public functions that are internal to Earmark, so that **only** external API
functions are public in `Earmark`
Expand All @@ -21,6 +20,7 @@ defmodule Earmark.Internal do

"""
def as_ast!(markdown, options \\ [])

def as_ast!(markdown, options) do
case Proxy.as_ast(markdown, options) do
{:ok, result, _} -> result
Expand All @@ -32,18 +32,22 @@ defmodule Earmark.Internal do
def as_html(lines, options)

def as_html(lines, options) when is_list(options) do
case Options.make_options(options) do
case Options.make_options(options) do
{:ok, options1} -> as_html(lines, options1)
{:error, messages} -> {:error, "", messages}
end
end

def as_html(lines, options) do
{status, ast, messages} = Transform.postprocessed_ast(lines, %{options| messages: MapSet.new([])})
{status, ast, messages} =
Transform.postprocessed_ast(lines, %{options | messages: MapSet.new([])})

{status, Transform.transform(ast, options), messages}
end

@spec as_html!([String.t()] | String.t(), Options.options()) :: String.t()
def as_html!(lines, options \\ [])

def as_html!(lines, options) do
{_status, html, messages} = as_html(lines, options)
emit_messages(messages, options)
Expand Down Expand Up @@ -81,9 +85,10 @@ defmodule Earmark.Internal do
options_ =
options
|> Options.relative_filename(filename)

case Path.extname(filename) do
".eex" -> EEx.eval_file(options_.file, include: &include(&1, options_))
_ -> SysInterface.readlines(options_.file) |> Enum.to_list
_ -> SysInterface.readlines(options_.file) |> Enum.to_list()
end
end

Expand All @@ -92,10 +97,11 @@ defmodule Earmark.Internal do
ends in `.eex`

The returned string is then passed to `as_html` this is used in the escript now and allows
for a simple inclusion mechanism, as a matter of fact an `include` function is passed
for a simple inclusion mechanism, as a matter of fact an `include` function is passed

"""
def from_file!(filename, options \\ [])

def from_file!(filename, options) do
filename
|> include(options)
Expand Down Expand Up @@ -123,6 +129,6 @@ defmodule Earmark.Internal do
Error,
"#{inspect(task)} has not responded within the set timeout of #{timeout}ms, consider increasing it"
)

end

# SPDX-License-Identifier: Apache-2.0
6 changes: 4 additions & 2 deletions lib/earmark/message.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
defmodule Earmark.Message do
@moduledoc false

alias Earmark.Options
@moduledoc false

def emit_messages(messages, %Options{file: file}) do
messages
|> Enum.each(&emit_message(file, &1))
end

def emit_messages(messages, proplist) when is_list(proplist) do
messages
|> Enum.each(&emit_message(proplist[:file], &1))
Expand All @@ -15,9 +15,11 @@ defmodule Earmark.Message do
defp emit_message(filename, msg), do: IO.puts(:stderr, format_message(filename, msg))

defp format_message(filenale, message)

defp format_message(nil, {type, line, text}) do
"<no file>:#{line}: #{type}: #{text}"
end

defp format_message(filename, {type, line, text}) do
"#{filename}:#{line}: #{type}: #{text}"
end
Expand Down
11 changes: 11 additions & 0 deletions lib/earmark/options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ defmodule Earmark.Options do
timeout: nil,
wikilinks: false

@type options ::
t()
| Earmark.Parser.Options.t()
| map()
| maybe_improper_list()
| Keyword.t()

@doc ~S"""
Make a legal and normalized Option struct from, maps or keyword lists

Expand Down Expand Up @@ -115,6 +122,9 @@ defmodule Earmark.Options do
{:error, [{:error, 0, "footnote_offset option must be numeric"}, {:error, 0, "line option must be numeric"}]}

"""
@spec make_options(options()) ::
{:ok, options()}
| {:error, [{atom(), integer(), String.t()}]}

def make_options(options \\ [])

Expand Down Expand Up @@ -191,6 +201,7 @@ defmodule Earmark.Options do
"./local.md"

"""
@spec relative_filename(options(), String.t()) :: options()
def relative_filename(options, filename)

def relative_filename(options, filename) when is_list(options) do
Expand Down
18 changes: 16 additions & 2 deletions lib/earmark/transform.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ defmodule Earmark.Transform do
alias Earmark.EarmarkParserProxy, as: Proxy
alias __MODULE__.Pop

@compact_tags ~w[a code em strong del]
@type node_or_string() :: Earmark.ast_node() | String.t()

@compact_tags ~w[a code em strong del]
# https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#void-element
@void_elements ~W(area base br col command embed hr img input keygen link meta param source track wbr)

Expand Down Expand Up @@ -223,7 +224,7 @@ defmodule Earmark.Transform do


"""

@spec make_postprocessor(Options.options()) :: (node_or_string() -> node_or_string())
def make_postprocessor(options)

def make_postprocessor(%{postprocessor: nil, registered_processors: rps}),
Expand All @@ -235,6 +236,9 @@ defmodule Earmark.Transform do
@line_end ~r{\n\r?}

@doc false
@spec postprocessed_ast([String.t()] | String.t(), Options.options()) ::
{:ok, Earmark.ast_node(), [Earmark.Error.t()]}
| {:error, Earmark.ast_node(), [Earmark.Error.t()]}
def postprocessed_ast(lines, options)

def postprocessed_ast(lines, options) when is_binary(lines),
Expand All @@ -258,6 +262,7 @@ defmodule Earmark.Transform do
@doc """
Transforms an AST to html, also accepts the result of `map_ast_with` for convenience
"""
@spec transform(Earmark.ast_node(), Options.options()) :: String.t()
def transform(ast, options \\ %{initial_indent: 0, indent: 2, compact_output: false})
def transform({ast, _}, options), do: transform(ast, options)

Expand Down Expand Up @@ -297,6 +302,8 @@ defmodule Earmark.Transform do
...(13)> map_ast(ast, &Earmark.AstTools.merge_atts_in_node(&1, class: "private"), true)
[{"ul", [{"class", "private"}], [{"li", [{"class", "private"}], ["one"], %{}}, {"li", [{"class", "private"}], ["two"], %{}}], %{}}]
"""
@spec map_ast(Earmark.ast_node(), (Earmark.ast_node() -> Earmark.ast_node()), boolean()) ::
Earmark.ast_node()
def map_ast(ast, fun, ignore_strings \\ false) do
_walk_ast(ast, fun, ignore_strings, [])
end
Expand All @@ -320,6 +327,13 @@ defmodule Earmark.Transform do
{[{"ul", [], [{"li", [], ["*"], %{}}], %{}}, {"p", [], ["*"], %{}}, {"ul", [], [{"li", [], ["*"], %{}}], %{}}], 6}

"""
@spec map_ast_with(
Earmark.ast(),
any(),
(Earmark.ast_node(), any() -> {Earmark.ast_node(), any()}),
boolean()
) ::
{Earmark.ast(), any()}
def map_ast_with(ast, value, fun, ignore_strings \\ false) do
_walk_ast_with(ast, value, fun, ignore_strings, [])
end
Expand Down
2 changes: 2 additions & 0 deletions lib/earmark_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,8 @@ defmodule Earmark.Parser do

The AST is exposed in the spirit of [Floki's](https://hex.pm/packages/floki).
"""
@spec as_ast([String.t()] | String.t(), Earmark.Options.options()) ::
{:error, binary(), [any()]} | {:ok, binary(), [map()]}
def as_ast(lines, options \\ %Options{})

def as_ast(lines, %Options{} = options) do
Expand Down
1 change: 1 addition & 0 deletions lib/earmark_parser/options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ defmodule Earmark.Parser.Options do
...(1)> options.annotations
~r{\A(.*)(%%.*)}
"""
@spec normalize(Earmark.Options.options()) :: Earmark.Options.options()
def normalize(options)

def normalize(%__MODULE__{} = options) do
Expand Down
Loading