···77 <a href="LICENSE"> <img src="https://img.shields.io/github/license/vic/flake-aspects" alt="License"/> </a>
88</p>
991010-# `<aspect>.<class>` transposition for Dendritic Nix
1010+# `<aspect>.<class>` Transposition for Dendritic Nix
1111+1212+In [aspect-oriented](https://vic.github.io/dendrix/Dendritic.html) [Dendritic](https://github.com/mightyiam/dendritic) setups, it is common to expose modules using the structure `flake.modules.<class>.<aspect>`.
11131212-On [aspect oriented](https://vic.github.io/dendrix/Dendritic.html) [Dendritic](https://github.com/mightyiam/dendritic) setups, it is common to expose modules using `flake.modules.<class>.<aspect>`.
1313-However, for humans, it might be more intuitive to use a transposed attrset `<aspect>.<class>`. Because it feels more natural to nest classes inside aspects than the other way around.
1414+However, for many users, a transposed attribute set, `<aspect>.<class>`, can be more intuitive. It often feels more natural to nest classes within aspects rather than the other way around.
14151515-This project provides a [`transpose`](default.nix) primitive, small and powerful enough to implement [cross-aspect dependencies](aspects.nix) for *any* nix configuration class, and a [flake-parts module](flakeModule.nix) for turning `flake.aspects` into `flake.modules`.
1616+This project provides a small, dependency-free [`transpose`](default.nix) primitive that is powerful enough to implement [cross-aspect dependencies](aspects.nix) for any Nix configuration class. It also includes a [flake-parts module](flakeModule.nix) that transforms `flake.aspects` into `flake.modules`.
16171718<table>
1819<tr>
···7273</tr>
7374</table>
74757575-## Usage
7676+## Usage ⚙️
76777777-### As a deps-free library from `./default.nix`:
7878+### As a Dependency-Free Library (`./default.nix`) 📚
78797979-Our [`transpose`](default.nix) library takes an optional `emit` function that
8080-can be used to ignore some items, modify them or produce many other items on its place.
8080+The [`transpose`](default.nix) library accepts an optional `emit` function that can be used to ignore items, modify them, or generate multiple items from a single input.
81818282```nix
8383let transpose = import ./default.nix { lib = pkgs.lib; }; in
8484transpose { a.b.c = 1; } # => { b.a.c = 1; }
8585```
86868787-This `emit` function is used by our [`aspects`](aspects.nix) library
8888-(both libs are flakes-independent) to provide cross-aspects same-class module dependencies.
8787+This `emit` function is utilized by the [`aspects`](aspects.nix) library (both libraries are independent of flakes) to manage cross-aspect, same-class module dependencies.
89889090-### As a *Dendritic* flake-parts module that provides the `flake.aspects` option:
8989+### As a Dendritic Flake-Parts Module (`flake.aspects` option) 🧩
91909292-> `flake.aspects` transposes into `flake.modules`.
9191+The `flake.aspects` option is transposed into `flake.modules`.
93929493```nix
9595-# code in this example can (and should) be split into different dendritic modules.
9494+# The code in this example can (and should) be split into different Dendritic modules.
9695{ inputs, ... }: {
9796 imports = [ inputs.flake-aspects.flakeModule ];
9897 flake.aspects = {
999810099 sliding-desktop = {
101101- description = "nextgen tiling windowing";
102102- nixos = { }; # configure Niri on Linux
103103- darwin = { }; # configure Paneru on MacOS
100100+ description = "Next-generation tiling windowing";
101101+ nixos = { }; # Configure Niri on Linux
102102+ darwin = { }; # Configure Paneru on macOS
104103 };
105104106106-107105 awesome-cli = {
108108- description = "enhances environment with best of cli an tui";
109109- nixos = { }; # os services
110110- darwin = { }; # apps like ghostty, iterm2
111111- homeManager = { }; # fish aliases, tuis, etc.
112112- nixvim = { }; # plugins
106106+ description = "Enhances the environment with the best of CLI and TUI";
107107+ nixos = { }; # OS services
108108+ darwin = { }; # Apps like ghostty, iTerm2
109109+ homeManager = { }; # Fish aliases, TUIs, etc.
110110+ nixvim = { }; # Plugins
113111 };
114112115113 work-network = {
116116- description = "work vpn and ssh access.";
117117- nixos = {}; # enable openssh
118118- darwin = {}; # enable MacOS ssh server
119119- terranix = {}; # provision vpn
120120- hjem = {}; # home link .ssh keys and configs.
121121- }
114114+ description = "Work VPN and SSH access";
115115+ nixos = {}; # Enable OpenSSH
116116+ darwin = {}; # Enable macOS SSH server
117117+ terranix = {}; # Provision VPN
118118+ hjem = {}; # Home: link .ssh keys and configs
119119+ };
122120123121 };
124122}
125123```
126124127127-#### Declaring cross-aspect dependencies
125125+#### Declaring Cross-Aspect Dependencies 🔗
128126129129-`flake.aspects` also allow **aspects** to declare dependencies between them.
127127+`flake.aspects` also allows aspects to declare dependencies among themselves.
130128131131-Of course each module can have its own `imports`, however aspect requirements
132132-are aspect-level instead of module-level. Dependencies will ultimately resolve to
133133-modules and get imported only when they exist.
129129+Each module can have its own `imports`, but aspect requirements are defined at the aspect level, not the module level. Dependencies are eventually resolved to modules and are imported only if they exist.
134130135135-In the following example, our `development-server` aspect can be applied into
136136-linux and macos hosts.
137137-Note that `alice` prefers to use `nixos`+`homeManager`, while `bob` likes `darwin`+`hjem`.
131131+In the example below, the `development-server` aspect can be applied to both Linux and macOS hosts. Note that `alice` uses `nixos` + `homeManager`, while `bob` uses `darwin` + `hjem`.
138132139139-The `development-server` aspect is a "_usability concern_", it configures the exact same
140140-development environment on two different OS.
141141-When applied to a NixOS machine, the `alice.nixos` module will likely
142142-configure the alice user, but there is no nixos user for `bob`.
133133+The `development-server` aspect addresses a usability concern by configuring the same development environment on different operating systems. When applied to a NixOS machine, the `alice.nixos` module will likely configure the `alice` user; there is no corresponding NixOS user for `bob`.
143134144135```nix
145136{
146146- flake.aspects = {config, ...}: {
137137+ flake.aspects = { config, ... }: {
147138 development-server = {
148139 requires = with config; [ alice bob ];
149140150150- # without flake-aspects, you'd normally do:
141141+ # Without flake-aspects, you would normally do:
151142 # nixos.imports = [ inputs.self.modules.nixos.alice ];
152143 # darwin.imports = [ inputs.self.modules.darwin.bob ];
153144 };
154145155155- alice = {
146146+ alice = {
156147 nixos = {};
157148 };
158149···163154}
164155```
165156166166-It is out of scope for this library to create OS configurations.
167167-As you might have guessed, exposing configurations would look like this:
157157+Creating OS configurations is outside the scope of this library. Exposing configurations might look like this:
168158169159```nix
170160{ inputs, ... }:
···175165 };
176166177167 flake.darwinConfigurations.fooHost = inputs.darwin.lib.darwinSystem {
178178- system = "aarm64-darwin";
168168+ system = "aarch64-darwin";
179169 modules = [ inputs.self.modules.darwin.development-server ];
180170 };
181171}
182172```
183173184184-#### Advanced aspect dependencies.
174174+#### Advanced Aspect Dependencies 🧭
185175186186-You have already seen that an `aspect` can have a `requires` list:
176176+An aspect can declare a `requires` list:
187177188178```nix
189189-# A foo aspect that depends on aspects bar and baz.
179179+# A 'foo' aspect that depends on 'bar' and 'baz' aspects.
190180flake.aspects = { config, ... }: {
191181 foo.requires = [ config.bar config.baz ];
192182}
193183```
194184195195-cross-aspect requirements work like this:
185185+Cross-aspect requirements work as follows:
196186197197-When a module `flake.modules.nixos.foo` is requested (eg, included in a nixosConfiguration),
198198-a corresponding module will be computed from `flake.aspects.foo.nixos`.
187187+When a module like `flake.modules.nixos.foo` is requested (for example, included in a `nixosConfiguration`), a corresponding module is computed from `flake.aspects.foo.nixos`.
199188200200-`flake.aspects.foo.requires` is a list of functions (**providers**)
201201-that will be called with `{aspect = "foo"; class = "nixos"}` to obtain another aspect
202202-providing a module having the same `class` (`nixos` in our example).
189189+`flake.aspects.foo.requires` is a list of functions (providers) that are called with `{ aspect = "foo"; class = "nixos" }`. These providers return another aspect that provides a module of the same `class` (in this case, `nixos`).
203190204204-_providers_ are a way of asking: if I have a (`foo`, `nixos`) module what other
205205-aspects can you provide that have `nixos` modules to be imported in `foo`.
191191+Providers answer the question: given a (`foo`, `nixos`) module, what other aspects can provide `nixos` modules to be imported into `foo`?
206192207207-> This way, it is aspects *being included* who decide what configuration must
208208-> be used by its caller aspect.
193193+This means that the included aspect determines which configuration its caller should use.
209194210210-by default, all aspects have a `<aspect>.provides.itself` function that ignores its argument
211211-and always returns the `<aspect>` itself.
212212-This is why you can use the `with config; [ bar baz ]` syntax.
213213-They are actually `[ config.bar.provides.itself config.baz.provides.itself ]`.
195195+By default, all aspects include a `<aspect>.provides.itself` function that ignores its argument and returns the `<aspect>` itself. This is why `with config; [ bar baz ]` works: it is shorthand for `[ config.bar.provides.itself config.baz.provides.itself ]`.
214196215215-but you can also define custom providers that can inspect the argument's `aspect` and `class`
216216-and return some set of modules accordingly. you can also use this feature to have aspects that
217217-like as proxy/routers of dependencies.
197197+You can also define custom providers that inspect the `aspect` and `class` arguments and return a set of modules accordingly. This allows aspects to act as proxies or routers for dependencies.
218198219199```nix
220220-flake.aspects.alice.provides.os-user = { aspect, class }:
221221-if someCondition aspect && class == "nixos" then { nixos = { ... }; } else { }
200200+flake.aspects.alice.provides.os-user = { aspect, class }:
201201+ if someCondition aspect && class == "nixos" then { nixos = { ... }; } else { };
222202```
223203224224-the `os-user` provider can be now included in a `requires` list:
204204+The `os-user` provider can then be included in a `requires` list:
225205226206```nix
227227-flake.aspects = {config, ...}: {
207207+flake.aspects = { config, ... }: {
228208 home-server.requires = [ config.alice.provides.os-user ];
229209}
230210```
231211232232-## Testing
212212+## Testing ✅
233213234214```shell
235215nix run ./checkmate#fmt --override-input target .