690994a28c
Previously, for types defined using typedef (like all primitive types) type.checkType would return a boolean. This is largely fine since in most places `type.checkToBool (type.checkType x)` or similar is used. However, some functions actually take type.checkType up on the promise that it returns a set of the form: { ok = <bool>; err = <option string>; } This is the case for restrict which has checkToBool = v: v.ok; and will generate a proper set except if `t.checkToBool (t.checkType v) == false` in which case it will return t.checkType v. If t was a primitive type or defined using typedef, previously `t.checkType v` would be a boolean which meant as soon as (restrict …).checkToBool was called on a restrict checkType result in cases where the wrapped type didn't match, an unrelated error would be thrown: nix-repl> with nix.yants; restrict "foo" (_: true) int "lol" error: value is a boolean while a set was expected, at /home/lukas/src/depot/nix/yants/default.nix:38:39 This is fixed by making typedef return a proper set from checkType and adjusting its checkToBool accordingly. Unfortunately I don't think we can easily add test cases for this except by using recursive nix or VM tests as there is no way to introspect error messages. Change-Id: I96a7be065630f04ca33358f21809284911ec14fe Reviewed-on: https://cl.tvl.fyi/c/depot/+/2536 Tested-by: BuildkiteCI Reviewed-by: tazjin <mail@tazj.in> Reviewed-by: Profpatsch <mail@profpatsch.de> |
||
---|---|---|
.. | ||
screenshots | ||
tests | ||
default.nix | ||
README.md |
yants
This is a tiny type-checker for data in Nix, written in Nix.
Features
- Checking of primitive types (
int
,string
etc.) - Checking polymorphic types (
option
,list
,either
) - Defining & checking struct/record types
- Defining & matching enum types
- Defining & matching sum types
- Defining function signatures (including curried functions)
- Types are composable!
option string
!list (either int (option float))
! - Type errors also compose!
Currently lacking:
- Any kind of inference
- Convenient syntax for attribute-set function signatures
Primitives & simple polymorphism
Structs
Nested structs!
Enums!
Functions!
Usage
Yants can be imported from its default.nix
. A single attribute (lib
) can be
passed, which will otherwise be imported from <nixpkgs>
.
TIP: You do not need to clone my whole repository to use Yants! It is split out
into the nix/yants
branch which you can clone with, for example, git clone -b nix/yants https://git.tazj.in yants
.
Examples for the most common import methods would be:
-
Import into scope with
with
:with (import ./default.nix {}); # ... Nix code that uses yants ...
-
Import as a named variable:
let yants = import ./default.nix {}; in yants.string "foo" # or other uses ...
-
Overlay into
pkgs.lib
:# wherever you import your package set (e.g. from <nixpkgs>): import <nixpkgs> { overlays = [ (self: super: { lib = super.lib // { yants = import ./default.nix { inherit (super) lib; }; }; }) ]; } # yants now lives at lib.yants, besides the other library functions!
Please see my Nix one-pager for more generic information about the Nix language and what the above constructs mean.
Stability
The current API of Yants is not yet considered stable, but it works fine and should continue to do so even if used at an older version.
Yants' tests use Nix versions above 2.2 - compatibility with older versions is not guaranteed.