defmodule Spark.Dsl.Section do
@moduledoc """
Declares a DSL section.
A dsl section allows you to organize related configurations. All extensions
configure sections, they cannot add DSL builders to the top level. This
keeps things organized, and concerns separated.
A section may have nested sections, which will be configured the same as other sections.
Getting the options/entities of a section is done by providing a path, so you would
use the nested path to retrieve that configuration. See `Spark.Dsl.Extension.get_entities/2`
and `Spark.Dsl.Extension.get_opt/4`.
A section may have entities, which are constructors that produce instances of structs.
For more on entities, see `Spark.Dsl.Entity`.
A section may also have a `schema`, which is a `NimbleOptions` schema. Spark will produce
builders for those options, so that they may be configured. They are retrieved with
`Spark.Dsl.Extension.get_opt/4`.
To create a section that is available at the top level (i.e not nested inside of its own name), use
`top_level?: true`. Remember, however, that this has no effect on sections nested inside of other sections.
For a full example, see `Spark.Dsl.Extension`.
"""
defstruct [
:name,
imports: [],
schema: [],
describe: "",
snippet: "",
links: nil,
examples: [],
modules: [],
top_level?: false,
no_depend_modules: [],
auto_set_fields: [],
deprecations: [],
entities: [],
sections: [],
docs: "",
patchable?: false
]
alias Spark.{
Dsl.Entity,
Dsl.Section,
OptionsHelpers
}
@type name :: atom()
@type imports :: [module]
@typedoc """
User provided documentation.
Documentation provided in a `Section`'s `describe` field will be included by `Spark` in any generated documentation that includes the `Section`.
"""
@type describe :: String.t()
@type snippet :: String.t()
@typedoc """
Determines whether a section can be declared directly in a module.
When `top_level?: true`, that Section's DSL can be declared outside of a `do` block in a module.
## Example
A `Section` declared with `top_level?: true`:
```elixir
@my_section %Spark.Dsl.Section{
top_level?: true,
name: :my_section,
schema: [my_field: [type: :atom, required: true]]
}
```
Can be declared like this:
```elixir
defmodule MyDslModule do
my_field :value
end
```
With `top_level?: false`, the DSL section would need to be declared explicitly/:
```elixir
defmodule MyDslModule do
my_section do
my_field :value
end
end
```
"""
@type top_level?() :: boolean()
@type links :: nil | Keyword.t([String.t()])
@type examples() :: [String.t()]
@type modules :: [atom]
@type no_depend_modules() :: [atom]
@type auto_set_fields() :: Keyword.t(any)
@type entities :: [Entity.t()]
@type sections :: [Section.t()]
@typedoc """
Internal field. Not set by user.
"""
@type docs :: String.t()
@type patchable? :: boolean()
@type t :: %Section{
name: name(),
imports: imports(),
schema: OptionsHelpers.schema(),
describe: describe(),
snippet: snippet(),
top_level?: top_level?(),
links: links(),
examples: examples(),
modules: modules(),
no_depend_modules: no_depend_modules(),
auto_set_fields: auto_set_fields(),
entities: entities(),
sections: sections(),
docs: docs(),
patchable?: patchable?()
}
end