Packages

spark

2.7.1
2.7.2 2.7.1 2.7.0 2.6.1 2.6.0 2.5.0 2.4.1 2.4.0 2.3.14 2.3.13 2.3.12 2.3.11 2.3.10 2.3.9 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.69 2.2.68 2.2.67 2.2.66 2.2.65 2.2.64 2.2.63 2.2.62 2.2.61 2.2.60 2.2.59 2.2.58 2.2.57 2.2.56 2.2.55 2.2.54 2.2.53 2.2.52 2.2.51 2.2.50 2.2.49 2.2.48 2.2.47 2.2.46 2.2.45 2.2.44 2.2.43 2.2.42 2.2.41 2.2.40 2.2.39 2.2.38 2.2.37 2.2.36 2.2.35 2.2.34 2.2.33 2.2.32 2.2.31 2.2.30 2.2.29 2.2.28 2.2.27 2.2.26 2.2.25 2.2.24 2.2.23 2.2.22 2.2.21 2.2.20 2.2.19 2.2.18 2.2.17 2.2.16 2.2.15 2.2.14 2.2.13 2.2.12 2.2.11 2.2.10 2.2.9 2.2.8 2.2.7 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 2.2.1 2.2.0 2.1.24 2.1.23 2.1.22 2.1.21 2.1.20 2.1.19 2.1.18 2.1.17 2.1.16 2.1.15 2.1.14 2.1.13 2.1.12 2.1.11 2.1.10 2.1.9 2.1.8 2.1.7 2.1.6 2.1.5 2.1.4 2.1.3 2.1.2 2.1.1 2.1.0 2.0.1 2.0.0 1.1.55 1.1.54 1.1.53 1.1.52 1.1.51 1.1.50 1.1.49 1.1.48 1.1.47 1.1.46 1.1.45 1.1.44 1.1.43 1.1.42 1.1.41 1.1.40 1.1.39 1.1.38 1.1.37 1.1.36 1.1.35 1.1.34 1.1.32 1.1.31 1.1.30 1.1.29 1.1.28 1.1.27 1.1.26 1.1.25 1.1.24 1.1.22 1.1.21 1.1.20 1.1.19 1.1.18 1.1.17 1.1.16 1.1.15 1.1.14 retired 1.1.13 1.1.12 1.1.11 1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.9 1.0.8 1.0.7 1.0.6 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 1.0.0 0.4.12 0.4.11 0.4.10 0.4.9 0.4.8 0.4.7 0.4.6 0.4.5 0.4.4 0.4.3 0.4.2 0.4.1 0.3.12 0.3.11 0.3.10 0.3.9 0.3.8 0.3.7 0.3.6 0.3.5 0.3.4 0.3.3 0.3.2 0.3.1 0.3.0 0.2.18 0.2.17 0.2.16 0.2.15 0.2.14 0.2.13 0.2.12 0.2.11 0.2.10 0.2.9 0.2.8 0.2.7 0.2.6 0.2.5 0.2.4 0.2.3 0.2.2 0.2.1 0.2.0 0.1.29 0.1.28 0.1.27 0.1.26 0.1.25 0.1.24 0.1.23 0.1.22 0.1.21 0.1.20 0.1.19 0.1.18 0.1.17 0.1.16 0.1.15 0.1.14 0.1.13 0.1.12 0.1.11 0.1.10 0.1.9 0.1.8 0.1.7 0.1.6 0.1.5 0.1.4 0.1.3 0.1.2 0.1.1 0.1.0

Generic tooling for building DSLs

Current section

Files

Jump to
spark lib spark docs.ex
Raw

lib/spark/docs.ex

# SPDX-FileCopyrightText: 2022 spark contributors <https://github.com/ash-project/spark/graphs/contributors>
#
# SPDX-License-Identifier: MIT
defmodule Spark.Docs do
@moduledoc """
Tools for generating docs & search data for extras.
"""
@doc """
Builds a redirects map for a DSL from mod/funs to their respective DSL docs.
This is useful for redirecting links to private DSL modules (like `Ash.Resource.Dsl.Actions.Create`)
to their corresponding documentation pages (like `dsl-ash-resource#actions-create`).
## Example
redirects_for([Ash.Resource.Dsl])
# => %{
# "Ash.Resource.Dsl.Actions.Create" => "dsl-ash-resource#actions-create",
# ...
# }
These redirects can be passed to ex_doc's `:redirects` option to handle links
to private DSL modules.
"""
def redirects_for(dsls, existing_redirects \\ %{}) do
dsls
|> Enum.reduce(existing_redirects, fn dsl, acc ->
module_prefix = dsl.module_prefix()
extension_name = extension_name(dsl)
doc_filename = dsl_doc_filename(extension_name)
acc
|> add_section_redirects(dsl.sections(), module_prefix, doc_filename, [])
|> add_patch_redirects(dsl.dsl_patches(), module_prefix, doc_filename)
end)
end
defp extension_name(dsl) do
dsl
|> inspect()
|> String.trim_trailing(".Dsl")
end
defp dsl_doc_filename(extension_name) do
name =
extension_name
|> String.split(".")
|> Enum.map_join("-", &String.downcase/1)
"dsl-#{name}"
end
defp add_section_redirects(redirects, sections, module_prefix, doc_filename, path) do
Enum.reduce(sections, redirects, fn section, acc ->
section_path = path ++ [section.name]
acc
|> add_entity_redirects(section.entities, module_prefix, doc_filename, section_path, [])
|> add_section_redirects(section.sections, module_prefix, doc_filename, section_path)
end)
end
defp add_entity_redirects(
redirects,
entities,
module_prefix,
doc_filename,
section_path,
nested_entity_path
) do
Enum.reduce(entities, redirects, fn entity, acc ->
entity_module =
Spark.Dsl.Extension.entity_mod_name(
module_prefix,
nested_entity_path,
section_path,
entity
)
anchor = anchor(section_path ++ nested_entity_path ++ [entity.name])
redirect_target = "#{doc_filename}##{anchor}"
acc
|> Map.put(inspect(entity_module), redirect_target)
|> add_nested_entity_redirects(
entity.entities,
module_prefix,
doc_filename,
section_path,
nested_entity_path ++ [entity.name]
)
end)
end
defp add_nested_entity_redirects(
redirects,
nested_entities,
module_prefix,
doc_filename,
section_path,
nested_entity_path
) do
nested_entities
|> Enum.flat_map(fn {_key, entities} -> List.wrap(entities) end)
|> Enum.reduce(redirects, fn nested_entity, acc ->
add_entity_redirects(
acc,
[nested_entity],
module_prefix,
doc_filename,
section_path,
nested_entity_path
)
end)
end
defp add_patch_redirects(redirects, patches, module_prefix, doc_filename) do
Enum.reduce(patches, redirects, fn
%Spark.Dsl.Patch.AddEntity{section_path: section_path, entity: entity}, acc ->
add_entity_redirects(acc, [entity], module_prefix, doc_filename, section_path, [])
end)
end
@doc """
Generates searchable documentation suitable for ex_doc
"""
def search_data_for(dsl) do
dsl.sections()
|> Enum.flat_map(fn section ->
section_search_data(section)
end)
|> Enum.concat(
Enum.flat_map(dsl.dsl_patches(), fn %Spark.Dsl.Patch.AddEntity{
section_path: section_path,
entity: entity
} ->
entity_search_data(entity, section_path)
end)
)
end
defp section_search_data(section, path \\ []) do
schema_path =
if section.top_level? do
path
else
path ++ [section.name]
end
Enum.concat([
[
%{
anchor: anchor(schema_path),
body: section.describe,
title: title(schema_path),
type: "DSL"
}
],
schema_search_data(section.schema, schema_path),
Enum.flat_map(section.entities, &entity_search_data(&1, schema_path)),
Enum.flat_map(section.sections, &section_search_data(&1, schema_path))
])
|> Enum.map(fn search_item ->
if section.top_level? do
%{search_item | anchor: "#{section.name}-#{search_item.anchor}"}
else
search_item
end
end)
end
defp entity_search_data(entity, path) do
Enum.concat([
[
%{
anchor: anchor(path ++ [entity.name]),
body: entity.describe,
title: title(path ++ [entity.name]),
type: "DSL"
}
],
schema_search_data(entity.schema, path ++ [entity.name]),
Enum.flat_map(entity.entities, fn {_key, entities} ->
Enum.flat_map(entities, fn nested_entity ->
entity_search_data(nested_entity, path ++ [entity.name])
end)
end)
])
end
defp schema_search_data(schema, path) do
Enum.flat_map(schema, fn {key, config} ->
if config[:hide] do
[]
else
[
%{
anchor: anchor(path ++ [key]),
body: config[:doc] || "",
title: title(path ++ [key]),
type: "DSL"
}
]
end
end)
end
defp anchor(list), do: Enum.join(list, "-")
defp title(list), do: Enum.join(list, ".")
end