lib/introspect: recurse for nested attrsOf

This commit is contained in:
Johannes Kirschbauer
2025-10-01 16:56:43 +02:00
parent a8156d2fa6
commit 1a8131f17f
2 changed files with 127 additions and 20 deletions

View File

@@ -10,6 +10,46 @@ let
] ]
); );
pushPositions = map (
def:
lib.mapAttrs (_n: v: {
inherit (def) file;
value = v;
}) def.value
);
unwrapNullOr =
type:
let
typeName = type.name or null;
in
if typeName == "nullOr" then type.nestedTypes.name or null else typeName;
mergeAttrs =
{ type, definitionsWithLocations }:
let
# Vendored merge from lib.types.attrsOf
# Because we still cannot access highest prio for the individual attrs yet.
elemType = type.nestedTypes.elemType;
mergedAttrs = lib.zipAttrsWith (name: defs: lib.modules.mergeDefinitions ([ name ]) elemType defs) (
pushPositions definitionsWithLocations
);
headType = unwrapNullOr elemType;
nullable = elemType.name or null == "nullOr";
total = elemType.name or null == "submodule";
in
lib.mapAttrs (_name: merged: {
__this = {
prio = merged.defsFinal'.highestPrio;
files = map (def: def.file) merged.defsFinal'.values;
inherit
headType
nullable
total
;
};
}) mergedAttrs;
/** /**
Takes a set of options as returned by `configuration` Takes a set of options as returned by `configuration`
@@ -45,19 +85,15 @@ let
lib.mapAttrs ( lib.mapAttrs (
_: opt: _: opt:
let let
headType = headType = unwrapNullOr opt.type;
let
typeName = opt.type.name or null;
in
if typeName == "nullOr" then opt.type.nestedTypes.name or null else typeName;
nullable = opt.type.name or null == "nullOr"; nullable = opt.type.name or null == "nullOr";
total = opt.type.name or null == "submodule";
definitionInfo = { definitionInfo = {
__this = { __this = {
prio = opt.highestPrio or null; prio = opt.highestPrio or null;
files = opt.files or [ ]; files = opt.files or [ ];
inherit headType nullable; inherit headType nullable total;
total = opt.type.name or null == "submodule";
}; };
}; };
@@ -71,18 +107,34 @@ let
/** /**
Maps attrsOf and lazyAttrsOf Maps attrsOf and lazyAttrsOf
*/ */
handleAttrsOf = attrs: lib.mapAttrs (_: handleMeta) attrs; handleAttrsOf =
type: defs: attrs:
lib.mapAttrs (
name: meta:
(mergeAttrs {
inherit type;
definitionsWithLocations = defs;
}).${name}
// handleMeta {
inherit meta;
definitionsWithLocations =
(builtins.zipAttrsWith (_name: values: values) (pushPositions defs)).${name};
}
) attrs;
/** /**
Maps attrsOf and lazyAttrsOf Maps attrsOf and lazyAttrsOf
*/ */
handleListOf = list: { __list = lib.map handleMeta list; }; handleListOf = list: { __list = lib.map handleMeta { meta = list; }; };
/** /**
Unwraps the valueMeta of an option based on its type Unwraps the valueMeta of an option based on its type
*/ */
handleMeta = handleMeta =
meta: {
meta,
definitionsWithLocations ? [ ],
}:
let let
hasType = meta ? _internal.type; hasType = meta ? _internal.type;
type = meta._internal.type; type = meta._internal.type;
@@ -93,7 +145,7 @@ let
# TODO: handle types # TODO: handle types
getPrios { options = filterOptions meta.configuration.options; } getPrios { options = filterOptions meta.configuration.options; }
else if type.name == "attrsOf" || type.name == "lazyAttrsOf" then else if type.name == "attrsOf" || type.name == "lazyAttrsOf" then
handleAttrsOf meta.attrs handleAttrsOf meta._internal.type definitionsWithLocations meta.attrs
# TODO: Add index support in nixpkgs first # TODO: Add index support in nixpkgs first
# else if type.name == "listOf" then # else if type.name == "listOf" then
# handleListOf meta.list # handleListOf meta.list
@@ -103,7 +155,7 @@ let
if opt ? type && opt.type.name == "submodule" then if opt ? type && opt.type.name == "submodule" then
(definitionInfo) // submodulePrios (definitionInfo) // submodulePrios
else if opt ? type && (opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf") then else if opt ? type && (opt.type.name == "attrsOf" || opt.type.name == "lazyAttrsOf") then
definitionInfo // (handleAttrsOf opt.valueMeta.attrs) definitionInfo // (handleAttrsOf opt.type opt.definitionsWithLocations opt.valueMeta.attrs)
# TODO: Add index support in nixpkgs, otherwise we cannot # TODO: Add index support in nixpkgs, otherwise we cannot
else if opt ? type && (opt.type.name == "listOf") then else if opt ? type && (opt.type.name == "listOf") then
definitionInfo // (handleListOf opt.valueMeta.list) definitionInfo // (handleListOf opt.valueMeta.list)

View File

@@ -314,12 +314,17 @@ in
} }
); );
}; };
}
{
config.foo.nested = lib.mkForce {
# <- 50 prio
"bar" = 2;
};
}
{
config.foo = { config.foo = {
"nested" = { "other" = lib.mkForce {
"bar" = 2; # <- 100 prio ? "bar" = 2; # <- 50 prio
};
"other" = {
"bar" = lib.mkForce 2; # <- 50 prio ?
}; };
}; };
} }
@@ -330,11 +335,19 @@ in
expected = { expected = {
foo = { foo = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [
"<unknown-file>"
"<unknown-file>"
];
prio = 100; prio = 100;
total = false; total = false;
}; };
nested = { nested = {
__this = {
files = [ "<unknown-file>" ];
prio = 50;
total = true;
};
bar = { bar = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [ "<unknown-file>" ];
@@ -344,10 +357,15 @@ in
}; };
}; };
other = { other = {
__this = {
files = [ "<unknown-file>" ];
prio = 50;
total = true;
};
bar = { bar = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [ "<unknown-file>" ];
prio = 50; prio = 100;
total = false; total = false;
}; };
}; };
@@ -401,7 +419,17 @@ in
total = false; total = false;
}; };
a = { a = {
__this = {
files = [ "<unknown-file>" ];
prio = 100;
total = false;
};
b = { b = {
__this = {
files = [ "<unknown-file>" ];
prio = 100;
total = true;
};
bar = { bar = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [ "<unknown-file>" ];
@@ -411,6 +439,11 @@ in
}; };
}; };
c = { c = {
__this = {
files = [ "<unknown-file>" ];
prio = 100;
total = true;
};
bar = { bar = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [ "<unknown-file>" ];
@@ -421,7 +454,17 @@ in
}; };
}; };
x = { x = {
__this = {
files = [ "<unknown-file>" ];
prio = 100;
total = false;
};
y = { y = {
__this = {
files = [ "<unknown-file>" ];
prio = 100;
total = true;
};
bar = { bar = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [ "<unknown-file>" ];
@@ -431,6 +474,11 @@ in
}; };
}; };
z = { z = {
__this = {
files = [ "<unknown-file>" ];
prio = 100;
total = true;
};
bar = { bar = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [ "<unknown-file>" ];
@@ -443,7 +491,6 @@ in
}; };
}; };
}; };
test_attrsOf_submodule_default = test_attrsOf_submodule_default =
let let
evaluated = eval [ evaluated = eval [
@@ -496,6 +543,14 @@ in
total = false; total = false;
}; };
jon = { jon = {
__this = {
files = [
"<unknown-file>"
"inventory.json"
];
prio = 100;
total = true;
};
fludl = { fludl = {
__this = { __this = {
files = [ "<unknown-file>" ]; files = [ "<unknown-file>" ];