Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b77055c
look_for_alignments/1 Consolidated two Enum.map together; other chang…
bradhanks Feb 17, 2024
d1d337a
_split_table_columns/1: combined two Enum.map function calls
bradhanks Feb 17, 2024
4725020
refactored some conditionals to pattern matching
bradhanks Feb 17, 2024
9f3ef38
undo Enum.map refactor
bradhanks Feb 18, 2024
6d76148
Merge branch 'master' of https://github.com/bradhanks/earmark_parser
bradhanks Mar 17, 2025
e9ae60f
consolidated block modules into a single file, add types for Line and…
bradhanks Mar 17, 2025
cadc78e
EarmarkParser.Message typing edits
bradhanks Mar 17, 2025
f5dd60c
applied pre-existing alias, renamed nv -> new_value
bradhanks Mar 17, 2025
2211317
Options.t edits: renderer and math were missing. normalize/1 lets the…
bradhanks Mar 18, 2025
dfe67c5
`new/2` type specification with aliases for EarmarkParser.Options and…
bradhanks Mar 18, 2025
adc96fc
ListInfo.t type definition
bradhanks Mar 18, 2025
19c70ca
added EarmarkParser.{Options, Line}; added type specifications for Ea…
bradhanks Mar 18, 2025
85d7c1e
refactor from case to pattern matching; added new helper function `_…
bradhanks Mar 18, 2025
4b6e1ee
type specification for `parse_markdown/2`
bradhanks Mar 18, 2025
293e600
type specification for `parse_list/3`
bradhanks Mar 18, 2025
ce89aa6
EarmarkParser.AstRenderer.render type specification
bradhanks Mar 18, 2025
6074cb0
Fixed dialyzer warnings:
bradhanks Mar 18, 2025
817c738
EarmarkParser.Helpers.LookaheadHelpers type specification
bradhanks Mar 18, 2025
784f13a
Type specifications for EarmarkParser.Message functions; fixed ts() …
bradhanks Mar 18, 2025
ea95ebe
Merge branch 'master' of https://github.com/RobertDober/earmark_parse…
bradhanks Mar 18, 2025
48514f6
type spec fix
bradhanks Mar 18, 2025
2237e35
mix format
bradhanks Mar 18, 2025
2a61c7e
https://github.com/RobertDober/earmark_parser/pull/168#discussion_r20…
bradhanks Mar 19, 2025
a6cef10
updated @void_tag to make list comprehensive
bradhanks Mar 19, 2025
8483cfe
https://github.com/RobertDober/earmark_parser/pull/168#discussion_r20…
bradhanks Mar 19, 2025
3850a90
https://github.com/RobertDober/earmark_parser/pull/168#discussion_r20…
bradhanks Mar 19, 2025
9a2cd28
mix format
bradhanks Mar 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions lib/earmark_parser.ex
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
defmodule EarmarkParser do
@type ast_meta :: map()
@type ast_tag :: binary()
@type ast_attribute_name :: binary()
@type ast_attribute_value :: binary()
@type ast_tag :: String.t()
@type ast_attribute_name :: String.t()
@type ast_attribute_value :: String.t()
@type ast_attribute :: {ast_attribute_name(), ast_attribute_value()}
@type ast_attributes :: list(ast_attribute())
@type ast_tuple :: {ast_tag(), ast_attributes(), ast(), ast_meta()}
@type ast_node :: binary() | ast_tuple()
@type ast_node :: String.t() | ast_tuple()
@type ast :: list(ast_node())

@type error :: {atom(), non_neg_integer(), binary()}
@type error :: {atom(), non_neg_integer(), String.t()}
@type errors :: list(error())

@type t :: {:ok, ast(), []} | {:error, ast(), errors()}
Expand Down Expand Up @@ -615,7 +615,7 @@ defmodule EarmarkParser do

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

def as_ast(lines, %Options{} = options) do
Expand Down
1 change: 1 addition & 0 deletions lib/earmark_parser/ast_renderer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule EarmarkParser.AstRenderer do

@moduledoc false

@spec render([Block.t()], Context.t(), boolean()) :: Context.t()
def render(blocks, context = %Context{options: %Options{}}, loose? \\ true) do
_render(blocks, context, loose?)
end
Expand Down
8 changes: 4 additions & 4 deletions lib/earmark_parser/context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ defmodule EarmarkParser.Context do
alias EarmarkParser.Options

@type t :: %__MODULE__{
options: EarmarkParser.Options.t(),
options: Options.t(),
links: map(),
footnotes: map(),
referenced_footnote_ids: MapSet.t(String.t()),
value: String.t() | [String.t()]
}

defstruct options: %EarmarkParser.Options{},
defstruct options: %Options{},
links: Map.new(),
rules: nil,
footnotes: Map.new(),
Expand All @@ -23,8 +23,8 @@ defmodule EarmarkParser.Context do

@doc false
def modify_value(%__MODULE__{value: value} = context, fun) do
nv = fun.(value)
%{context | value: nv}
new_value = fun.(value)
%{context | value: new_value}
end

@doc false
Expand Down
5 changes: 5 additions & 0 deletions lib/earmark_parser/helpers/lookahead_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ defmodule EarmarkParser.Helpers.LookaheadHelpers do

import EarmarkParser.Helpers.LeexHelpers

@type backtix_string :: String.t()
@type natural :: non_neg_integer()

@doc """
Indicates if the _numbered_line_ passed in leaves an inline code block open.

Expand All @@ -11,6 +14,7 @@ defmodule EarmarkParser.Helpers.LookaheadHelpers do

Otherwise `{nil, 0}` is returned
"""
@spec opens_inline_code(EarmarkParser.Line.t()) :: {backtix_string | nil, natural}
def opens_inline_code(%{line: line, lnb: lnb}) do
case tokenize(line, with: :earmark_parser_string_lexer) |> has_still_opening_backtix(nil) do
nil -> {nil, 0}
Expand All @@ -26,6 +30,7 @@ defmodule EarmarkParser.Helpers.LookaheadHelpers do
opening backtix
"""
# (#{},{_,_}) -> {_,_}
@spec still_inline_code(EarmarkParser.Line.t(), {backtix_string, natural}) :: {backtix_string | nil, natural}
def still_inline_code(%{line: line, lnb: lnb}, old = {pending, _pending_lnb}) do
case tokenize(line, with: :earmark_parser_string_lexer) |> has_still_opening_backtix({:old, pending}) do
nil -> {nil, 0}
Expand Down
15 changes: 15 additions & 0 deletions lib/earmark_parser/line.ex
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,21 @@ defmodule EarmarkParser.Line do
initial_indent: 0,
list_indent: 0
)

@type natural :: non_neg_integer()

@type t :: %__MODULE__{
annotation: nil | String.t(),
ial: nil | String.t(),
lnb: natural,
type: :ul | :ol,
line: String.t(),
indent: natural,
bullet: String.t(),
content: String.t(),
initial_indent: natural,
list_indent: natural
}
end

defmodule SetextUnderlineHeading do
Expand Down
2 changes: 1 addition & 1 deletion lib/earmark_parser/line_scanner/rgx.ex
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ defmodule EarmarkParser.LineScanner.Rgx do
Regex.run(~r/\A (?:_\s?){3,} \z/x, content)
end

@void_tags ~w{area br hr img wbr}
@void_tags ~w{area base br col embed hr img input link meta param source track wbr}
def void_tag_rgx do
~r'''
^<( #{Enum.join(@void_tags, "|")} )
Expand Down
12 changes: 8 additions & 4 deletions lib/earmark_parser/message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ defmodule EarmarkParser.Message do
alias EarmarkParser.Context
alias EarmarkParser.Options

@type message_type :: :error | :warning
@type t :: {message_type, number, binary}
@type ts :: list(t)
@type container_type :: Options.t() | Context.t()
@type message_type :: :error | :warning | :deprecated
@type t :: {message_type, non_neg_integer(), String.t()}
@type ts :: [t()]
@type container :: Options.t() | Context.t()

@spec add_messages(container, ts()) :: container
def add_messages(container, messages) do
Enum.reduce(messages, container, &add_message(&2, &1))
end

@spec add_message(container, t()) :: container
def add_message(container, message)

def add_message(options = %Options{}, message) do
Expand All @@ -23,6 +25,7 @@ defmodule EarmarkParser.Message do
%{context | options: add_message(context.options, message)}
end

@spec get_messages(container) :: ts()
def get_messages(container)

def get_messages(%Context{options: %{messages: messages}}) do
Expand All @@ -32,6 +35,7 @@ defmodule EarmarkParser.Message do
@doc """
For final output
"""
@spec sort_messages(container) :: [t()]
def sort_messages(container) do
container
|> get_messages()
Expand Down
40 changes: 22 additions & 18 deletions lib/earmark_parser/options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ defmodule EarmarkParser.Options do
timeout: nil

@type t :: %__MODULE__{
renderer: module(),
all: boolean(),
gfm: boolean(),
gfm_tables: boolean(),
Expand All @@ -42,18 +43,19 @@ defmodule EarmarkParser.Options do
parse_inline: boolean(),

# allow for annotations
annotations: nil | binary(),
annotations: nil | String.t() | Regex.t(),
# additional prefies for class of code blocks
code_class_prefix: nil | binary(),
code_class_prefix: nil | String.t(),

# Filename and initial line number of the markdown block passed in
# for meaningful error messages
file: binary(),
line: number(),
file: String.t(),
line: non_neg_integer(),
# [{:error|:warning, lnb, text},...]
messages: MapSet.t(),
messages: MapSet.t(EarmarkParser.Message.t()),
pure_links: boolean(),
sub_sup: boolean(),
math: boolean(),

# deprecated
pedantic: boolean(),
Expand Down Expand Up @@ -105,22 +107,12 @@ defmodule EarmarkParser.Options do
...(1)> options.annotations
~r{\A(.*)(%%.*)}
"""
@spec normalize(t() | keyword()) :: t()
def normalize(options)

def normalize(%__MODULE__{} = options) do
case options.annotations do
%Regex{} ->
options

nil ->
options

_ ->
%{
options
| annotations: Regex.compile!("\\A(.*)(#{Regex.escape(options.annotations)}.*)")
}
end
options
|> _normalize_annotations()
|> _set_all_if_applicable()
|> _deprecate_old_messages()
end
Expand All @@ -129,6 +121,18 @@ defmodule EarmarkParser.Options do
struct(__MODULE__, options) |> normalize()
end

defp _normalize_annotations(%__MODULE__{annotations: %Regex{}} = options) do
options
end

defp _normalize_annotations(%__MODULE__{annotations: nil} = options) do
options
end

defp _normalize_annotations(%__MODULE__{annotations: annotations} = options) do
%{options | annotations: Regex.compile!("\\A(.*)(#{Regex.escape(annotations)}.*)")}
end

defp _deprecate_old_messages(options)

defp _deprecate_old_messages(%__MODULE__{messages: %MapSet{}} = options) do
Expand Down
5 changes: 3 additions & 2 deletions lib/earmark_parser/parser.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule EarmarkParser.Parser do
@moduledoc false
alias EarmarkParser.{Block, Line, LineScanner, Options}
alias EarmarkParser.{Block, Line, LineScanner, Options, Context}

import EarmarkParser.Helpers.{AttrParser, LineHelpers, ReparseHelpers}

Expand All @@ -19,6 +19,7 @@ defmodule EarmarkParser.Parser do
The options are a `%EarmarkParser.Options{}` structure. See `as_html!`
for more details.
"""
@spec parse_markdown([String.t()] | String.t(), Options.t()) :: {[Block.t()], Context.t()}
def parse_markdown(lines, options)

def parse_markdown(lines, options = %Options{}) when is_list(lines) do
Expand Down Expand Up @@ -513,7 +514,7 @@ defmodule EarmarkParser.Parser do
# Consolidate multiline inline code blocks into an element #
############################################################
@not_pending {nil, 0}
# ([#{},...]) -> {[#{}],[#{}],{'nil' | binary(),number()}}
# ([#{},...]) -> {[#{}],[#{}],{'nil' | String.t(),number()}}
# @spec consolidate_para( ts ) :: { ts, ts, {nil | String.t, number} }
defp consolidate_para(lines) do
_consolidate_para(lines, [], @not_pending, nil)
Expand Down
32 changes: 22 additions & 10 deletions lib/earmark_parser/parser/list_info.ex
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
defmodule EarmarkParser.Parser.ListInfo do
alias EarmarkParser.{Options, Line, Line.ListItem}

import EarmarkParser.Helpers.LookaheadHelpers, only: [opens_inline_code: 1, still_inline_code: 2]

@moduledoc false

@not_pending {nil, 0}

defstruct(
indent: 0,
lines: [],
loose?: false,
pending: @not_pending,
options: %EarmarkParser.Options{},
width: 0
)

def new(%EarmarkParser.Line.ListItem{initial_indent: ii, list_indent: width} = item, options) do
defstruct indent: 0,
lines: [],
loose?: false,
pending: @not_pending,
options: %Options{},
width: 0

@type t :: %__MODULE__{
indent: non_neg_integer(),
lines: [String.t()],
loose?: boolean(),
pending: {nil | String.t(), non_neg_integer()},
options: Options.t(),
width: non_neg_integer()
}

@spec new(ListItem.t(), Options.t()) :: t()
def new(%ListItem{initial_indent: ii, list_indent: width} = item, options) do
pending = opens_inline_code(item)
%__MODULE__{indent: ii, lines: [item.content], options: options, pending: pending, width: width}
end

@spec update_list_info(t(), String.t(), Line.t(), boolean()) :: t()
def update_list_info(list_info, line, pending_line, loose? \\ false) do
prepend_line(list_info, line) |> _update_rest(pending_line, loose?)
end

@spec prepend_line(t(), String.t()) :: t()
def prepend_line(%__MODULE__{lines: lines} = list_info, line) do
%{list_info | lines: [line | lines]}
end
Expand Down
1 change: 1 addition & 0 deletions lib/earmark_parser/parser/list_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule EarmarkParser.Parser.ListParser do

@not_pending {nil, 0}

@spec parse_list([Line.t()], [Block.t()], Options.t()) :: {[Block.t()], [Line.t()], Options.t()}
def parse_list(lines, result, options \\ %Options{}) do
{items, rest, options1} = _parse_list_items_init(lines, [], options)
list = _make_list(items, _empty_list(items))
Expand Down
Loading