jinx Nix, transpiled to TypeScript

Usage

Run it

$ nix run github:fzakaria/jinx -- eval ./default.nix
$ nix run github:fzakaria/jinx -- eval "$(nix eval --raw nixpkgs#path)" -A hello.drvPath

jinx eval compiles the files an evaluation reaches into a cache under ~/.cache/jinx and runs them. There is no search path: nixpkgs is named by its path. The commands:

command what it does
jinx eval <file> [-A attr] [--json] evaluate a file, like nix-instantiate --eval --strict; --arg and --argstr as there
jinx compile <dir> --out <tree> compile every .nix file under a directory into a TypeScript tree
jinx eval <file> --tree <tree> evaluate against a compiled tree instead of the cache
jinx instantiate <file> [-A attr] write the .drv closure to the store, for nix-store --realise
jinx eval-jobs <file> [--workers N] every attribute of a set, one JSON line each, like nix-eval-jobs

--impure reads the environment and the current system as nix-instantiate does; without it, evaluation is pure.

In a flake

{
  inputs.jinx.url = "github:fzakaria/jinx";

  outputs = { self, nixpkgs, jinx }: {
    devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
      packages = [ jinx.packages.x86_64-linux.jinx ];
    };
  };
}

jinx.packages.<system>.jinx is the command; nix develop then has jinx on PATH.

A NixOS configuration

A system closure evaluates like any other attribute. jinx has no search path, so nixpkgs is named by path:

$ nixpkgs=$(nix eval --raw nixpkgs#path)
$ jinx eval $nixpkgs/nixos --arg configuration ./configuration.nix \
    -A config.system.build.toplevel.drvPath
$ jinx instantiate $nixpkgs/nixos --arg configuration ./configuration.nix \
    -A config.system.build.toplevel
$ nix-store --realise /nix/store/...-nixos-system-....drv

The drvPath is the one nix-instantiate computes, so the store builds what jinx wrote.

The same system from TypeScript (examples/nixos.ts): a module is a function of the module arguments, and its body is an object. A read of pkgs waits in lazy until the option is read, as it does in Nix.

import { lazy, load } from "jinx";

const configuration = ({ pkgs }) => ({
  fileSystems: { "/": { device: "/dev/sda1", fsType: "ext4" } },
  boot: { loader: { grub: { device: "/dev/sda" } } },
  networking: { hostName: "jinx", firewall: { allowedTCPPorts: [22, 80] } },
  services: { openssh: { enable: true } },
  environment: { systemPackages: lazy(() => [pkgs.git, pkgs.ripgrep]) },
  users: { users: { farid: { isNormalUser: true, extraGroups: ["wheel"] } } },
  system: { stateVersion: "25.11" },
});

const nixos = load("/path/to/nixpkgs/nixos", { args: { configuration } });
console.log(nixos.config.system.build.toplevel.drvPath);

From TypeScript

The library in src/lib evaluates Nix and gives it back as a view: attribute reads force, calls apply, and plain objects, arrays, strings and numbers pass as arguments.

import { loadNixpkgs } from "jinx";

const pkgs = loadNixpkgs("/path/to/nixpkgs", { system: "x86_64-linux" });

const hello = pkgs.stdenv.mkDerivation({
  pname: "hello",
  version: "2.12.2",
  src: pkgs.fetchurl({
    url: "mirror://gnu/hello/hello-2.12.2.tar.gz",
    hash: "sha256-WpqZbcKSzCTc9BHO6H6S9qrluNE72caBm0x6nc4IGKs=",
  }),
});

console.log(hello.drvPath);
export what it is
loadNixpkgs(dir, opts) nixpkgs as a view, with system, config and overlays filled in
load(file, opts) any Nix file as a view; opts.args is applied if it is a function
nix the builtins as a view: nix.derivation({...}), nix.toJSON(...)
lazy(() => v) an attribute evaluated when something reads it
path(base, rel) a Nix path value
Derivation the type of a viewed derivation: name, drvPath, outPath, outputs
show(v) a value printed as nix-instantiate --eval prints it

opts.tree points at a compiled tree, opts.cache at another cache directory, opts.system sets builtins.currentSystem.

examples/hello.ts is the package above; examples/nixos.ts evaluates a NixOS configuration written as an object. Typed views of a package set, so pkgs. completes and a misspelled attribute is a type error, come from tools/gen-nixpkgs-dts.ts (examples/typed-hello.ts).

In the browser

The playground compiles and evaluates a snippet in the tab; <nixpkgs> there is the compiled nixpkgs, fetched as the evaluation needs it, so a package or a NixOS system evaluates in the page. The nixpkgs page evaluates attributes of the same tree. nix run github:fzakaria/jinx#serve serves the same site from the store, the compiled nixpkgs included, with no network.

Edit this page on GitHub