diff --git a/lib/safe_code/validator.ex b/lib/safe_code/validator.ex index 80aef8a..080aca1 100644 --- a/lib/safe_code/validator.ex +++ b/lib/safe_code/validator.ex @@ -25,6 +25,18 @@ defmodule SafeCode.Validator do |> validate_quoted(opts) end + @spec validate_heex(binary, keyword) :: {:ok, ast :: Macro.t()} | {:error, Exception.t()} + def validate_heex(heex, opts \\ []) when is_binary(heex) do + quoted = + heex + |> HeexParser.parse_template() + |> validate_quoted(include_phoenix(opts)) + + {:ok, quoted} + rescue + error -> {:error, error} + end + def validate_heex!(heex, opts \\ []) when is_binary(heex) do heex |> HeexParser.parse_template() diff --git a/test/safe_code/validator_test.exs b/test/safe_code/validator_test.exs index dea53da..56072cc 100644 --- a/test/safe_code/validator_test.exs +++ b/test/safe_code/validator_test.exs @@ -33,6 +33,45 @@ defmodule SafeCode.ValidatorTest do end describe "validate_heex/1" do + test "basic" do + heex = """ + hello <%= 1 + 1 %> how <%= 2+2 %> are you + """ + + assert {:ok, _quoted} = Validator.validate_heex(heex) + end + + test "for loop" do + heex = """ + <%= for foo <- bar do %> + <%= foo %> + <% end %> + """ + + assert {:ok, _quoted} = Validator.validate_heex(heex) + end + + test "return the error tuple when invalid template" do + heex = """ +
+ hello <%= 1 + 1 %> how <%= 2+2 %> are you + """ + + assert {:error, %Phoenix.LiveView.HTMLTokenizer.ParseError{} = error} = Validator.validate_heex(heex) + assert error.description == "end of template reached without closing tag for
" + end + + test "return an error tuple on problem function" do + str = """ + <%= System.cmd("touch", ["foo"]) %> + """ + + assert {:error, %InvalidNode{} = error} = Validator.validate_heex(str) + assert error.message == "System . :cmd\n\nast:\n{:., [line: 1], [{:__aliases__, [line: 1], [:System]}, :cmd]}" + end + end + + describe "validate_heex!/1" do test "basic" do heex = """ hello <%= 1 + 1 %> how <%= 2+2 %> are you