fake.modules transposition for aspect-oriented Dendritic Nix. with cross-aspect dependencies. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ dendrix.oeiuwq.com/Dendritic.html
dendritic nix aspect oriented

providers type checks for class or aspect-chain args

+14 -16
+4 -4
README.md
··· 222 223 #### Parameterized Providers 224 225 - Providers can be implemented as curried functions, allowing you to create parameterized modules. All arguments must be explicitly named. This is useful for creating reusable configurations that can be customized at the inclusion site. 226 227 - For a real-world example, see how `vic/den` [defines](https://github.com/vic/den/blob/main/nix/aspects.nix) `flake.aspects.default.host` and its [usage](https://github.com/vic/den/blob/main/templates/default/modules/_example/aspects.nix). 228 229 ```nix 230 flake.aspects = { aspects, ... }: { 231 system = { 232 nixos.system.stateVersion = "25.11"; 233 - provides.user = { userName }: { aspect-chain, class }: { 234 darwin.system.primaryUser = userName; 235 nixos.users.${userName}.isNormalUser = true; 236 }; ··· 238 239 home-server.includes = [ 240 aspects.system 241 - (aspects.system.provides.user { userName = "bob"; }) 242 ]; 243 } 244 ```
··· 222 223 #### Parameterized Providers 224 225 + Providers can be implemented as curried functions, allowing you to create parameterized modules. This is useful for creating reusable configurations that can be customized at the inclusion site. 226 227 + For real-world examples, see how `vic/den` defines [auto-imports](https://github.com/vic/den/blob/main/modules/aspects/batteries/import-tree.nix) and [home-managed](https://github.com/vic/den/blob/main/modules/aspects/batteries/home-managed.nix) parametric aspects. 228 229 ```nix 230 flake.aspects = { aspects, ... }: { 231 system = { 232 nixos.system.stateVersion = "25.11"; 233 + provides.user = userName: { 234 darwin.system.primaryUser = userName; 235 nixos.users.${userName}.isNormalUser = true; 236 }; ··· 238 239 home-server.includes = [ 240 aspects.system 241 + (aspects.system.provides.user "bob") 242 ]; 243 } 244 ```
+6 -8
checkmate.nix
··· 303 provides = 304 { provides, ... }: 305 { 306 - three-and-four-and-five = _: { 307 classOne.bar = [ "3" ]; 308 includes = [ 309 provides.four 310 aspects.five 311 ]; 312 }; 313 - four = _: { 314 classOne.bar = [ "4" ]; 315 }; 316 }; ··· 339 flake.aspects = 340 { aspects, ... }: 341 { 342 - aspectOne.includes = [ (aspects.aspectTwo.provides.hello { world = "mundo"; }) ]; 343 aspectOne.classOne.bar = [ "1" ]; 344 345 - aspectTwo.provides.hello = 346 - { world }: # args must always be named. 347 - _: { 348 - classOne.bar = [ world ]; 349 - }; 350 }; 351 }; 352
··· 303 provides = 304 { provides, ... }: 305 { 306 + three-and-four-and-five = { 307 classOne.bar = [ "3" ]; 308 includes = [ 309 provides.four 310 aspects.five 311 ]; 312 }; 313 + four = { 314 classOne.bar = [ "4" ]; 315 }; 316 }; ··· 339 flake.aspects = 340 { aspects, ... }: 341 { 342 + aspectOne.includes = [ (aspects.aspectTwo.provides.hello "mundo") ]; 343 aspectOne.classOne.bar = [ "1" ]; 344 345 + aspectTwo.provides.hello = world: { 346 + classOne.bar = [ world ]; 347 + }; 348 }; 349 }; 350
+4 -4
nix/types.nix
··· 15 # { class, aspect-chain } => aspect-object 16 # { class, ... } => aspect-object 17 # { aspect-chain, ... } => aspect-object 18 - # name => aspect-object 19 functionToAspect = lib.types.addCheck (lib.types.functionTo aspectSubmodule) ( 20 f: 21 let 22 args = lib.functionArgs f; 23 arity = lib.length (lib.attrNames args); 24 - isEmpty = arity == 0; 25 hasClass = args ? class; 26 hasChain = args ? aspect-chain; 27 classOnly = hasClass && arity == 1; 28 chainOnly = hasChain && arity == 1; 29 both = hasClass && hasChain && arity == 2; 30 in 31 - isEmpty || classOnly || chainOnly || both 32 ); 33 34 functionProviderType = lib.types.either functionToAspect (lib.types.functionTo providerType); ··· 72 readOnly = true; 73 description = "Provides itself"; 74 type = providerType; 75 - default = _: aspect; 76 }; 77 } 78 );
··· 15 # { class, aspect-chain } => aspect-object 16 # { class, ... } => aspect-object 17 # { aspect-chain, ... } => aspect-object 18 functionToAspect = lib.types.addCheck (lib.types.functionTo aspectSubmodule) ( 19 f: 20 let 21 args = lib.functionArgs f; 22 arity = lib.length (lib.attrNames args); 23 hasClass = args ? class; 24 hasChain = args ? aspect-chain; 25 classOnly = hasClass && arity == 1; 26 chainOnly = hasChain && arity == 1; 27 both = hasClass && hasChain && arity == 2; 28 in 29 + classOnly || chainOnly || both 30 ); 31 32 functionProviderType = lib.types.either functionToAspect (lib.types.functionTo providerType); ··· 70 readOnly = true; 71 description = "Provides itself"; 72 type = providerType; 73 + default = 74 + # deadnix: skip 75 + { class, ... }: aspect; 76 }; 77 } 78 );