AE
Ash Elixir•3w ago
adonig

Correct Way to Display Spark.Error.DslError?

Hi! I’m writing a custom DSL extension and I’m struggling with making Spark.Error.DslError show up in the right place. I followed patterns from core Ash code (like default_accept.ex and verify_identities.ex), and also looked at extensions like Ash Cloak. Here's what I did in my verifier:
@impl true
def verify(dsl_state) do
inferred_attrs = InferredAttributes.Info.inferred_attributes(dsl_state)

for attr <- inferred_attrs do
if !Ash.Resource.Info.attribute(dsl_state, attr.name) do
raise Spark.Error.DslError,
module: Spark.Dsl.Verifier.get_persisted(dsl_state, :module),
message: "All inferred attributes must be attributes. Got: #{inspect(attr.name)}",
path: [:inferred_attributes, attr.name]
end
end

:ok
end
@impl true
def verify(dsl_state) do
inferred_attrs = InferredAttributes.Info.inferred_attributes(dsl_state)

for attr <- inferred_attrs do
if !Ash.Resource.Info.attribute(dsl_state, attr.name) do
raise Spark.Error.DslError,
module: Spark.Dsl.Verifier.get_persisted(dsl_state, :module),
message: "All inferred attributes must be attributes. Got: #{inspect(attr.name)}",
path: [:inferred_attributes, attr.name]
end
end

:ok
end
This seems not to raise, so I tried again this time in the transformer code:
@impl true
def transform(dsl_state) do
module = Spark.Dsl.Transformer.get_persisted(dsl_state, :module)
inferred_attrs = InferredAttributes.Info.inferred_attributes(dsl_state)

Enum.reduce_while(inferred_attrs, {:ok, dsl_state}, fn attr, {:ok, dsl_state} ->
attribute = Ash.Resource.Info.attribute(dsl_state, attr.name)

if !attribute do
raise Spark.Error.DslError,
module: module,
message: "No attribute called #{attr.name} found",
path: [:inferred_attributes, attr.name]
end

if attribute.primary_key? do
raise Spark.Error.DslError,
module: module,
message: "Cannot infer primary key attribute",
path: [:inferred_attributes, attr.name]
end

{:cont, {:ok, dsl_state}}
end)
end
@impl true
def transform(dsl_state) do
module = Spark.Dsl.Transformer.get_persisted(dsl_state, :module)
inferred_attrs = InferredAttributes.Info.inferred_attributes(dsl_state)

Enum.reduce_while(inferred_attrs, {:ok, dsl_state}, fn attr, {:ok, dsl_state} ->
attribute = Ash.Resource.Info.attribute(dsl_state, attr.name)

if !attribute do
raise Spark.Error.DslError,
module: module,
message: "No attribute called #{attr.name} found",
path: [:inferred_attributes, attr.name]
end

if attribute.primary_key? do
raise Spark.Error.DslError,
module: module,
message: "Cannot infer primary key attribute",
path: [:inferred_attributes, attr.name]
end

{:cont, {:ok, dsl_state}}
end)
end
This raises as expected, but the error isn't tied to the DSL location. It does show up, but only on line 1 of the module. Is there a recommended way to raise Spark.Error.DslError so that it points you to the invalid DSL section or field? Any help or examples appreciated! šŸ™
3 Replies
ZachDaniel
ZachDaniel•3w ago
Currently spark DSL errors cannot point at source locations. It's a feature I'd like to support.
adonig
adonigOP•3w ago
How does Ash do the context errors? Is it validation on the Spark.Dsl.Entity? šŸ¤”
No description
adonig
adonigOP•3w ago
Just realized Ash Cloak doesn't modify the default actions. Is that intentional? my bad, forgot def after?(Ash.Resource.Transformers.DefaultAccept), do: true

Did you find this page helpful?