labs/lib/src/default.nix

79 lines
2 KiB
Nix

let
files = [
./attrs
./bools
./dag
./errors
./fp
./generators
./importers
./licenses
./lists
./math
./modules
./numbers
./options
./packages
./paths
./points
./strings
./types
./versions
];
libs = builtins.map (f: import f) files;
## Calculate the fixed point of a function. This will evaluate the function `f`
## until its result settles (or Nix's recursion limit is reached). This allows
## us to define recursive functions without worrying about the order of their
## definitions.
##
## @type (a -> a) -> a
fix = f: let
x = f x;
in
x;
## Merge two attribute sets recursively until a given predicate returns true.
## Any values that are _not_ attribute sets will be overridden with the value
## from `y` first if it exists and then `x` otherwise.
##
## @type Attrs a b c => (String -> Any -> Any -> Bool) -> a -> b -> c
mergeAttrsRecursiveUntil = predicate: x: y: let
process = path:
builtins.zipAttrsWith (
name: values: let
currentPath = path ++ [name];
isSingleValue = builtins.length values == 1;
isComplete =
predicate currentPath
(builtins.elemAt values 1)
(builtins.elemAt values 0);
in
if isSingleValue || isComplete
then builtins.elemAt values 0
else process currentPath values
);
in
process [] [x y];
## Merge two attribute sets recursively. Any values that are _not_ attribute sets
## will be overridden with the value from `y` first if it exists and then `x`
## otherwise.
##
## @type Attrs a b c => a -> b -> c
mergeAttrsRecursive =
mergeAttrsRecursiveUntil
(path: x: y:
!(builtins.isAttrs x && builtins.isAttrs y));
lib = fix (
self: let
merge = acc: create:
mergeAttrsRecursive acc (create self);
in
builtins.foldl' merge {} libs
);
in
lib.points.withExtend (lib.fp.const lib)