I am trying to use this library to parse my custom markdown where I want to find calls to HEEX and then handle them but cannot figure out how to make the custom parser to be invoked.
The markdown:
## TEST
Some text before a card.
<.card image_path="/images/awesome.svg">Some nice card with an image on the left.</.card>
Continuing after the card.
My parser:
defmodule MasWeb.MdParser do
use Md.Parser
alias Md.Parser.Syntax.Void
@default_syntax Map.put(Void.syntax(), :settings, Void.settings())
@syntax @default_syntax
@impl true
def parse(input, state) do
# copied from the Md.Parser source code:
%State{ast: ast, path: []} = state = do_parse(input, state)
{"", %State{state | ast: Enum.reverse(ast)}}
end
end
The docs for Md.Parser
say this:
Custom parsers might be used in syntax declaration when the generic functionality
is not enough.Letâs consider one needs a specific handling of links with titles.
The generic engine does not support it, so one would need to implement a custom parser
and instructMd.Parser
to use it with:# config/prod.exs config :md, syntax: %{ custom: %{ {"![", MyApp.Parsers.Img}, ... } }
Once the original parser would meet the
"!["
binary, itâd callMyApp.Parsers.Img.parse/2
.
The latter must proceed until the tag is closed and return the remainder and the updated state
as a tuple.
Adding the configuration to config/prod.exs
doesnât seem to make sense to me, thus I added it to config.exs
:
config :md, syntax: %{
custom: [
{"<.", MasWeb.MdParser},
]
}
But then I get this error:
Erlang/OTP 25 [erts-13.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]
ERROR! the application :md has a different value set for key :syntax during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to different behaviour than expected:
* Compile time value was not set
* Runtime value was set to: %{custom: [{"<.", MasWeb.MdParser}]}
To fix this error, you might:
* Make the runtime value match the compile time one
* Recompile your project. If the misconfigured application is a dependency, you may need to run "mix deps.compile md --force"
* Alternatively, you can disable this check. If you are using releases, you can set :validate_compile_env to false in your release configuration. If you are using Mix to start your system, you can pass the --no-validate-compile-env flag
10:57:41.583 [error] Task #PID<0.252.0> started from #PID<0.107.0> terminating
** (stop) "aborting boot"
(elixir 1.14.3) Config.Provider.boot/2
Function: &:erlang.apply/2
Args: [#Function<1.104735216/1 in Mix.Tasks.Compile.All.load_apps/3>, [md: "/home/developer/workspace/_build/dev/lib"]]
** (EXIT from #PID<0.107.0>) an exception was raised:
** (ErlangError) Erlang error: "aborting boot"
(elixir 1.14.3) Config.Provider.boot/2
If I try to recompile it as suggested in the output:
mix deps.compile md 1 â”
==> md
Compiling 13 files (.ex)
== Compilation error in file lib/md/parser/default.ex ==
** (FunctionClauseError) no function clause matching in :erl_eval."-inside-an-interpreted-fun-"/1
The following arguments were given to :erl_eval."-inside-an-interpreted-fun-"/1:
# 1
{"<.", MasWeb.MdParser}
(stdlib 4.3) :erl_eval."-inside-an-interpreted-fun-"/1
(stdlib 4.3) erl_eval.erl:898: :erl_eval.eval_fun/8
/home/developer/workspace/deps/md/lib/md/parser/default.ex:1: (file)
/home/developer/workspace/deps/md/lib/md/parser/default.ex:1: (file)
(stdlib 4.3) erl_eval.erl:748: :erl_eval.do_apply/7
(stdlib 4.3) erl_eval.erl:136: :erl_eval.exprs/6
/home/developer/workspace/deps/md/lib/md/parser/default.ex:1: Md.Engine.__before_compile__/1
could not compile dependency :md, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile md", update it with "mix deps.update md" or clean it with "mix deps.clean md"
I have no idea how to recover form this error, thus I commented out the MD entry from my config.exs
and tried instead to configure it through my custom parser:
defmodule MasWeb.MdParser do
use Md.Parser
alias Md.Parser.Syntax.Void
@default_syntax Map.put(Void.syntax(), :settings, Void.settings())
@syntax @default_syntax |> Map.merge(%{
# I think I am doing something wrong here
common: {"<.", MasWeb.MdParser}, # example from Md.Parser
})
@impl true
def parse(input, state) do
IO.inspect(input, label: "MD PARSER INPUT")
IO.inspect(state, label: "MD PARSER STATE")
%State{ast: ast, path: []} = state = do_parse(input, state)
{"", %State{state | ast: Enum.reverse(ast)}}
end
end
I can now compile but I never see the IO.inspect
output, thus my custom parser is not being invoked, which I kind of expected to happen, but i needed to give it a try.
Any guidance how to proceed to get a custom parser configured in my Phoenix app?