Skip to content

Commit

Permalink
formats.kdl: init
Browse files Browse the repository at this point in the history
  • Loading branch information
feathecutie committed Aug 1, 2024
1 parent 3033fd9 commit c882b47
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 0 deletions.
61 changes: 61 additions & 0 deletions nixos/doc/manual/development/settings-options.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,67 @@ have a predefined type and string generator already declared under
and returning a set with TOML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).

`pkgs.formats.kdl` { }

: A function taking an empty attribute set (for future extensibility)
and returning a set with [KDL](https://kdl.dev/)-specific attributes `type`,
`lib` and `generate` as specified [below](#pkgs-formats-result).

`lib` is a set containing the functions `node` and `typed`, which are helper
functions indended to facilitate generating the required structure for pkgs.formats.kdl
in an ergonomic way.

Their signatures are as follows:

`node`:

```nix
name: type: arguments: properties: children: { inherit name type arguments properties children; };
```

`typed`:

```nix
type: value: { inherit type value; };
```

This allows writing the KDL node

```kdl
name "arg1" (special-type)"arg2" prop=1 {
child
}
```

as

```nix
(node "name" null [ "arg1" (typed "special-type" "arg2") ] { prop = 1; } [
(node "child" null [ ] { } [ ])
])
```

instead of

```nix
{
name = "name";
arguments = [
"arg1"
{
type = "special-type";
value = "arg2";
}
];
properties = { prop = 1; };
children = [
{
name = "child";
}
];
}
```

`pkgs.formats.elixirConf { elixir ? pkgs.elixir }`

: A function taking an attribute set with values
Expand Down
134 changes: 134 additions & 0 deletions pkgs/pkgs-lib/formats.nix
Original file line number Diff line number Diff line change
Expand Up @@ -513,4 +513,138 @@ rec {
'') {};
};

# The KDL document language (https://kdl.dev/)
kdl = {}: {

type = (with lib.types; let
# https://github.com/kdl-org/kdl/blob/main/SPEC.md#value
untypedKdlValue = (nullOr (oneOf [ str bool number ])) // { description = "KDL value"; };
kdlValue = either untypedKdlValue ((submodule {
options = {
type = lib.mkOption {
type = nullOr str;
default = null;
description = ''
[Type Annotation](https://github.com/kdl-org/kdl/blob/main/SPEC.md#type-annotation) of the value.
Set to `null` to prevent generating a type annotation.
'';
};
value = lib.mkOption {
type = untypedKdlValue;
description = ''
The actual KDL value.
'';
};
};
}) // { description = "submodule: { type = /* type annotation */; value = /* KDL value */; }"; });
node = submoduleWith {
modules = lib.toList {
options = {
name = lib.mkOption {
type = str;
description = ''
Name of [KDL node](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node).
'';
};
type = lib.mkOption {
type = nullOr str;
default = null;
description = ''
[Type Annotation](https://github.com/kdl-org/kdl/blob/main/SPEC.md#type-annotation) of [KDL node](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node).
Set to `null` to prevent generating a type annotation.
'';
};
arguments = lib.mkOption {
type = listOf kdlValue;
default = [ ];
description = ''
[Arguments](https://github.com/kdl-org/kdl/blob/main/SPEC.md#argument) of [KDL node](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node).
'';
};
properties = lib.mkOption {
type = attrsOf kdlValue;
default = { };
description = ''
[Properties](https://github.com/kdl-org/kdl/blob/main/SPEC.md#property) of [KDL node](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node).
'';
};
children = lib.mkOption {
type = listOf (node // {
# Prevent Nix from trying to recurse into suboptions or submodules, as this leads to a stack overflow
getSubOptions = prefix: {};
getSubModules = null;
});
default = [ ];
description = ''
[Children](https://github.com/kdl-org/kdl/blob/main/SPEC.md#children-block) of [KDL node](https://github.com/kdl-org/kdl/blob/main/SPEC.md#node).
'';
};
};
};
description = "KDL node";
};
valueType = listOf node;
in
valueType);

lib = {
/**
Helper function for generating attrsets expect by pkgs.formats.kdl
# Example
```nix
let
settingsFormat = pkgs.formats.kdl { };
inherit (settingsFormat.lib) node;
in
settingsFormat.generate "sample.kdl" [
(node "foo" null [ ] { } [
(node "bar" null [ "baz" ] { a = 1; } [ ])
])
]
```
# Arguments
name
: The name of the node, represented by a string
type
: The type annotation of the node, represented by a string, or null to avoid generating a type annotation
arguments
: The arguments of the node, represented as a list of KDL values
properties
: The properties of the node, represented as an attrset of KDL values
children
: The children of the node, represented as a list of nodes
*/
node = name: type: arguments: properties: children: { inherit name type arguments properties children; };

/**
Helper function for generting the format of a typed value as expected by pkgs.formats.kdl
type
: The type of the value, represented by a string
value
: The value itself
*/
typed = type: value: { inherit type value; };
};

generate = name: value: pkgs.callPackage ({ runCommand, json2kdl }: runCommand name {
nativeBuildInputs = [ json2kdl ];
value = builtins.toJSON value;
passAsFile = [ "value" ];
} ''
json2kdl "$valuePath" "$out"
'') {};

};

}

0 comments on commit c882b47

Please sign in to comment.