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
1{
2 inputs,
3 lib,
4 config,
5 ...
6}:
7let
8 inherit (config) den;
9
10 # "Just Give 'Em One of These" - Moe Szyslak
11 # A __functor that applies context to parametric includes (functions)
12 funk =
13 apply: aspect:
14 aspect
15 // {
16 __functor = self: ctx: {
17 includes = builtins.filter (x: x != { }) (
18 map (apply ctx) (builtins.filter isFn (self.includes or [ ]))
19 );
20 };
21 };
22
23 isFn = f: (builtins.isFunction f) || (builtins.isAttrs f && f ? __functor);
24 canTake = import ./fn-can-take.nix lib;
25
26 # an aspect producing only owned configs
27 owned = (lib.flip builtins.removeAttrs) [
28 "includes"
29 "__functor"
30 ];
31
32 # only static includes from an aspect.
33 statics =
34 aspect:
35 aspect
36 // {
37 __functor =
38 self:
39 { class, aspect-chain }:
40 {
41 includes = map (applyStatics { inherit class aspect-chain; }) (self.includes or [ ]);
42 };
43 };
44
45 applyStatics =
46 ctx: f:
47 if !isFn f then
48 f
49 else if isStatic f && isCtxStatic ctx then
50 f ctx
51 else
52 { };
53
54 isStatic = canTake.atLeast {
55 class = "";
56 aspect-chain = [ ];
57 };
58 isCtxStatic = (lib.flip canTake.exactly) ({ class, aspect-chain }: class aspect-chain);
59
60 take.unused = _unused: used: used;
61 take.exactly = take canTake.exactly;
62 take.atLeast = take canTake.atLeast;
63 take.__functor =
64 _: takes: fn: ctx:
65 if takes ctx fn then fn ctx else { };
66
67 parametric.atLeast = funk (lib.flip take.atLeast);
68 parametric.exactly = funk (lib.flip take.exactly);
69 parametric.expands =
70 attrs: parametric.withOwn (aspect: ctx: parametric.atLeast aspect (ctx // attrs));
71 parametric.fixedTo =
72 attrs: aspect:
73 aspect
74 // {
75 __functor =
76 self:
77 { class, aspect-chain }:
78 {
79 includes = [
80 (owned self)
81 (statics self { inherit class aspect-chain; })
82 (parametric.atLeast self attrs)
83 ];
84 };
85 };
86 parametric.withOwn =
87 functor: aspect:
88 aspect
89 // {
90 __functor = self: ctx: {
91 includes =
92 if isCtxStatic ctx then
93 [
94 (owned self)
95 (statics self ctx)
96 ]
97 else
98 [ (functor self ctx) ];
99 };
100 };
101 parametric.__functor = _: parametric.withOwn parametric.atLeast;
102
103 aspects = inputs.flake-aspects.lib lib;
104
105 __findFile = import ./den-brackets.nix { inherit lib config; };
106
107 nh = import ./nh.nix {
108 inherit
109 lib
110 config
111 den
112 inputs
113 ;
114 };
115
116 ctxApply = import ./ctx-apply.nix { inherit lib den; };
117
118 home-env = import ./home-env.nix { inherit lib den inputs; };
119
120 nixModule = import ./nixModule {
121 inherit
122 lib
123 inputs
124 config
125 den-lib
126 ;
127 };
128
129 den-lib = {
130 inherit
131 parametric
132 aspects
133 __findFile
134 statics
135 owned
136 isFn
137 canTake
138 take
139 isStatic
140 ctxApply
141 nh
142 home-env
143 nixModule
144 ;
145 };
146in
147den-lib