Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/tests/modules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,10 @@ checkConfigError 'In module .*/options-type-error-configuration.nix: expected an
# Check that that merging of option collisions doesn't depend on type being set
checkConfigError 'The option .group..*would be a parent of the following options, but its type .<no description>. does not support nested options.\n\s*- option.s. with prefix .group.enable..*' config.group.enable ./merge-typeless-option.nix

# types.optionDeclaration
checkConfigOutput '^10$' config.anOption ./option.nix
checkConfigError 'A definition for option .aBadOptionDef. is not of type .option declaration.' config.aBadOptionDef ./option.nix

# Test that types.optionType merges types correctly
checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix
checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix
Expand Down
27 changes: 27 additions & 0 deletions lib/tests/modules/option.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
config,
lib,
options,
...
}:
{
options = {
theOption = lib.mkOption {
type = lib.types.optionDeclaration;
};
anOption = config.theOption;
aBadOptionDef = lib.mkOption {
type = lib.types.optionDeclaration;
description = ''
This option is perfectly fine, but will have a bad definition.
'';
};
};
config = {
theOption = lib.mkOption {
type = lib.types.int;
};
anOption = 10;
aBadOptionDef = options.theOption; # Not a declaration
};
}
7 changes: 7 additions & 0 deletions lib/types.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,13 @@ rec {
};
};

optionDeclaration = mkOptionType {
name = "optionDeclaration";
description = "option declaration";
descriptionClass = "noun";
check = opt: isType "option" opt && !(opt ? value);
};

# The type of a type!
optionType = mkOptionType {
name = "optionType";
Expand Down
16 changes: 16 additions & 0 deletions nixos/doc/manual/development/option-types.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,22 @@ Users must still be careful about how they reference these paths.
multiple option definitions are correctly merged together. The main use
case is as the type of the `_module.freeformType` option.

`types.optionDeclaration`

: The type of a module system option declaration, as created by `lib.mkOption`.
This allows an option to hold another option declaration as its value, which
can then be spliced into a module's `options` attrset. Note that this only
accepts option declarations, not evaluated options (i.e. options that have
been processed by `evalModules` and have a `value` field).

::: {.warning}
Use of this type is a form of metaprogramming that makes modules harder
to reason about, since options and their types become dynamic values
rather than statically declared structure. Prefer conventional module
patterns where possible, and only reach for `types.optionDeclaration` when the
added complexity is justified.
:::

`types.attrs`

: A free-form attribute set.
Expand Down
Loading