{ lib, config, self, inputs, ... }: let inherit (config.lib) and eq hasFiles ; in { config.lib = rec { # Try to passthru `inputs` by default defaultThingHandle = { raw, thingType }: name: result: let thing = if raw then result else result.${thingType}; passthru = { inherit inputs; }; handledThing = if and [ (builtins.isFunction thing) # FIXME: check for subset, not `eq` (eq (lib.pipe thing [ builtins.functionArgs builtins.attrNames ]) (lib.pipe passthru [ builtins.attrNames ])) ] # { inputs, ... }: { foo, ... }: bar then thing passthru # { foo, ... }: bar else thing; handledResult = if raw then handledThing else result // { ${thingType} = handledThing; }; in handledResult; # TODO: make `passthru` more generic (maybe take `thing` as arg and decide itself what to do?) createThings = { baseDir , thingType ? "thing" , filter ? (name: type: true) , handle ? (defaultThingHandle { inherit raw thingType; }) , raw ? true , extras ? {} , ... }: assert raw -> extras == {}; lib.pipe baseDir [ # Read given directory builtins.readDir # Filter out unwanted things (lib.filterAttrs filter) # Map each entry to a thing (lib.mapAttrs' (name: type: let # BUG: cannot use `append` because of `${self}` (not a path) # thingDir = lib.path.append baseDir "${name}"; thingDir = "${baseDir}/${name}"; importedExtras = lib.pipe extras [ (lib.mapAttrs (name: { default, ... }: assert name != "default"; assert name != thingType; let extraPath = "${thingDir}/${name}.nix"; in if builtins.pathExists extraPath then import extraPath else default)) ]; thing = import thingDir; result = if raw then thing else lib.attrsets.unionOfDisjoint { ${thingType} = thing; } importedExtras; in if and [ (type == "directory") (hasFiles [ "default.nix" ] (builtins.readDir thingDir)) ] then # Classic thing in a directory lib.nameValuePair name result else if and [ (type == "regular") (lib.hasSuffix ".nix" name) ] then # Classic thing in a file lib.nameValuePair (lib.removeSuffix ".nix" name) result else # Invalid thing lib.nameValuePair name null)) # Filter invalid things (lib.filterAttrs (thingName: thing: thing != null)) # Handle if needed (lib.mapAttrs handle) ]; }; }