feat: add portable submodule type #11
|
@ -916,6 +916,117 @@ lib: {
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
## Create a type from a submodule which can be used in multiple parts of the configuration.
|
||||
##
|
||||
## @type { module :: Module, name? :: String, description? :: String } -> Attrs
|
||||
portable =
|
||||
{ name ? "PortableSubmodule"
|
||||
, description ? "portable submodule"
|
||||
, module
|
||||
,
|
||||
}:
|
||||
let
|
||||
normalize =
|
||||
value:
|
||||
if builtins.isFunction value || builtins.isList value then
|
||||
value
|
||||
else if value ? __modules__ then
|
||||
value.__modules__
|
||||
else
|
||||
{ config = value; };
|
||||
|
||||
initial = lib.types.create {
|
||||
name = "PortableSubmoduleInitial";
|
||||
description = "initial portable submodule value";
|
||||
check = value: builtins.isFunction value || builtins.isAttrs value || builtins.isList value;
|
||||
merge =
|
||||
location: definitions:
|
||||
let
|
||||
normalized = builtins.map (definition: lib.lists.from.any (normalize definition.value)) definitions;
|
||||
in
|
||||
builtins.concatLists normalized;
|
||||
};
|
||||
|
||||
base = { config }: {
|
||||
options = {
|
||||
__modules__ = lib.options.create {
|
||||
description = "User specified modules to be evaluated.";
|
||||
type = lib.types.list.of (initial // { merge = lib.options.merge.one; });
|
||||
internal = true;
|
||||
default.value = [ ];
|
||||
};
|
||||
|
||||
extend = lib.options.create {
|
||||
description = "Extend the submodule configuration.";
|
||||
type = lib.types.function lib.types.raw;
|
||||
internal = true;
|
||||
writable = false;
|
||||
default.value = module:
|
||||
let
|
||||
normalized =
|
||||
if builtins.isList module then module
|
||||
else if builtins.isFunction module || module ? config then
|
||||
[ module ]
|
||||
else [{ config = module; }];
|
||||
|
||||
modules = config.__modules__ ++ normalized;
|
||||
|
||||
result = lib.modules.run {
|
||||
modules = [
|
||||
module
|
||||
base
|
||||
{ config.__modules__ = modules; }
|
||||
] ++ modules;
|
||||
};
|
||||
in
|
||||
result.config;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
transform = location: value:
|
||||
let
|
||||
modules = lib.lists.from.any (normalize value);
|
||||
|
||||
result = lib.modules.run {
|
||||
prefix = location;
|
||||
modules = [
|
||||
module
|
||||
base
|
||||
{ config.__modules__ = modules; }
|
||||
] ++ modules;
|
||||
};
|
||||
in
|
||||
result.config;
|
||||
|
||||
final = lib.types.raw // {
|
||||
merge = location: definitions:
|
||||
let
|
||||
modules = lib.lists.flatten (
|
||||
builtins.map (definition: normalize definition.value) definitions
|
||||
);
|
||||
|
||||
result = lib.modules.run {
|
||||
prefix = location;
|
||||
modules = [
|
||||
module
|
||||
base
|
||||
{ config.__modules__ = modules; }
|
||||
] ++ modules;
|
||||
};
|
||||
in
|
||||
result.config;
|
||||
};
|
||||
|
||||
type = lib.types.coerceWithLocation initial transform final;
|
||||
in
|
||||
type // {
|
||||
inherit name description;
|
||||
children = type.children // {
|
||||
inherit module base;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
deferred = {
|
||||
|
|
|
@ -1,4 +1,51 @@
|
|||
let
|
||||
lib = import ./../default.nix;
|
||||
in
|
||||
{ }
|
||||
{
|
||||
"PortableSubmodule" = {
|
||||
"is portable" =
|
||||
let
|
||||
submodule = { config }: {
|
||||
options = {
|
||||
primitive = lib.options.create {
|
||||
type = lib.types.string;
|
||||
default.value = "<default>";
|
||||
};
|
||||
|
||||
computed = lib.options.create {
|
||||
type = lib.types.string;
|
||||
default.value = "computed: ${config.primitive}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
option = lib.options.create {
|
||||
default.value = { };
|
||||
type = lib.types.submodules.portable {
|
||||
module = submodule;
|
||||
};
|
||||
};
|
||||
|
||||
moduleA = {
|
||||
options.a = option;
|
||||
};
|
||||
moduleB = { config }: {
|
||||
options.b = option;
|
||||
|
||||
config.b = config.a;
|
||||
};
|
||||
moduleC = {
|
||||
config.b.primitive = "custom";
|
||||
};
|
||||
|
||||
result = lib.modules.run {
|
||||
modules = [
|
||||
moduleA
|
||||
moduleB
|
||||
moduleC
|
||||
];
|
||||
};
|
||||
in
|
||||
result.config.b.computed == "computed: custom";
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue