Modular, context-aware and aspect-oriented dendritic Nix configurations. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ den.oeiuwq.com
configurations den dendritic nix aspect oriented

woot woot

+50 -6
+50 -6
nix/namespace.nix
··· 3 3 let 4 4 from = lib.flatten [ sources ]; 5 5 isOutput = builtins.any (x: x == true) from; 6 - denfuls = map (lib.getAttrFromPath [ 7 - "denful" 8 - name 9 - ]) (builtins.filter builtins.isAttrs from); 6 + attrs = builtins.filter builtins.isAttrs from; 7 + 8 + # Strip module system metadata to get clean raw values 9 + stripMeta = value: 10 + if builtins.isList value then 11 + map stripMeta value 12 + else if builtins.isAttrs value then 13 + let 14 + # Remove module system special attributes 15 + cleaned = builtins.removeAttrs value [ 16 + "__functor" 17 + "__functionArgs" 18 + "_module" 19 + "config" 20 + ]; 21 + in 22 + lib.mapAttrs (_: stripMeta) cleaned 23 + else 24 + value; 25 + 26 + # Deep merge that concatenates lists instead of overwriting them 27 + deepMergeWith = lhs: rhs: 28 + if builtins.isList lhs && builtins.isList rhs then 29 + lhs ++ rhs 30 + else if builtins.isAttrs lhs && builtins.isAttrs rhs then 31 + let 32 + allKeys = lib.unique (builtins.attrNames lhs ++ builtins.attrNames rhs); 33 + mergedAttrs = builtins.listToAttrs (map (name: { 34 + inherit name; 35 + value = 36 + if lhs ? ${name} && rhs ? ${name} then 37 + deepMergeWith lhs.${name} rhs.${name} 38 + else if lhs ? ${name} then 39 + lhs.${name} 40 + else 41 + rhs.${name}; 42 + }) allKeys); 43 + in 44 + mergedAttrs 45 + else 46 + rhs; 47 + 48 + # Extract denful values, strip metadata, and merge them deeply before passing to module system 49 + deepMerge = builtins.foldl' (acc: x: 50 + deepMergeWith acc (stripMeta (lib.getAttrFromPath [ "denful" name ] x)) 51 + ) { } attrs; 10 52 11 53 sourceModule = { 12 - config.den.ful.${name} = lib.mkMerge denfuls; 54 + config.den.ful.${name} = deepMerge; 13 55 }; 14 56 15 57 aliasModule = lib.mkAliasOptionModule [ name ] [ "den" "ful" name ]; ··· 17 59 outputModule = 18 60 if isOutput then 19 61 { 20 - config.flake.denful.${name} = config.den.ful.${name}; 62 + # Use mkOptionDefault to ensure this assignment has lower priority 63 + # This prevents re-evaluation and duplication issues 64 + config.flake.denful.${name} = lib.mkOptionDefault config.den.ful.${name}; 21 65 } 22 66 else 23 67 { };