Skip to content

Commit 9a44167

Browse files
committed
Raise helpful errors for DSL section inline and inline+block syntax
Currently DSL sections throw confusing error messages for the following DSL declarations: 1. Using inline keyword args instead of block syntax gives ``` ** (Spark.Options.ValidationError) required :first_name option not found, received options: [] ``` 2. Using inline and block syntax throws the following compile error ``` error: undefined function section_name/2 (there is no such import) ``` We now catch these errors and show helpful errors so that the user understands what went wrong and how to fix it. The new errors are as follows: 1. Inline syntax ``` Cannot use inline syntax for DSL section `personal_details`. Use block syntax: `personal_details do ... end`. ``` 2. Mixed inline and block syntax ``` Cannot use both inline syntax and block syntax for DSL section `personal_details`. Use block syntax `personal_details do ... end` ```
1 parent 7cbbb88 commit 9a44167

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

lib/spark/dsl/extension.ex

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ defmodule Spark.Dsl.Extension do
471471
only_sections =
472472
sections
473473
|> Enum.reject(& &1.top_level?)
474-
|> Enum.map(&{&1.name, 1})
474+
|> Enum.flat_map(&[{&1.name, 1}, {&1.name, 2}])
475475

476476
quote generated: true, location: :keep do
477477
require Spark.Dsl.Extension
@@ -878,11 +878,37 @@ defmodule Spark.Dsl.Extension do
878878
end
879879

880880
unless section.top_level? && path == [] do
881-
defmacro unquote(section.name)(body) do
881+
# Handle mixed syntax - personal_details(opts, do: block)
882+
defmacro unquote(section.name)(opts, [do: _] = _block) do
883+
section_name = unquote(section.name)
884+
885+
raise Spark.Error.DslError,
886+
module: __CALLER__.module,
887+
message:
888+
"Cannot use both inline syntax and block syntax for DSL section `#{section_name}`. " <>
889+
"Use block syntax `#{section_name} do ... end`",
890+
path: unquote(path ++ [section.name])
891+
end
892+
893+
# Handle inline syntax and normal block syntax
894+
defmacro unquote(section.name)(body_or_opts) do
895+
section_name = unquote(section.name)
896+
897+
# Check if this is inline syntax (keyword list without :do)
898+
if is_list(body_or_opts) and not Keyword.has_key?(body_or_opts, :do) do
899+
raise Spark.Error.DslError,
900+
module: __CALLER__.module,
901+
message:
902+
"Cannot use inline syntax for DSL section `#{section_name}`. " <>
903+
"Use block syntax: `#{section_name} do ... end`.",
904+
path: unquote(path ++ [section.name])
905+
end
906+
907+
body = body_or_opts
908+
882909
opts_module = unquote(opts_module)
883910
section_path = unquote(path ++ [section.name])
884911
extension = unquote(extension)
885-
886912
entity_modules = unquote(entity_modules)
887913

888914
patch_modules =

test/dsl_test.exs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,36 @@ defmodule Spark.DslTest do
396396
end
397397
end
398398

399+
describe "DSL section syntax validation" do
400+
test "mixed inline/block syntax should provide helpful error" do
401+
assert_raise Spark.Error.DslError,
402+
~r/Cannot use both inline syntax and block syntax.*personal_details/,
403+
fn ->
404+
defmodule MixedSyntax do
405+
@moduledoc false
406+
use Spark.Test.Contact
407+
408+
personal_details first_name: "Luke" do
409+
last_name("Skywalker")
410+
end
411+
end
412+
end
413+
end
414+
415+
test "inline syntax for DSL section should provide helpful error" do
416+
assert_raise Spark.Error.DslError,
417+
~r/Cannot use inline syntax for DSL section.*personal_details/,
418+
fn ->
419+
defmodule InlineSyntax do
420+
@moduledoc false
421+
use Spark.Test.Contact
422+
423+
personal_details(first_name: "Luke", last_name: "Skywalker")
424+
end
425+
end
426+
end
427+
end
428+
399429
describe "optional entity arguments" do
400430
test "optional arguments can be supplied either as arguments or as dsl options" do
401431
defmodule OptionEinstein do

test/support/contact/contact.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule Spark.Test.Contact do
1515
doc: "A module"
1616
],
1717
contacter: [
18-
doc: "A function that wil contact this person with a message",
18+
doc: "A function that will contact this person with a message",
1919
type:
2020
{:spark_function_behaviour, Spark.Test.Contact.Contacter,
2121
Spark.Test.ContacterBuiltins, {Spark.Test.Contact.Contacter.Function, 1}}

0 commit comments

Comments
 (0)