Skip to content

Commit 8977f9d

Browse files
authored
Improve UndefinedVariableError and UndefinedFilterError error messages (#180)
1 parent c9fba28 commit 8977f9d

File tree

6 files changed

+78
-8
lines changed

6 files changed

+78
-8
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
# [Unreleased]
2+
3+
## Enhancements
4+
5+
* Align the `Solid.UndefinedFilterError` message with `Solid.UndefinedVariableError` - include line number
6+
7+
## Bug fixes
8+
9+
* Return `{:error, errors}` tuple when both strict_filters and strict_variables are enforced while rendering a template
10+
* Use correct variable name in the `Solid.UndefinedVariableError` message
11+
112
# 1.0.1 (2025-07-04)
213

314
## Bug fixes

lib/solid/argument.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,11 @@ defmodule Solid.Argument do
187187
{:error, {:not_found, key}, context} ->
188188
context =
189189
if strict_variables do
190-
Context.put_errors(context, %UndefinedVariableError{variable: key, loc: arg.loc})
190+
Context.put_errors(context, %UndefinedVariableError{
191+
variable: key,
192+
original_name: arg.original_name,
193+
loc: arg.loc
194+
})
191195
else
192196
context
193197
end

lib/solid/undefined_filter_error.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@ defmodule Solid.UndefinedFilterError do
33
defexception [:filter, :loc]
44

55
@impl true
6-
def message(exception), do: "Undefined filter #{exception.filter}"
6+
def message(exception) do
7+
line = exception.loc.line
8+
reason = "Undefined filter #{exception.filter}"
9+
"#{line}: #{reason}"
10+
end
711
end
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
defmodule Solid.UndefinedVariableError do
22
@type t :: %__MODULE__{}
3-
defexception [:variable, :loc]
3+
defexception [:variable, :original_name, :loc]
44

55
@impl true
66
def message(exception) do
77
line = exception.loc.line
8-
reason = "Undefined variable #{exception.variable}"
8+
reason = "Undefined variable #{exception.original_name}"
99
"#{line}: #{reason}"
1010
end
1111
end

test/solid/argument_test.exs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,10 @@ defmodule Solid.ArgumentTest do
296296
arg = %Variable{original_name: "key[1]", loc: @loc, identifier: "key", accesses: accesses}
297297
context = %Solid.Context{vars: %{"key" => "a string"}}
298298
assert {:ok, nil, context} = Argument.get(arg, context, [], strict_variables: true)
299-
assert context.errors == [%UndefinedVariableError{variable: ["key", 1], loc: @loc}]
299+
300+
assert context.errors == [
301+
%UndefinedVariableError{variable: ["key", 1], original_name: "key[1]", loc: @loc}
302+
]
300303
end
301304

302305
test "array access and nested" do
@@ -376,7 +379,9 @@ defmodule Solid.ArgumentTest do
376379
assert {:ok, 456, context} =
377380
Argument.get(arg, context, filters, strict_variables: true)
378381

379-
assert context.errors == [%UndefinedVariableError{variable: ["key"], loc: @loc}]
382+
assert context.errors == [
383+
%UndefinedVariableError{variable: ["key"], original_name: "key", loc: @loc}
384+
]
380385
end
381386

382387
test "missing filter strict_filters" do
@@ -445,7 +450,7 @@ defmodule Solid.ArgumentTest do
445450

446451
assert context.errors == [
447452
%Solid.UndefinedFilterError{filter: "unknown", loc: @loc},
448-
%UndefinedVariableError{variable: ["key"], loc: @loc}
453+
%UndefinedVariableError{variable: ["key"], original_name: "key", loc: @loc}
449454
]
450455
end
451456

@@ -523,7 +528,9 @@ defmodule Solid.ArgumentTest do
523528
strict_variables: true
524529
)
525530

526-
assert context.errors == [%UndefinedVariableError{variable: ["name"], loc: @loc}]
531+
assert context.errors == [
532+
%UndefinedVariableError{variable: ["name"], original_name: "name", loc: @loc}
533+
]
527534
end
528535
end
529536
end

test/solid_test.exs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,12 @@ defmodule SolidTest do
213213
assert error == [
214214
%Solid.UndefinedVariableError{
215215
variable: ["var1"],
216+
original_name: "var1",
216217
loc: %Solid.Parser.Loc{line: 1, column: 5}
217218
},
218219
%Solid.UndefinedVariableError{
219220
variable: ["var2"],
221+
original_name: "var2",
220222
loc: %Solid.Parser.Loc{line: 1, column: 16}
221223
}
222224
]
@@ -254,16 +256,19 @@ defmodule SolidTest do
254256
assert error == [
255257
%Solid.UndefinedVariableError{
256258
variable: ["var1"],
259+
original_name: "var1",
257260
loc: %Solid.Parser.Loc{line: 1, column: 5}
258261
},
259262
%Solid.UndefinedVariableError{
260263
variable: ["var2"],
264+
original_name: "var2",
261265
loc: %Solid.Parser.Loc{line: 1, column: 16}
262266
},
263267
# FIXME this should somehow point out which file?
264268
# Check how liquid does this
265269
%Solid.UndefinedVariableError{
266270
variable: ["var3"],
271+
original_name: "var3",
267272
loc: %Solid.Parser.Loc{line: 1, column: 4}
268273
}
269274
]
@@ -296,6 +301,7 @@ defmodule SolidTest do
296301
assert error == [
297302
%Solid.UndefinedVariableError{
298303
variable: ["var1"],
304+
original_name: "var1",
299305
loc: %Solid.Parser.Loc{line: 1, column: 5}
300306
},
301307
%Solid.UndefinedFilterError{
@@ -304,9 +310,47 @@ defmodule SolidTest do
304310
},
305311
%Solid.UndefinedVariableError{
306312
variable: ["var2"],
313+
original_name: "var2",
307314
loc: %Solid.Parser.Loc{line: 1, column: 38}
308315
}
309316
]
310317
end
318+
319+
test "undefined variable error message with multiple variables" do
320+
template =
321+
"{{ var1 }}\n{{ event.name }}\n{{ user.properties['name'] }}\n"
322+
323+
{:error, [first_error, second_error, third_error], _partial_result} =
324+
template
325+
|> Solid.parse!()
326+
|> Solid.render(%{}, strict_variables: true, file_system: {TestFileSystem, nil})
327+
328+
assert String.contains?(Solid.UndefinedVariableError.message(first_error), "var1")
329+
330+
assert String.contains?(
331+
Solid.UndefinedVariableError.message(second_error),
332+
"event.name"
333+
)
334+
335+
assert String.contains?(
336+
Solid.UndefinedVariableError.message(third_error),
337+
"user.properties['name']"
338+
)
339+
end
340+
341+
test "undefined filter error message with line number" do
342+
template = "{{ var1 | not_a_filter }}"
343+
344+
assert_raise Solid.RenderError,
345+
"1 error(s) found while rendering\n1: Undefined filter not_a_filter",
346+
fn ->
347+
template
348+
|> Solid.parse!()
349+
|> Solid.render!(%{"var1" => "value"},
350+
strict_filters: true,
351+
file_system: {TestFileSystem, nil}
352+
)
353+
end
354+
end
311355
end
312356
end

0 commit comments

Comments
 (0)