summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lib/attrsets.nix21
-rw-r--r--lib/default.nix2
-rw-r--r--lib/tests/misc.nix17
3 files changed, 38 insertions, 2 deletions
diff --git a/lib/attrsets.nix b/lib/attrsets.nix
index 0a4c3c8ebcf..8b5c0ef4cea 100644
--- a/lib/attrsets.nix
+++ b/lib/attrsets.nix
@@ -3,7 +3,7 @@
 
 let
   inherit (builtins) head tail length;
-  inherit (lib.trivial) id;
+  inherit (lib.trivial) flip id mergeAttrs pipe;
   inherit (lib.strings) concatStringsSep concatMapStringsSep escapeNixIdentifier sanitizeDerivationName;
   inherit (lib.lists) foldr foldl' concatMap concatLists elemAt all partition groupBy take foldl;
 in
@@ -77,6 +77,25 @@ rec {
     let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
     in attrByPath attrPath (abort errorMsg);
 
+  /* Map each attribute in the given set and merge them into a new attribute set.
+
+     Type:
+       concatMapAttrs ::
+         (String -> a -> AttrSet)
+         -> AttrSet
+         -> AttrSet
+
+     Example:
+       concatMapAttrs
+         (name: value: {
+           ${name} = value;
+           ${name + value} = value;
+         })
+         { x = "a"; y = "b"; }
+       => { x = "a"; xa = "a"; y = "b"; yb = "b"; }
+  */
+  concatMapAttrs = f: flip pipe [ (mapAttrs f) attrValues (foldl' mergeAttrs { }) ];
+
 
   /* Update or set specific paths of an attribute set.
 
diff --git a/lib/default.nix b/lib/default.nix
index 8bb06954518..cc4bedc5869 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -78,7 +78,7 @@ let
     inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
       getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs
       filterAttrsRecursive foldAttrs collect nameValuePair mapAttrs
-      mapAttrs' mapAttrsToList mapAttrsRecursive mapAttrsRecursiveCond
+      mapAttrs' mapAttrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond
       genAttrs isDerivation toDerivation optionalAttrs
       zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
       recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix
index 31c938a8ffd..b73da4f1010 100644
--- a/lib/tests/misc.nix
+++ b/lib/tests/misc.nix
@@ -478,6 +478,23 @@ runTests {
 
 # ATTRSETS
 
+  testConcatMapAttrs = {
+    expr = concatMapAttrs
+      (name: value: {
+        ${name} = value;
+        ${name + value} = value;
+      })
+      {
+        foo = "bar";
+        foobar = "baz";
+      };
+    expected = {
+      foo = "bar";
+      foobar = "baz";
+      foobarbaz = "baz";
+    };
+  };
+
   # code from the example
   testRecursiveUpdateUntil = {
     expr = recursiveUpdateUntil (path: l: r: path == ["foo"]) {