Skip to content
Closed
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
83 changes: 83 additions & 0 deletions lib/attrsets.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,89 @@ rec {
*/
attrsToList = mapAttrsToList nameValuePair;

/**
Recursively deconstructs attrset to a list of path-value pairs.

Note that this function ignores empty sets. If you need them in your result,
look at `attrsToList'`.

# Inputs

`set`

: The attribute set to deconstruct.

# Type

```
attrsToListRecursive :: AttrSet -> [ { path :: [ String ]; value :: Any; } ]
```

# Examples

```nix
attrsToListRecursive { n = { a = "A"; m = { b = "B"; c = {}; }; }; d = "D"; e = {}; }
=> [ { path = [ "d" ]; value = "D"; } { path = [ "n" "a" ]; value = "A"; } { path = [ "n" "m" "b" ]; value = "B"; } ]
```
*/
attrsToListRecursive =
set:
let
op =
acc: path: value:
# the current value is tree
if (isAttrs value) then
(recurse acc path value)
# the current value is leaf
else
acc ++ [ { inherit path value; } ];
recurse =
acc: path: value:
foldl' (acc: key: op acc (path ++ [ key ]) value.${key}) acc (attrNames value);
in
recurse [ ] [ ] set;

/**
Like `attrsToListRecursive` but takes empty sets in tree as a leaves.

# Inputs

`set`

: The attribute set to deconstruct.

# Type

```
attrsToListRecursive' :: AttrSet -> [ { path :: [ String ]; value :: Any; } ]
```

# Examples

```nix
attrsToListRecursive' { n = { a = "A"; m = { b = "B"; c = {}; }; }; d = "D"; e = {}; }
=> [ { path = [ "d" ]; value = "D"; } { path = [ "e" ]; value = { }; } { path = [ "n" "a" ]; value = "A"; } { path = [ "n" "m" "b" ]; value = "B"; } { path = [ "n" "m" "c" ]; value = { }; } ]
```
*/
attrsToListRecursive' =
set:
let
op =
acc: path: value:
# the current value is leaf or empty tree
if ((!isAttrs value) || (value == { })) then
acc ++ [ { inherit path value; } ]
# the current value is non-empty tree
else
(recurse acc path value);

recurse =
acc: path: value:
foldl' (acc: key: op acc (path ++ [ key ]) value.${key}) acc (attrNames value);

in
recurse [ ] [ ] set;

/**
Like `mapAttrs`, except that it recursively applies itself to the *leaf* attributes of a potentially-nested attribute set:
the second argument of the function will never be an attrset.
Expand Down
2 changes: 2 additions & 0 deletions lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ let
mapAttrs'
mapAttrsToList
attrsToList
attrsToListRecursive
attrsToListRecursive'
concatMapAttrs
mapAttrsRecursive
mapAttrsRecursiveCond
Expand Down