Sebastian Walz 860d31cee1
Tohu vaBohu
2023-04-21 00:22:52 +02:00

307 lines
9.6 KiB
Nix

{ core, context, extendPath, ... }:
options:
let
inherit(core) debug list set string type;
addOption
= { options, ... } @ state:
name:
option:
state
// {
options
= options
// {
${name} = option;
};
};
collect
= {
__type__,
apply,
default,
documentation,
internal,
optionType,
path,
readOnly,
}:
definitions:
if type.isList definitions
then
let
value
= if definitions == []
then
if optionType.check default
then
default
else
debug.panic
"collect"
"The default value of `${path}` does not match its type `${optionType.name}`!"
else if list.length definitions == 1
then
let
first = (list.head definitions).value;
in
if optionType.check first
then
first
else
debug.panic
"collect"
"The value of `${path}` does not match its type `${optionType.name}`!"
else if readOnly
then
debug.panic
"collect"
"The option `${path}` is read-only, but was set multiple times!"
else if list.any ({ value, ... }: optionType.check value) definitions
then
optionType.merge [ path ] definitions
else
debug.panic
"collect"
"A value of `${path}` does not match its type `${optionType.name}`!";
in
debug.warn
"collect"
{
when = optionType.deprecationMessage != null;
text
= ''
The type `${optionType.name}' of option `${path}' defined is deprecated.
${optionType.deprecationMessage}
'';
}
value
else
debug.panic
"collect"
"A list of definitions expected, got ${type.getPrimitive definitions}";
collects
= { config, options, ... }:
if type.isSet config
then
set.map
(
name:
{
__type__ ? null,
...
} @ option:
if __type__ == "Option"
then
collect
option
(config.${name} or [])
else
collects
{
config = config.${name} or {};
options = option;
}
)
options
else
debug.panic
"collects"
"An attribute set of options expected, got ${type.getPrimitive config}";
combineLegacy
= { ... } @ state:
options:
debug.info "combineLegacy"
{
text = "mew";
data = options;
}
(
set.fold
(
{ options, path, ... } @ state:
name:
option:
let
addOption' = addOption state name;
path' = extendPath path name;
in
debug.debug "combineLegacy"
{
text = "${path'}";
data = (set.names option);
}
(
if set.hasAttribute name options
then
if options.${name} ? __type__
then
debug.panic
"combineLegacy"
"Option `${path'}` already defined"
else if option.__type__ or null == null
then
addOption'
(
combineLegacy
{
options = options.${name};
path = path';
}
option
).options
else
debug.panic
"combineLegacy"
"Option `${path'}` is already defined as an attribute set, so only attribute sets of options can be added"
else if option._type or null == "option"
then
addOption' (convertLegacy path' option)
else
addOption'
(
combineLegacy
{
options = {};
path = path';
}
option
).options
)
)
state
options
);
combineModules
= state:
{
config ? null,
evaluate ? null,
imports ? [],
legacy,
options,
...
}:
if legacy
then
combineLegacy state options
else
combine state options;
combine
= state:
options:
set.fold
(
{ options, path, ... } @ state:
name:
option:
let
addOption' = addOption state name;
path' = extendPath path name;
in
if set.hasAttribute name options
then
if options.${name} ? __type__
then
debug.panic
"combine"
"Option `${path'}` already defined"
else if option.__type__ or null == null
then
addOption'
(
combine
{
options = options.${name};
path = path';
}
option
).options
else
debug.panic
"combine"
"Option `${path'}` is already defined as an attribute set, so only attribute sets of options can be added"
else
addOption' option
)
state
options;
convertLegacy
= path:
{
default ? null,
defaultText ? null,
example ? null,
description ? null,
relatedPackages ? null,
type ? null,
apply ? (x: x),
internal ? false,
value ? null,
visible ? true,
readOnly ? false,
...
}:
debug.info "convertLegacy"
{
text = "value?";
when = value != null;
data = value;
}
{
__type__ = "Option";
documentation
= if visible
then
{
default
= if defaultText != null
then
defaultText
else
string default;
inherit description example relatedPackages;
type = { inherit(type) description descriptionClass name; };
}
else
null;
inherit apply default internal path readOnly;
optionType = convertLegacyType type;
};
convertLegacyType
= {
check, # T -> bool
deprecationMessage, # string?
description, # string
descriptionClass, # irrelevant?
emptyValue, # {} | { value: T; }
functor, # string -> type -> wrapped -> payload: P -> (binop: P -> P -> P) ->
getSubOptions, # T -> { string -> U }
getSubModules, # [ LegacyModule ]?
merge, # [ string ] -> [ { file: path; value: T; } ] -> { string -> T }
name, # string
nestedTypes, # irrelevant?
substSubModules, # T -> U
typeMerge, # T -> T -> T
...
}:
{
inherit check deprecationMessage merge name;
};
options'
= combineLegacy
{
options = {};
path = null;
}
(set.remove options [ "_module" ]);
in