Types and defaults
yen has no type system of its own. A type is any value with check = value: bool.
lib.types from nixpkgs works, a kind works (see Instances and refs),
and yen.lib.is makes a type from any function.
| Constructor | Default |
|---|---|
lib.types.str, any type | none: the field is required |
yen.lib.opt type value | value |
yen.lib.maybe type | null |
yen.lib.derive type (self: …) | computed from the instance itself |
yen.lib.is (v: …) | none: a type from a check function |
# A type is anything with `check = value: bool`. yen adds defaults on top of it.{ yen, lib, ... }:let inherit (yen.lib) opt maybe derive is ;in{ yen.kinds.host.fields = { addr = lib.types.str; # required port = opt lib.types.port 22; # a default jump = maybe lib.types.str; # null by default vpn = derive lib.types.str (self: "vpn-${self.name}"); # a default computed from the instance tags = opt (is (v: lib.isList v && lib.all lib.isString v)) [ ]; # your own check settings.kernel.channel = opt (lib.types.enum [ "lts" "latest" ]) "lts"; # nested fields };}Fields can nest. settings.kernel.channel is one field at a path, with its own type and default.
An instance gives only what it needs:
{ yen, ... }:{ yen.host.web.addr = "10.0.0.1"; yen.host.db = { addr = "10.0.0.2"; port = 2222; vpn = "vpn-database"; # an explicit value wins over `derive` settings.kernel.channel = "latest"; };}The read of a field looks at the instance first, then at the default, then checks the value:
{ db = { channel = "latest"; jump = null; port = 2222; tags = [ ]; vpn = "vpn-database"; }; web = { channel = "lts"; jump = null; port = 22; tags = [ ]; vpn = "vpn-web"; };}