1<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-freeform-modules">
2 <title>Freeform modules</title>
3 <para>
4 Freeform modules allow you to define values for option paths that
5 have not been declared explicitly. This can be used to add
6 attribute-specific types to what would otherwise have to be
7 <literal>attrsOf</literal> options in order to accept all attribute
8 names.
9 </para>
10 <para>
11 This feature can be enabled by using the attribute
12 <literal>freeformType</literal> to define a freeform type. By doing
13 this, all assignments without an associated option will be merged
14 using the freeform type and combined into the resulting
15 <literal>config</literal> set. Since this feature nullifies name
16 checking for entire option trees, it is only recommended for use in
17 submodules.
18 </para>
19 <anchor xml:id="ex-freeform-module" />
20 <para>
21 <emphasis role="strong">Example: Freeform submodule</emphasis>
22 </para>
23 <para>
24 The following shows a submodule assigning a freeform type that
25 allows arbitrary attributes with <literal>str</literal> values below
26 <literal>settings</literal>, but also declares an option for the
27 <literal>settings.port</literal> attribute to have it type-checked
28 and assign a default value. See
29 <link linkend="ex-settings-typed-attrs">Example: Declaring a
30 type-checked <literal>settings</literal> attribute</link> for a more
31 complete example.
32 </para>
33 <programlisting language="bash">
34{ lib, config, ... }: {
35
36 options.settings = lib.mkOption {
37 type = lib.types.submodule {
38
39 freeformType = with lib.types; attrsOf str;
40
41 # We want this attribute to be checked for the correct type
42 options.port = lib.mkOption {
43 type = lib.types.port;
44 # Declaring the option also allows defining a default value
45 default = 8080;
46 };
47
48 };
49 };
50}
51</programlisting>
52 <para>
53 And the following shows what such a module then allows
54 </para>
55 <programlisting language="bash">
56{
57 # Not a declared option, but the freeform type allows this
58 settings.logLevel = "debug";
59
60 # Not allowed because the the freeform type only allows strings
61 # settings.enable = true;
62
63 # Allowed because there is a port option declared
64 settings.port = 80;
65
66 # Not allowed because the port option doesn't allow strings
67 # settings.port = "443";
68}
69</programlisting>
70 <note>
71 <para>
72 Freeform attributes cannot depend on other attributes of the same
73 set without infinite recursion:
74 </para>
75 <programlisting language="bash">
76{
77 # This throws infinite recursion encountered
78 settings.logLevel = lib.mkIf (config.settings.port == 80) "debug";
79}
80</programlisting>
81 <para>
82 To prevent this, declare options for all attributes that need to
83 depend on others. For above example this means to declare
84 <literal>logLevel</literal> to be an option.
85 </para>
86 </note>
87</section>