Skip to content
Merged

docs #35

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: GH Pages
on:
workflow_dispatch:
push:
branches: [main]
paths: ["docs/**"]
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 10
- name: Build
run: |
pushd docs
pnpm install
pnpm run build
popd
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: "./docs/dist"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
212 changes: 28 additions & 184 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<!-- Badges -->

<p align="right">
<a href="https://github.com/sponsors/vic"><img src="https://img.shields.io/badge/sponsor-vic-white?logo=githubsponsors&logoColor=white&labelColor=%23FF0000" alt="Sponsor Vic"/>
<a href="https://dendritic.oeiuwq.com/sponsor"><img src="https://img.shields.io/badge/sponsor-vic-white?logo=githubsponsors&logoColor=white&labelColor=%23FF0000" alt="Sponsor Vic"/>
</a>
<a href="https://vic.github.io/dendrix/Dendritic-Ecosystem.html#vics-dendritic-libraries"> <img src="https://img.shields.io/badge/Dendritic-Nix-informational?logo=nixos&logoColor=white" alt="Dendritic Nix"/> </a>
<a href="https://dendritic.oeiuwq.com"> <img src="https://img.shields.io/badge/Dendritic-Nix-informational?logo=nixos&logoColor=white" alt="Dendritic Nix"/> </a>
<a href="https://github.com/vic/flake-aspects/actions">
<img src="https://github.com/vic/flake-aspects/actions/workflows/test.yml/badge.svg" alt="CI Status"/> </a>
<a href="LICENSE"> <img src="https://img.shields.io/github/license/vic/flake-aspects" alt="License"/> </a>
</p>

# `<aspect>.<class>` Transposition for Dendritic Nix

> `flake-aspects` and [vic](https://bsky.app/profile/oeiuwq.bsky.social)'s [dendritic libs](https://vic.github.io/dendrix/Dendritic-Ecosystem.html#vics-dendritic-libraries) made for you with Love++ and AI--. If you like my work, consider [sponsoring](https://github.com/sponsors/vic)
> `flake-aspects` and [vic](https://bsky.app/profile/oeiuwq.bsky.social)'s [dendritic libs](https://dendritic.oeiuwq.com) made for you with Love++ and AI--. If you like my work, consider [sponsoring](https://dendritic.oeiuwq.com/sponsor)

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>`.
In [aspect-oriented](https://den.oeiuwq.com) [Dendritic](https://github.com/mightyiam/dendritic) setups, it is common to expose modules using the structure `flake.modules.<class>.<aspect>`.

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.

Expand Down Expand Up @@ -77,198 +77,42 @@ This project provides a small, dependency-free [`transpose`](nix/default.nix) pr
</tr>
</table>

Unlike `flake.modules.<class>.<aspect>` which is _flat_, aspects can be nested forming a _tree_ by using the `provides` (short alias: `_`) attribute. Each aspect can also specify a list of `includes` of other aspects, forming a _graph_ of dependencies.
Unlike `flake.modules.<class>.<aspect>` which is _flat_, aspects form a _tree_ via `provides` (alias: `_`) and a _graph_ via `includes`.

---

## Usage

### As a `flake-parts` Module
## Quick Start

```nix
{ inputs, ... }: {
imports = [ inputs.flake-aspects.flakeModule ];
flake.aspects = {
sliding-desktop = {
nixos = { }; # Niri on Linux
darwin = { }; # Paneru on macOS
};
awesome-cli = {
nixos = { }; darwin = { }; homeManager = { }; nixvim = { };
# flake.nix
{
inputs.flake-aspects.url = "github:vic/flake-aspects";
outputs = { flake-parts, flake-aspects, nixpkgs, ... }@inputs:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [ flake-aspects.flakeModule ];
flake.aspects = { aspects, ... }: {
my-desktop = {
nixos = { };
darwin = { };
includes = [ aspects.my-tools ];
};
my-tools.nixos = { };
};
};
};
flake.nixosConfigurations.my-host = inputs.nixpkgs.lib.nixosSystem {
modules = [
inputs.self.modules.nixos.sliding-desktop # read resolved module
];
};
}
```

### Without Flakes ([test](checkmate/modules/tests/without_flakes.nix))

```nix
let

myModules = (lib.evalModules {
modules = [
(new-scope "my") # creates my.aspects and my.modules.
{ my.aspects.laptop.nixos = ...; }
];
}).config.my.modules;

in lib.nixosSystem { modules = [ myModules.nixos.laptop ]; };
```

Useful for libraries that want isolated aspect scopes or flake-parts independence (see [`den`'s scope](https://github.com/vic/den/blob/main/nix/scope.nix)).

---

## API ([nix/lib.nix](nix/lib.nix))

| Export | Description |
| --------------------- | ----------------------------------------------------------- |
| `transpose { emit? }` | Generic 2-level transposition |
| `types` | Nix type system for aspects and providers |
| `aspects` | Aspect-aware transposition with resolution |
| `new` | Low-level scope factory (callback-based) |
| `new-scope` | Named scope factory (`${name}.aspects` / `${name}.modules`) |
| `forward` | Cross-class module forwarding |

### Core: `transpose` ([nix/default.nix](nix/default.nix))

Generic 2-level attribute set transposition parameterized by an `emit` function.

```nix
transpose { a.b.c = 1; } # ⇒ { b.a.c = 1; }
```

`emit` receives `{ child, parent, value }` and returns a list of `{ parent, child, value }` items. Default: `lib.singleton` (identity). This allows users to filter, modify or multiply items being transposed. This is exploited by [nix/aspects.nix](nix/aspects.nix) to intercept each transposition and inject [resolution](nix/resolve.nix).

Tests: [transpose_swap](checkmate/modules/tests/transpose_swap.nix), [transpose_common](checkmate/modules/tests/transpose_common.nix), [tranpose_flake_modules](checkmate/modules/tests/tranpose_flake_modules.nix).

### Resolution: `resolve` ([nix/resolve.nix](nix/resolve.nix))

Recursive dependency resolver. Given a `class` and an `aspect-chain` (the call stack of aspects that led here -- most recent last), it extracts the class-specific config and recursively resolves all `includes`.

The `aspect-chain` lets providers know who is including them and make decisions based on call context. Tests: [aspect_chain](checkmate/modules/tests/aspect_chain.nix), [aspect_modules_resolved](checkmate/modules/tests/aspect_modules_resolved.nix).

### Scope Factories ([nix/new.nix](nix/new.nix), [nix/new-scope.nix](nix/new-scope.nix))

`new` is a callback-based factory: `new (option: transposed: moduleDefinition) aspectsConfig`. The [flakeModule](nix/flakeModule.nix) uses it to wire `flake.aspects → flake.modules`.

`new-scope` wraps `new` to create named scopes: `new-scope "foo"` produces `foo.aspects` (input) and `foo.modules` (output). Multiple independent namespaces can coexist. Tests: [without_flakes](checkmate/modules/tests/without_flakes.nix), [aspect_assignment](checkmate/modules/tests/aspect_assignment.nix).

### Forward ([nix/forward.nix](nix/forward.nix))

Cross-class configuration forwarding. Routes resolved modules from one class into a submodule path of another class. Used by [`den`](https://github.com/vic/den) to forward `homeManager` modules into `nixos.home-manager.users.<name>`. Test: [forward](checkmate/modules/tests/forward.nix).

---

## Dependency Resolution

### `includes` — Cross-Aspect Dependencies ([test](checkmate/modules/tests/aspect_dependencies.nix))

```nix
flake.aspects = { aspects, ... }: {
server = {
includes = with aspects; [ networking monitoring ];
nixos = { };
};
networking.nixos = { };
monitoring.nixos = { };
};
```
Also works [without flakes](checkmate/modules/tests/without_flakes.nix) via `new-scope` and `lib.evalModules`.

When `flake.modules.nixos.server` is evaluated, it resolves to `{ imports = [ server.nixos, networking.nixos, monitoring.nixos ] }`. Only classes that exist on the included aspect are imported.
## Documentation

### Providers — `provides` / `_` ([test](checkmate/modules/tests/aspect_provides.nix))
**[Full documentation](https://flake-aspects.oeiuwq.com)**

Aspects can expose sub-aspects as providers. `_` is an alias for `provides`.

```nix
flake.aspects = { aspects, ... }: {
gaming = {
nixos = { };
_.emulation = {
nixos = { };
_.nes.nixos = { };
};
};
my-host.includes = [ aspects.gaming._.emulation._.nes ];
};
```

Providers receive `{ class, aspect-chain }` and can use them for conditional logic or context-aware configuration. The `aspect-chain` tracks the full inclusion path.

### Fixpoint Semantics ([test](checkmate/modules/tests/aspect_fixpoint.nix))

The top-level `aspects` argument is a fixpoint: providers at any depth can reference siblings or top-level aspects.

```nix
flake.aspects = { aspects, ... }: {
two.provides = { aspects, ... }: {
sub = { includes = [ aspects.sibling ]; classOne = { }; };
sibling.classOne = { };
};
one.includes = [ aspects.two._.sub ];
};
```

### Parametric Providers ([test](checkmate/modules/tests/aspect_parametric.nix))

Curried functions act as parametric providers:

```nix
flake.aspects = { aspects, ... }: {
base._.user = userName: {
nixos.users.${userName}.isNormalUser = true;
};
server.includes = [ (aspects.base._.user "bob") ];
};
```

### Top-Level Parametric Aspects ([test](checkmate/modules/tests/aspect_toplevel_parametric.nix))

Top-level aspects can also be curried providers:

```nix
flake.aspects = { aspects, ... }: {
greeter = { message }: { nixos.greeting = message; };
host.includes = [ (aspects.greeter { message = "hello"; }) ];
};
```

### `__functor` Override ([test](checkmate/modules/tests/aspect_default_provider_functor.nix), [test](checkmate/modules/tests/aspect_default_provider_override.nix))

The default `__functor` just returns the aspect itself. However, you can override the `__functor` to allow an aspect to intercept when it is being included and provide different config depending on who is including it.

```nix
flake.aspects = { aspects, ... }: {
foo = {
nixos = { ... };
__functor = self:
{ class, aspect-chain }:
if class == "nixos" then self else { darwin = ...; includes = [ ... ]; };
};
};
```

### Forward ([nix/forward.nix](nix/forward.nix)) ([test](checkmate/modules/tests/forward.nix))

Route modules from one class into a submodule path of another:

```nix
forward {
each = host.users;
fromClass = _user: "homeManager";
intoClass = _user: "nixos";
intoPath = user: [ "home-manager" "users" user.name ];
fromAspect = user: den.aspects.${user.name};
}
```

---
| Section | Content |
| ------------------------------------------------------------------- | ------------------------------------------------------------------- |
| [Concepts](https://vic.github.io/flake-aspects/concepts/transpose/) | Transpose, resolution algorithm, providers & fixpoint |
| [Guides](https://vic.github.io/flake-aspects/guides/flake-parts/) | flake-parts, standalone, dependencies, parametric, functor, forward |
| [Reference](https://vic.github.io/flake-aspects/reference/api/) | API exports, type system, test suite |

## Testing

Expand Down
1 change: 1 addition & 0 deletions checkmate/modules/formatter.nix
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
perSystem.treefmt.programs.nixf-diagnose.enable = false;
perSystem.treefmt.settings.global.excludes = [ "docs/*" ];
}
21 changes: 21 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/

# dependencies
node_modules/

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*


# environment variables
.env
.env.production

# macOS-specific files
.DS_Store
4 changes: 4 additions & 0 deletions docs/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}
11 changes: 11 additions & 0 deletions docs/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}
49 changes: 49 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Starlight Starter Kit: Basics

[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)

```
pnpm create astro@latest -- --template starlight
```

> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!

## 🚀 Project Structure

Inside of your Astro + Starlight project, you'll see the following folders and files:

```
.
├── public/
├── src/
│ ├── assets/
│ ├── content/
│ │ └── docs/
│ └── content.config.ts
├── astro.config.mjs
├── package.json
└── tsconfig.json
```

Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.

Images can be added to `src/assets/` and embedded in Markdown with a relative link.

Static assets, like favicons, can be placed in the `public/` directory.

## 🧞 Commands

All commands are run from the root of the project, from a terminal:

| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `pnpm install` | Installs dependencies |
| `pnpm dev` | Starts local dev server at `localhost:4321` |
| `pnpm build` | Build your production site to `./dist/` |
| `pnpm preview` | Preview your build locally, before deploying |
| `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` |
| `pnpm astro -- --help` | Get help using the Astro CLI |

## 👀 Want to learn more?

Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
Loading