11# SPDX-FileCopyrightText: 2018-2022, 2025 Jean-Philippe Cugnet <jean-philippe@cugnet.eu>
22# SPDX-FileCopyrightText: 2018 Marcin Górnik <marcin.gornik@gmail.com>
33# SPDX-FileCopyrightText: 2022 Jonathan Chukinas <chukinas@gmail.com>
4+ # SPDX-FileCopyrightText: 2022 Balázs Jávorszky <javorszky.balazs@estyle.hu>
45#
56# SPDX-License-Identifier: MIT
67
@@ -16,6 +17,7 @@ defmodule TypedStruct do
1617 :ts_plugin_fields ,
1718 :ts_fields ,
1819 :ts_types ,
20+ :ts_docs ,
1921 :ts_enforce_keys
2022 ]
2123
@@ -116,10 +118,46 @@ defmodule TypedStruct do
116118 @ enforce_keys @ ts_enforce_keys
117119 defstruct @ ts_fields
118120
121+ TypedStruct . __typedoc__ ( @ ts_docs )
119122 TypedStruct . __type__ ( @ ts_types , unquote ( opts ) )
120123 end
121124 end
122125
126+ @ doc false
127+ defmacro __typedoc__ ( docs ) do
128+ quote bind_quoted: [ docs: docs ] do
129+ field_docs =
130+ docs
131+ |> Enum . reverse ( )
132+ |> Enum . filter ( fn { _ , doc } -> ! is_nil ( doc ) end )
133+ |> Enum . map ( fn { name , doc } -> "- `#{ name } ` - #{ doc } " end )
134+
135+ if field_docs != [ ] do
136+ # If there are field docs, we complete the `@typedoc` with field
137+ # documentation. However, if there is no `@typedoc` already, let’s emit
138+ # a warning instead.
139+ if Module . has_attribute? ( __MODULE__ , :typedoc ) do
140+ @ typedoc """
141+ #{ @ typedoc }
142+
143+ ## Fields
144+
145+ #{ Enum . join ( field_docs , "\n " ) }
146+ """
147+ else
148+ IO . warn (
149+ """
150+ adding field documentation has no effect without a @typedoc
151+
152+ hint: add a @typedoc on your `typedstruct` definition
153+ """ ,
154+ Macro.Env . stacktrace ( __ENV__ )
155+ )
156+ end
157+ end
158+ end
159+ end
160+
123161 @ doc false
124162 defmacro __type__ ( types , opts ) do
125163 if Keyword . get ( opts , :opaque , false ) do
@@ -174,6 +212,7 @@ defmodule TypedStruct do
174212 * `default` - sets the default value for the field
175213 * `enforce` - if set to true, enforces the field and makes its type
176214 non-nullable
215+ * `doc` - description for the field to be added to the `@typedoc`
177216 """
178217 defmacro field ( name , type , opts \\ [ ] ) do
179218 quote bind_quoted: [ name: name , type: Macro . escape ( type ) , opts: opts ] do
@@ -208,6 +247,7 @@ defmodule TypedStruct do
208247 Module . put_attribute ( mod , :ts_fields , { name , opts [ :default ] } )
209248 Module . put_attribute ( mod , :ts_plugin_fields , { name , type , opts , env } )
210249 Module . put_attribute ( mod , :ts_types , { name , type_for ( type , nullable? ) } )
250+ Module . put_attribute ( mod , :ts_docs , { name , opts [ :doc ] } )
211251 if enforce? , do: Module . put_attribute ( mod , :ts_enforce_keys , name )
212252 end
213253
0 commit comments