{ lib, ... }: let sane-lib = rec { feeds = import ./feeds.nix { inherit lib; }; fs = import ./fs.nix { inherit lib sane-lib; }; merge = import ./merge.nix { inherit lib sane-lib; }; path = import ./path.nix { inherit lib; }; types = import ./types.nix { inherit lib; }; # re-exports inherit (merge) mkTypedMerge; # like `builtins.listToAttrs` but any duplicated `name` throws error on access. # Type: listToDisjointAttrs :: [{ name :: String, value :: Any }] -> AttrSet listToDisjointAttrs = l: joinAttrsets (builtins.map nameValueToAttrs l); # true if p is a prefix of l (even if p == l) # Type: isPrefixOfList :: [Any] -> [Any] -> bool isPrefixOfList = p: l: (lib.sublist 0 (lib.length p) l) == p; # merges N attrsets # Type: joinAttrsets :: [AttrSet] -> AttrSet joinAttrsets = l: lib.foldl' lib.attrsets.unionOfDisjoint {} l; # merges N attrsets, recursively # Type: joinAttrsetsRecursive :: [AttrSet] -> AttrSet joinAttrsetsRecursive = l: lib.foldl' (lib.attrsets.recursiveUpdateUntil (path: lhs: rhs: false)) {} l; # evaluate a `{ name, value }` pair in the same way that `listToAttrs` does. # Type: nameValueToAttrs :: { name :: String, value :: Any } -> Any nameValueToAttrs = { name, value }: { "${name}" = value; }; # if `maybe-null` is non-null, yield that. else, return the `default`. withDefault = default: maybe-null: if maybe-null != null then maybe-null else default; # removes null entries from the provided AttrSet. acts recursively. # Type: filterNonNull :: AttrSet -> AttrSet filterNonNull = attrs: lib.filterAttrsRecursive (n: v: v != null) attrs; # return only the subset of `attrs` whose name is in the provided set. # Type: filterByName :: [String] -> AttrSet filterByName = names: attrs: lib.filterAttrs (name: value: builtins.elem name names) attrs; # transform a list into an AttrSet via a function which maps an element to a { name, value } pair. # it's an error for the same name to be specified more than once # Type: mapToAttrs :: (a -> { name :: String, value :: Any }) -> [a] -> AttrSet mapToAttrs = f: list: listToDisjointAttrs (builtins.map f list); # flatten a nested AttrSet into a list of { path = [String]; value } items. # the output contains only non-attr leafs. # so e.g. { a.b = 1; } -> [ { path = ["a" "b"]; value = 1; } ] # but e.g. { a.b = {}; } -> [] # # Type: flattenAttrs :: AttrSet[AttrSet|Any] -> [{ path :: String, value :: Any }] flattenAttrs = flattenAttrs' []; flattenAttrs' = path: value: if builtins.isAttrs value then ( builtins.concatLists ( lib.mapAttrsToList (name: flattenAttrs' (path ++ [ name ])) value ) ) else [ { inherit path value; } ]; # like `lib.listFilesRecursive` but does not mangle paths. # # Type: enumerateFilePaths :: path -> [String] enumerateFilePaths = base: builtins.concatLists ( lib.mapAttrsToList (name: type: if type == "directory" then # enumerate this directory and then prefix each result with the directory's name builtins.map (e: "${name}/${e}") (enumerateFilePaths (base + "/${name}")) else [ name ] ) (builtins.readDir base) ); }; in sane-lib