Skip to content
This repository was archived by the owner on Apr 30, 2026. It is now read-only.

xinux-org/genemator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

genemator

Nix code generator using rnix/rowan. Build Nix AST programmatically with a closure-based builder API.

Install

# Cargo.toml
[dependencies]
genemator = { git = "https://github.com/xinux-org/genemator" }

Or via CLI:

cargo add --git https://github.com/xinux-org/genemator

Usage

use genemator::NixBuilder;

fn main() {
    let mut b = NixBuilder::new();

    b.attr_set(|b| {
        b.binding("pname", |b| b.string("hello"));
        b.binding("version", |b| b.string("1.0"));
        b.binding("src", |b| b.path("./."));
    });

    // Raw output
    println!("{}", b.finish());
    // { pname = "hello"; version = "1.0"; src = ./.; }

    // Or formatted via nixpkgs-fmt
    // println!("{}", b.format());
}

API

Literals

b.string("hello")       // "hello"
b.int(42)               // 42
b.float(3.14)           // 3.14
b.bool(true)            // true
b.null()                // null
b.path("./src")         // ./src
b.path("/etc/nixos")    // /etc/nixos
b.path("~/config")      // ~/config
b.ident("pkgs")         // pkgs

Attr Sets

b.attr_set(|b| {
    b.binding("foo", |b| b.string("bar"));
    b.binding("nested", |b| {
        b.attr_set(|b| b.binding("x", |b| b.int(1)))
    });
});
// { foo = "bar"; nested = { x = 1; }; }

b.rec_attr_set(|b| {
    b.binding("a", |b| b.int(1));
    b.binding("b", |b| b.ident("a"));
});
// rec { a = 1; b = a; }

Lists

b.list(|b| {
    b.int(1);
    b.ws();
    b.string("two");
    b.ws();
    b.ident("three");
});
// [ 1 "two" three ]

Let-In

b.let_in(
    |b| {
        b.binding("x", |b| b.int(1));
        b.binding("y", |b| b.int(2));
    },
    |b| b.ident("x")
);
// let x = 1; y = 2; in x

Functions

// Lambda
b.lambda("x", |b| b.ident("x"));
// x: x

// Pattern lambda
use genemator::PatternParam;
let params: Vec<PatternParam> = vec![
    ("config", None),
    ("pkgs", None),
];
b.lambda_pattern(&params, |b| b.attr_set(|_| {}));
// { config, pkgs }: { }

// With default
let default: &dyn Fn(&mut NixBuilder) = &|b| b.int(1);
let params: Vec<PatternParam> = vec![("x", Some(default))];
b.lambda_pattern(&params, |b| b.ident("x"));
// { x ? 1 }: x

// Function application
b.apply(|b| b.ident("f"), |b| b.ident("x"));
// f x

b.apply(
    |b| b.ident("f"),
    |b| b.paren(|b| b.apply(|b| b.ident("g"), |b| b.ident("x")))
);
// f (g x)

Control Flow

b.if_then_else(
    |b| b.bool(true),
    |b| b.int(1),
    |b| b.int(2)
);
// if true then 1 else 2

b.with_expr(
    |b| b.ident("pkgs"),
    |b| b.list(|b| {
        b.ident("git");
        b.ws();
        b.ident("vim");
    })
);
// with pkgs; [ git vim ]

Inherit

b.attr_set(|b| {
    b.inherit(&["foo", "bar"]);
});
// { inherit foo bar; }

b.attr_set(|b| {
    b.inherit_from(|b| b.ident("pkgs"), &["git", "vim"]);
});
// { inherit (pkgs) foo bar; }

String Interpolation

b.interpolated_string(|s| {
    s.literal("Hello ");
    s.interpolate(|b| b.ident("name"));
    s.literal("!");
});
// "Hello ${name}!"

Output

// Get SyntaxNode
let node = b.finish();
println!("{}", node);

// Get formatted string via nixpkgs-fmt
let formatted = b.format();

Real-World Examples

Derivation

let mut b = NixBuilder::new();
b.attr_set(|b| {
    b.binding("pname", |b| b.string("myapp"));
    b.binding("version", |b| b.string("1.0.0"));
    b.binding("src", |b| b.path("./."));
    b.binding("buildInputs", |b| {
        b.with_expr(
            |b| b.ident("pkgs"),
            |b| b.list(|b| {
                b.ident("openssl");
                b.ws();
                b.ident("zlib");
            })
        )
    });
});

NixOS Module

let mut b = NixBuilder::new();
let params: Vec<PatternParam> = vec![
    ("config", None),
    ("lib", None),
    ("pkgs", None),
];
b.lambda_pattern(&params, |b| {
    b.attr_set(|b| {
        b.binding("options", |b| b.attr_set(|_| {}));
        b.binding("config", |b| b.attr_set(|_| {}));
    })
});

Flake

let mut b = NixBuilder::new();
b.attr_set(|b| {
    b.binding("description", |b| b.string("My flake"));
    b.binding("inputs", |b| {
        b.attr_set(|b| {
            b.binding("nixpkgs", |b| {
                b.attr_set(|b| {
                    b.binding("url", |b| b.string("github:nixos/nixpkgs/nixos-unstable"));
                })
            });
        })
    });
    b.binding("outputs", |b| {
        b.lambda("inputs", |b| b.attr_set(|_| {}))
    });
});

License

GPL-3.0

About

Nix code generator using rnix/rowan. Build Nix AST programmatically with a closure-based builder API. [maintainer=@shakhzodkudratov]

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Contributors