Skip to content

Commit

Permalink
Normalize compile error accross Elixir versions
Browse files Browse the repository at this point in the history
  • Loading branch information
msaraiva committed Oct 28, 2024
1 parent f83f731 commit cbda7bb
Show file tree
Hide file tree
Showing 20 changed files with 157 additions and 148 deletions.
8 changes: 4 additions & 4 deletions lib/surface/catalogue.ex
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ defmodule Surface.Catalogue do
subject

_ ->
message = """
no subject defined for #{inspect(type)}
message = "no subject defined for #{inspect(type)}"

Hint: You can define the subject using the :subject option. Example:
hint = """
you can define the subject using the :subject option. Example:
use #{inspect(type)}, subject: MyApp.MyButton
"""

Surface.IOHelper.compile_error(message, caller.file, caller.line)
Surface.IOHelper.compile_error(message, hint, caller.file, caller.line)
end
end

Expand Down
17 changes: 14 additions & 3 deletions lib/surface/compile_error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ defmodule Surface.CompileError do
lineCode = String.trim_trailing(lineCode)
:elixir_errors.format_snippet(:error, {line, column}, file, description, lineCode, %{})
else
description
prefix = IO.ANSI.format([:red, "error:"])
"#{prefix} #{description}"
end

hint =
Expand All @@ -47,12 +48,22 @@ defmodule Surface.CompileError do
end

location = Exception.format_file_line_column(Path.relative_to_cwd(file), line, column)
location <> " " <> message <> hint
location <> "\n" <> message <> hint
end
else
defp format_message(file, line, column, description, hint) do
location = Exception.format_file_line_column(Path.relative_to_cwd(file), line, column)
location <> " " <> description <> (hint || "")

hint =
if hint do
prefix = IO.ANSI.format([:blue, "hint:"])
"\n\n#{prefix} " <> hint
else
""
end

prefix = IO.ANSI.format([:red, "error:"])
location <> "\n#{prefix} " <> description <> hint
end
end
end
1 change: 0 additions & 1 deletion lib/surface/compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ defmodule Surface.Compiler do
%AST.Error{message: message, meta: meta}

{:error, {message, details, line, column}, meta} ->
details = if details, do: "\n\n" <> details, else: ""
# TODO: turn it back as a warning when using @after_verify in Elixir >= 0.14.
# Make sure to check if the genarated `require <component>.__info__()` doesn't get called,
# raising Elixir's CompileError.
Expand Down
2 changes: 1 addition & 1 deletion lib/surface/compiler/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ defmodule Surface.Compiler.Helpers do

defp hint_for_unloaded_module(node_alias) do
"""
Hint: make sure module `#{node_alias}` can be successfully compiled.
make sure module `#{node_alias}` can be successfully compiled.
If the module is namespaced, you can use its full name. For instance:
Expand Down
29 changes: 14 additions & 15 deletions test/surface/api_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,17 @@ defmodule Surface.APITest do
# invalid value
code = "prop field, :string, css_variant: 123"

message = """
code:4: invalid value for :css_variant. Expected either a boolean or a keyword list of options, got: 123.
message = ~r"""
code:4:\n.+?error:.+? invalid value for :css_variant\. Expected either a boolean or a keyword list of options, got: 123\.
Valid options for type :string are:
* :not_nil - the name of the variant when the value is not `nil`. Default is the assign name.
* :nil - the name of the variant when the value is `nil`. Default is `no-[assign-name]`.
\* :not_nil - the name of the variant when the value is not `nil`\. Default is the assign name\.
\* :nil - the name of the variant when the value is `nil`\. Default is `no-\[assign-name\]`\.
or, if you use the `values` or `values!` options:
* :prefix - the prefix of the variant name for each value listed in `values` or `values!`. Default is `[assign-name]-`.
\* :prefix - the prefix of the variant name for each value listed in `values` or `values!`. Default is `\[assign-name\]-`\.
"""

assert_raise(Surface.CompileError, message, fn -> eval(code) end)
Expand Down Expand Up @@ -445,11 +445,11 @@ defmodule Surface.APITest do
end
"""

message = """
code.exs:7: cannot use property `unknown` as generator for slot. \
message = ~r"""
code.exs:7:\n.+?error:.+? cannot use property `unknown` as generator for slot\. \
Expected an existing property of type `:generator`, got: an undefined property `unknown`.
Hint: Available generators are [:items]\
Hint: Available generators are \[:items\]\
"""

assert_raise(Surface.CompileError, message, fn ->
Expand All @@ -473,11 +473,11 @@ defmodule Surface.APITest do
end
"""

message = """
code.exs:6: cannot use property `label` as generator for slot. \
message = ~r"""
code.exs:6:\n.+?error:.+? cannot use property `label` as generator for slot\. \
Expected a property of type :generator, got: a property of type :string
Hint: Available generators are []\
Hint: Available generators are \[\]\
"""

assert_raise(Surface.CompileError, message, fn ->
Expand Down Expand Up @@ -804,9 +804,7 @@ defmodule Surface.APISyncTest do
assert {%Surface.CompileError{
description: "cannot render <NonExisting> (module NonExisting could not be loaded)",
hint: """
Hint: make sure module `NonExisting` can be successfully compiled.
make sure module `NonExisting` can be successfully compiled.
If the module is namespaced, you can use its full name. For instance:
Expand Down Expand Up @@ -843,7 +841,8 @@ defmodule Surface.APISyncTest do
end
"""

error_message = ~r"code.exs:7(:8)?: cannot render <NonExisting> \(module NonExisting could not be loaded\)"
error_message =
~r"code.exs:7(:8)?:\n.+?error:.+? cannot render <NonExisting> \(module NonExisting could not be loaded\)"

assert_raise(Surface.CompileError, error_message, fn ->
{{:module, _, _, _}, _} =
Expand Down
8 changes: 4 additions & 4 deletions test/surface/catalogue/live_example_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ defmodule Surface.Catalogue.LiveExampleTest do
end
"""

message = """
code.exs:2: no subject defined for Surface.Catalogue.LiveExample
message = ~r"""
code\.exs:2:\n.+?error:.+? no subject defined for Surface\.Catalogue\.LiveExample
Hint: You can define the subject using the :subject option. Example:
.+?hint:.+? you can define the subject using the :subject option\. Example:
use Surface.Catalogue.LiveExample, subject: MyApp.MyButton
use Surface\.Catalogue\.LiveExample, subject: MyApp.MyButton
"""

assert_raise Surface.CompileError, message, fn ->
Expand Down
6 changes: 3 additions & 3 deletions test/surface/catalogue/playground_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ defmodule Surface.Catalogue.PlaygroundTest do
end
"""

message = """
code.exs:2: no subject defined for Surface.Catalogue.Playground
message = ~r"""
code.exs:2:\n.+?error:.+? no subject defined for Surface.Catalogue.Playground
Hint: You can define the subject using the :subject option. Example:
.+?hint:.+?you can define the subject using the :subject option. Example:
use Surface.Catalogue.Playground, subject: MyApp.MyButton
"""
Expand Down
12 changes: 6 additions & 6 deletions test/surface/compiler/parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -742,8 +742,8 @@ defmodule Surface.Compiler.ParserTest do
/>
"""

message = """
nofile:2: invalid value for tagged expression `{=1}`. The expression must be either an assign or a variable.
message = ~r"""
nofile:2:\n.+?error:.+? invalid value for tagged expression `{=1}`. The expression must be either an assign or a variable.
Examples: `<div {=@class}>` or `<div {=class}>`
"""
Expand All @@ -758,8 +758,8 @@ defmodule Surface.Compiler.ParserTest do
/>
"""

message = """
nofile:2: cannot assign `{=@class}` to attribute `class`. \
message = ~r"""
nofile:2:\n.+?error:.+? cannot assign `{=@class}` to attribute `class`. \
The tagged expression `{= }` can only be used on a root attribute/property.
Example: <div {=@class}>
Expand Down Expand Up @@ -995,7 +995,7 @@ defmodule Surface.Compiler.ParserTest do
{/if}
"""

message = "nofile:2: missing expression for block {#if ...}"
message = ~r"nofile:2:\n.+?error:.+? missing expression for block {#if ...}"

assert_raise Surface.CompileError, message, fn -> parse!(code) end

Expand All @@ -1006,7 +1006,7 @@ defmodule Surface.Compiler.ParserTest do
{/case}
"""

message = "nofile:2: missing expression for block {#case ...}"
message = ~r"nofile:2:\n.+?error:.+? missing expression for block {#case ...}"

assert_raise Surface.CompileError, message, fn -> parse!(code) end
end
Expand Down
2 changes: 1 addition & 1 deletion test/surface/compiler_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,7 @@ defmodule Surface.CompilerSyncTest do

assert_raise(
Surface.CompileError,
~r/nofile:2(:4)?: cannot render <But> \(module But could not be loaded\)/,
~r/nofile:2(:4)?:\n.+?error:.+? cannot render <But> \(module But could not be loaded\)/,
fn ->
Surface.Compiler.compile(code, 1, __ENV__)
end
Expand Down
2 changes: 1 addition & 1 deletion test/surface/component_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ defmodule Surface.ComponentTest do
end
"""

message = "code.exs:2: invalid value for option :slot. Expected a string, got: {1, 2}"
message = ~r"code.exs:2:\n.+?error:.+? invalid value for option :slot. Expected a string, got: {1, 2}"

assert_raise(Surface.CompileError, message, fn ->
{{:module, _, _, _}, _} = Code.eval_string(code, [], %{__ENV__ | file: "code.exs", line: 1})
Expand Down
56 changes: 28 additions & 28 deletions test/surface/components/context_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -931,11 +931,11 @@ defmodule Surface.Components.ContextTest do
"""
end

message = """
code:2: invalid value for property "get". expected a scope \
module (optional) along with a keyword list of bindings, \
message = ~r"""
code:2:\n.+?error:.+? invalid value for property "get". expected a scope \
module \(optional\) along with a keyword list of bindings, \
e.g. {Form, form: form} or {field: my_field}, \
got: {ContextTest.Outer, field: [field]}.\
got: {ContextTest.Outer, field: \[field\]}.\
"""

assert_raise(Surface.CompileError, message, fn ->
Expand All @@ -954,7 +954,7 @@ defmodule Surface.Components.ContextTest do
"""
end

assert_raise(Surface.CompileError, ~r/code:2: invalid value for property "get"/, fn ->
assert_raise(Surface.CompileError, ~r/code:2:\n.+?error:.+? invalid value for property "get"/, fn ->
compile_surface(code)
end)
end
Expand All @@ -970,7 +970,7 @@ defmodule Surface.Components.ContextTest do
"""
end

assert_raise(Surface.CompileError, ~r/code:2: invalid value for property "get"/, fn ->
assert_raise(Surface.CompileError, ~r/code:2:\n.+?error:.+? invalid value for property "get"/, fn ->
compile_surface(code)
end)
end
Expand All @@ -988,9 +988,9 @@ defmodule Surface.Components.ContextTest do
"""
end

message = """
code:2: invalid value for property "put". expected a scope \
module (optional) along with a keyword list of values, \
message = ~r"""
code:2:\n.+?error:.+? invalid value for property "put". expected a scope \
module \(optional\) along with a keyword list of values, \
e.g. {MyModule, field: @value, other: "other"} or {field: @value}, \
got: {ContextTest.Outer, 123}.\
"""
Expand All @@ -1011,7 +1011,7 @@ defmodule Surface.Components.ContextTest do
"""
end

assert_raise(Surface.CompileError, ~r/code:2: invalid value for property "put"/, fn ->
assert_raise(Surface.CompileError, ~r/code:2:\n.+?error:.+? invalid value for property "put"/, fn ->
compile_surface(code)
end)
end
Expand All @@ -1027,7 +1027,7 @@ defmodule Surface.Components.ContextTest do
"""
end

assert_raise(Surface.CompileError, ~r/code:2: invalid value for property "put"/, fn ->
assert_raise(Surface.CompileError, ~r/code:2:\n.+?error:.+? invalid value for property "put"/, fn ->
compile_surface(code)
end)
end
Expand Down Expand Up @@ -1177,19 +1177,19 @@ defmodule Surface.Components.ContextTest do
end
"""

message = """
code.exs:7: components propagating context values through slots must be configured \
message = ~r"""
code.exs:7:\n.+?error:.+? components propagating context values through slots must be configured \
as `propagate_context_to_slots: true`.
In case you don't want to propagate any value, you need to explicitly \
set `propagate_context_to_slots` to `false`.
# Example
config :surface, :components, [
config :surface, :components, \[
{Surface.Components.ContextTest.WarnOnSlotPropContextPut, propagate_context_to_slots: true},
...
]
\]
This warning is emitted whenever a <#slot ...> uses the `context_put` prop or \
it's placed inside a parent component that propagates context values through its slots.
Expand Down Expand Up @@ -1217,26 +1217,26 @@ defmodule Surface.Components.ContextTest do
end
"""

message = """
code.exs:9: components propagating context values through slots must be configured \
message = ~r"""
code.exs:9:\n.+?error:.+? components propagating context values through slots must be configured \
as `propagate_context_to_slots: true`.
In case you don't want to propagate any value, you need to explicitly \
set `propagate_context_to_slots` to `false`.
# Example
config :surface, :components, [
config :surface, :components, \[
{Surface.Components.ContextTest.WarnOnContextPut, propagate_context_to_slots: true},
...
]
\]
This warning is emitted whenever a <#slot ...> uses the `context_put` prop or \
it's placed inside a parent component that propagates context values through its slots.
Current parent components propagating context values:
* `Surface.Components.Context` at line 8
\* `Surface.Components.Context` at line 8
"""

assert_raise(Surface.CompileError, message, fn ->
Expand All @@ -1263,27 +1263,27 @@ defmodule Surface.Components.ContextTest do
end
"""

message = """
code.exs:10: components propagating context values through slots must be configured \
as `propagate_context_to_slots: true`.
message = ~r"""
code.exs:10:\n.+?error:.+? components propagating context values through slots must be configured \
as `propagate_context_to_slots: true`\.
In case you don't want to propagate any value, you need to explicitly \
set `propagate_context_to_slots` to `false`.
set `propagate_context_to_slots` to `false`\.
# Example
config :surface, :components, [
config :surface, :components, \[
{Surface.Components.ContextTest.WarnOnSlotInsideComponentPropagating, propagate_context_to_slots: true},
...
]
\]
This warning is emitted whenever a <#slot ...> uses the `context_put` prop or \
it's placed inside a parent component that propagates context values through its slots.
Current parent components propagating context values:
* `Surface.Components.ContextTest.Outer` at line 8
* `Surface.Components.ContextTest.OuterUsingPropContextPut` at line 9
\* `Surface.Components.ContextTest.Outer` at line 8
\* `Surface.Components.ContextTest.OuterUsingPropContextPut` at line 9
"""

assert_raise(Surface.CompileError, message, fn ->
Expand Down
Loading

0 comments on commit cbda7bb

Please sign in to comment.