From 1a99d65e214c6c359aab32e988004ee2b74d3bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarom=C3=ADr=20=C4=8Cervenka?= Date: Thu, 4 Sep 2025 16:32:13 +0200 Subject: [PATCH 1/4] fix: variable name in undefined variable error --- lib/solid/undefined_variable_error.ex | 11 ++++++++++- test/solid_test.exs | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/solid/undefined_variable_error.ex b/lib/solid/undefined_variable_error.ex index b493138..4b26585 100644 --- a/lib/solid/undefined_variable_error.ex +++ b/lib/solid/undefined_variable_error.ex @@ -4,8 +4,17 @@ defmodule Solid.UndefinedVariableError do @impl true def message(exception) do + variable = exception.variable + + variable_name = + if is_list(variable) do + Enum.join(variable, ".") + else + variable + end + line = exception.loc.line - reason = "Undefined variable #{exception.variable}" + reason = "Undefined variable #{variable_name}" "#{line}: #{reason}" end end diff --git a/test/solid_test.exs b/test/solid_test.exs index b2ad5a7..0977409 100644 --- a/test/solid_test.exs +++ b/test/solid_test.exs @@ -308,5 +308,26 @@ defmodule SolidTest do } ] end + + test "undefined variable error message with multiple variables" do + template = "{{ var1 }}\n{{ event.name }}\n{{ user.properties.name }}" + + {:error, [first_error, second_error, third_error], _partial_result} = + template + |> Solid.parse!() + |> Solid.render(%{}, strict_variables: true, file_system: {TestFileSystem, nil}) + + assert String.contains?(Solid.UndefinedVariableError.message(first_error), "var1") + + assert String.contains?( + Solid.UndefinedVariableError.message(second_error), + "event.name" + ) + + assert String.contains?( + Solid.UndefinedVariableError.message(third_error), + "user.properties.name" + ) + end end end From d9a17227fab0b40ef0df98fae6133bae672e5f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarom=C3=ADr=20=C4=8Cervenka?= Date: Thu, 4 Sep 2025 16:33:41 +0200 Subject: [PATCH 2/4] chore: include line number in the undefined filter error --- lib/solid/undefined_filter_error.ex | 6 +++++- test/solid_test.exs | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/solid/undefined_filter_error.ex b/lib/solid/undefined_filter_error.ex index b7dd367..fca4a52 100644 --- a/lib/solid/undefined_filter_error.ex +++ b/lib/solid/undefined_filter_error.ex @@ -3,5 +3,9 @@ defmodule Solid.UndefinedFilterError do defexception [:filter, :loc] @impl true - def message(exception), do: "Undefined filter #{exception.filter}" + def message(exception) do + line = exception.loc.line + reason = "Undefined filter #{exception.filter}" + "#{line}: #{reason}" + end end diff --git a/test/solid_test.exs b/test/solid_test.exs index 0977409..ef539b2 100644 --- a/test/solid_test.exs +++ b/test/solid_test.exs @@ -329,5 +329,20 @@ defmodule SolidTest do "user.properties.name" ) end + + test "undefined filter error message with line number" do + template = "{{ var1 | not_a_filter }}" + + assert_raise Solid.RenderError, + "1 error(s) found while rendering\n1: Undefined filter not_a_filter", + fn -> + template + |> Solid.parse!() + |> Solid.render!(%{"var1" => "value"}, + strict_filters: true, + file_system: {TestFileSystem, nil} + ) + end + end end end From c51d42fa084b3859abafbfaca65788cea851eeb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarom=C3=ADr=20=C4=8Cervenka?= Date: Wed, 10 Sep 2025 17:16:01 +0200 Subject: [PATCH 3/4] chore: use original variable name in undefined variable error --- lib/solid/argument.ex | 6 +++++- lib/solid/undefined_variable_error.ex | 13 ++----------- test/solid/argument_test.exs | 15 +++++++++++---- test/solid_test.exs | 12 ++++++++++-- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/lib/solid/argument.ex b/lib/solid/argument.ex index ab651a6..d1b819c 100644 --- a/lib/solid/argument.ex +++ b/lib/solid/argument.ex @@ -187,7 +187,11 @@ defmodule Solid.Argument do {:error, {:not_found, key}, context} -> context = if strict_variables do - Context.put_errors(context, %UndefinedVariableError{variable: key, loc: arg.loc}) + Context.put_errors(context, %UndefinedVariableError{ + variable: key, + original_name: arg.original_name, + loc: arg.loc + }) else context end diff --git a/lib/solid/undefined_variable_error.ex b/lib/solid/undefined_variable_error.ex index 4b26585..5768ff4 100644 --- a/lib/solid/undefined_variable_error.ex +++ b/lib/solid/undefined_variable_error.ex @@ -1,20 +1,11 @@ defmodule Solid.UndefinedVariableError do @type t :: %__MODULE__{} - defexception [:variable, :loc] + defexception [:variable, :original_name, :loc] @impl true def message(exception) do - variable = exception.variable - - variable_name = - if is_list(variable) do - Enum.join(variable, ".") - else - variable - end - line = exception.loc.line - reason = "Undefined variable #{variable_name}" + reason = "Undefined variable #{exception.original_name}" "#{line}: #{reason}" end end diff --git a/test/solid/argument_test.exs b/test/solid/argument_test.exs index e148633..b9cfb03 100644 --- a/test/solid/argument_test.exs +++ b/test/solid/argument_test.exs @@ -296,7 +296,10 @@ defmodule Solid.ArgumentTest do arg = %Variable{original_name: "key[1]", loc: @loc, identifier: "key", accesses: accesses} context = %Solid.Context{vars: %{"key" => "a string"}} assert {:ok, nil, context} = Argument.get(arg, context, [], strict_variables: true) - assert context.errors == [%UndefinedVariableError{variable: ["key", 1], loc: @loc}] + + assert context.errors == [ + %UndefinedVariableError{variable: ["key", 1], original_name: "key[1]", loc: @loc} + ] end test "array access and nested" do @@ -376,7 +379,9 @@ defmodule Solid.ArgumentTest do assert {:ok, 456, context} = Argument.get(arg, context, filters, strict_variables: true) - assert context.errors == [%UndefinedVariableError{variable: ["key"], loc: @loc}] + assert context.errors == [ + %UndefinedVariableError{variable: ["key"], original_name: "key", loc: @loc} + ] end test "missing filter strict_filters" do @@ -445,7 +450,7 @@ defmodule Solid.ArgumentTest do assert context.errors == [ %Solid.UndefinedFilterError{filter: "unknown", loc: @loc}, - %UndefinedVariableError{variable: ["key"], loc: @loc} + %UndefinedVariableError{variable: ["key"], original_name: "key", loc: @loc} ] end @@ -523,7 +528,9 @@ defmodule Solid.ArgumentTest do strict_variables: true ) - assert context.errors == [%UndefinedVariableError{variable: ["name"], loc: @loc}] + assert context.errors == [ + %UndefinedVariableError{variable: ["name"], original_name: "name", loc: @loc} + ] end end end diff --git a/test/solid_test.exs b/test/solid_test.exs index ef539b2..90f3d4b 100644 --- a/test/solid_test.exs +++ b/test/solid_test.exs @@ -213,10 +213,12 @@ defmodule SolidTest do assert error == [ %Solid.UndefinedVariableError{ variable: ["var1"], + original_name: "var1", loc: %Solid.Parser.Loc{line: 1, column: 5} }, %Solid.UndefinedVariableError{ variable: ["var2"], + original_name: "var2", loc: %Solid.Parser.Loc{line: 1, column: 16} } ] @@ -254,16 +256,19 @@ defmodule SolidTest do assert error == [ %Solid.UndefinedVariableError{ variable: ["var1"], + original_name: "var1", loc: %Solid.Parser.Loc{line: 1, column: 5} }, %Solid.UndefinedVariableError{ variable: ["var2"], + original_name: "var2", loc: %Solid.Parser.Loc{line: 1, column: 16} }, # FIXME this should somehow point out which file? # Check how liquid does this %Solid.UndefinedVariableError{ variable: ["var3"], + original_name: "var3", loc: %Solid.Parser.Loc{line: 1, column: 4} } ] @@ -296,6 +301,7 @@ defmodule SolidTest do assert error == [ %Solid.UndefinedVariableError{ variable: ["var1"], + original_name: "var1", loc: %Solid.Parser.Loc{line: 1, column: 5} }, %Solid.UndefinedFilterError{ @@ -304,13 +310,15 @@ defmodule SolidTest do }, %Solid.UndefinedVariableError{ variable: ["var2"], + original_name: "var2", loc: %Solid.Parser.Loc{line: 1, column: 38} } ] end test "undefined variable error message with multiple variables" do - template = "{{ var1 }}\n{{ event.name }}\n{{ user.properties.name }}" + template = + "{{ var1 }}\n{{ event.name }}\n{{ user.properties['name'] }}\n" {:error, [first_error, second_error, third_error], _partial_result} = template @@ -326,7 +334,7 @@ defmodule SolidTest do assert String.contains?( Solid.UndefinedVariableError.message(third_error), - "user.properties.name" + "user.properties['name']" ) end From 51c01a7ccfaa7fbe8cf8cccbbc2fae197ea25800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarom=C3=ADr=20=C4=8Cervenka?= Date: Wed, 10 Sep 2025 17:22:02 +0200 Subject: [PATCH 4/4] docs: Update CHANGELOG --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ab559d..b1cf29b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +# [Unreleased] + +## Enhancements + +* Align the `Solid.UndefinedFilterError` message with `Solid.UndefinedVariableError` - include line number + +## Bug fixes + +* Return `{:error, errors}` tuple when both strict_filters and strict_variables are enforced while rendering a template +* Use correct variable name in the `Solid.UndefinedVariableError` message + # 1.0.1 (2025-07-04) ## Bug fixes