meta-types.nix: Refactor

This commit is contained in:
Silvan Mosberger
2026-02-26 14:53:02 +01:00
parent 4e0f75f6fe
commit 7ae278da36
2 changed files with 59 additions and 32 deletions
+5 -31
View File
@@ -317,7 +317,7 @@ let
${concatStrings (map (output: " - ${output}\n") missingOutputs)}
'';
metaTypes =
metaType =
let
types = import ./meta-types.nix { inherit lib; };
inherit (types)
@@ -329,13 +329,14 @@ let
any
listOf
bool
record
;
platforms = listOf (union [
str
(attrsOf any)
]); # see lib.meta.platformMatch
in
{
record {
# These keys are documented
description = str;
mainProgram = str;
@@ -404,34 +405,7 @@ let
identifiers = attrs;
};
# Map attrs directly to the verify function for performance
metaTypes' = mapAttrs (_: t: t.verify) metaTypes;
checkMetaAttr =
k: v:
if metaTypes ? ${k} then
if metaTypes'.${k} v then
[ ]
else
[
"key 'meta.${k}' has invalid value; expected ${metaTypes.${k}.name}, got\n ${
toPretty { indent = " "; } v
}"
]
else
[
"key 'meta.${k}' is unrecognized; expected one of: \n [${
concatMapStringsSep ", " (x: "'${x}'") (attrNames metaTypes)
}]"
];
checkMeta = meta: concatMap (attr: checkMetaAttr attr meta.${attr}) (attrNames meta);
metaInvalid =
if config.checkMeta then
meta: !all (attr: metaTypes ? ${attr} && metaTypes'.${attr} meta.${attr}) (attrNames meta)
else
meta: false;
metaInvalid = if config.checkMeta then meta: !metaType.verify meta else meta: false;
checkOutputsToInstall =
if config.checkMeta then
@@ -459,7 +433,7 @@ let
{
reason = "unknown-meta";
errormsg = "has an invalid meta attrset:${
concatMapStrings (x: "\n - " + x) (checkMeta attrs.meta)
concatMapStrings (x: "\n - " + x) (metaType.errors "${getName attrs}.meta" attrs.meta)
}\n";
remediation = "";
}
+54 -1
View File
@@ -12,16 +12,40 @@ let
isList
all
any
attrNames
attrValues
concatMap
isFunction
isBool
concatStringsSep
concatMapStringsSep
isFloat
elem
mapAttrs
;
isTypeDef = t: isAttrs t && t ? name && isString t.name && t ? verify && isFunction t.verify;
in
lib.fix (self: {
/*
`errors type "<context>" value` gives a list of string error messages,
each prefixed with "<context>: ", for why `value` is not of type `type`
Only use this if `type.verify value` is false
Types can override this by specifying their own `type.errors = ctx: value:` attribute
This is intentionally not tied into `type.verify`,
in order to keep the successful path as fast as possible with minimal allocations
*/
errors =
t:
t.errors or (ctx: v: [
"${ctx}: Invalid value; expected ${t.name}, got\n ${
lib.generators.toPretty { indent = " "; } v
}"
]);
string = {
name = "string";
verify = isString;
@@ -95,4 +119,33 @@ lib.fix (self: {
name = "union<${concatStringsSep "," (map (t: t.name) types)}>";
verify = v: any (func: func v) funcs;
};
record =
fields:
assert isAttrs fields && all isTypeDef (attrValues fields);
let
# Map attrs directly to the verify function for performance
fieldVerifiers = mapAttrs (_: t: t.verify) fields;
in
{
name = "record";
verify = v: isAttrs v && all (k: fieldVerifiers ? ${k} && fieldVerifiers.${k} v.${k}) (attrNames v);
errors =
ctx: v:
if !isAttrs v then
self.errors self.attrs ctx v
else
concatMap (
k:
if fieldVerifiers ? ${k} then
lib.optionals (fieldVerifiers.${k} v.${k}) (self.errors fields.${k} (ctx + ".${k}") v.${k})
else
[
"${ctx}: key '${k}' is unrecognized; expected one of: \n [${
concatMapStringsSep ", " (x: "'${x}'") (attrNames fields)
}]"
]
) (attrNames v);
};
})