lib/types: add types json from pkgs.formats (#470842)
This commit is contained in:
+24
-4
@@ -58,12 +58,19 @@ logFailure() {
|
||||
evalConfig() {
|
||||
local attr=$1
|
||||
shift
|
||||
local script="import ./default.nix { modules = [ $* ];}"
|
||||
|
||||
local nix_args=()
|
||||
|
||||
if [ "${ABORT_ON_WARN-0}" = "1" ]; then
|
||||
local-nix-instantiate --option abort-on-warn true -E "$script" -A "$attr"
|
||||
else
|
||||
local-nix-instantiate -E "$script" -A "$attr"
|
||||
nix_args+=(--option abort-on-warn true)
|
||||
fi
|
||||
|
||||
if [ "${STRICT_EVAL-0}" = "1" ]; then
|
||||
nix_args+=(--strict)
|
||||
fi
|
||||
|
||||
local script="import ./default.nix { modules = [ $* ];}"
|
||||
local-nix-instantiate "${nix_args[@]}" -E "$script" -A "$attr"
|
||||
}
|
||||
|
||||
reportFailure() {
|
||||
@@ -247,6 +254,19 @@ checkConfigError 'A definition for option .* is not of type .fileset.. Definitio
|
||||
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err3 ./fileset.nix
|
||||
checkConfigError 'A definition for option .* is not of type .fileset.. Definition values:\n.*' config.filesetCardinal.err4 ./fileset.nix
|
||||
|
||||
# types.serializableValueWith
|
||||
checkConfigOutput '^null$' config.nullableValue.null ./types.nix
|
||||
checkConfigOutput '^true$' config.nullableValue.bool ./types.nix
|
||||
checkConfigOutput '^1$' config.nullableValue.int ./types.nix
|
||||
checkConfigOutput '^1.1$' config.nullableValue.float ./types.nix
|
||||
checkConfigOutput '^"foo"$' config.nullableValue.str ./types.nix
|
||||
checkConfigOutput '^".*/store.*"$' config.nullableValue.path ./types.nix
|
||||
STRICT_EVAL=1 checkConfigOutput '^\{"foo":1\}$' config.nullableValue.attrs ./types.nix
|
||||
STRICT_EVAL=1 checkConfigOutput '^\[\{"bar":\[1\]\}\]$' config.nullableValue.list ./types.nix
|
||||
|
||||
checkConfigError 'A definition for option .* is not of type .VAL value.. .*' config.nullableValue.lambda ./types.nix
|
||||
checkConfigError 'A definition for option .* is not of type .VAL value.. .*' config.structuredValue.null ./types.nix
|
||||
|
||||
# Check boolean option.
|
||||
checkConfigOutput '^false$' config.enable ./declare-enable.nix
|
||||
checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*: true' config.enable ./define-enable.nix
|
||||
|
||||
@@ -16,6 +16,19 @@ in
|
||||
options = {
|
||||
pathInStore = mkOption { type = types.lazyAttrsOf types.pathInStore; };
|
||||
externalPath = mkOption { type = types.lazyAttrsOf types.externalPath; };
|
||||
# serializableValueWith
|
||||
nullableValue = mkOption {
|
||||
type = types.attrsOf (types.serializableValueWith { typeName = "VAL"; });
|
||||
};
|
||||
structuredValue = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.serializableValueWith {
|
||||
typeName = "VAL";
|
||||
nullable = false;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
assertions = mkOption { };
|
||||
};
|
||||
config = {
|
||||
@@ -35,6 +48,22 @@ in
|
||||
externalPath.ok1 = "/foo/bar";
|
||||
externalPath.ok2 = "/";
|
||||
|
||||
# serializableValueWith { nullable = true; }
|
||||
nullableValue.null = null; # null
|
||||
nullableValue.bool = true; # bool
|
||||
nullableValue.int = 1; # int
|
||||
nullableValue.float = 1.1; # float
|
||||
nullableValue.str = "foo"; # str
|
||||
nullableValue.path = ./.; # path
|
||||
nullableValue.attrs = {
|
||||
foo = 1;
|
||||
};
|
||||
nullableValue.list = [ { bar = [ 1 ]; } ]; # list
|
||||
nullableValue.lambda = x: x; # Error
|
||||
|
||||
# serializableValueWith { nullable = false; }
|
||||
structuredValue.null = null; # Error
|
||||
|
||||
assertions =
|
||||
with lib.types;
|
||||
|
||||
@@ -486,6 +515,9 @@ in
|
||||
assert (unique { message = "custom"; } (listOf str)).description == "list of string";
|
||||
assert (unique { message = "test"; } (either int str)).description == "signed integer or string";
|
||||
assert (unique { message = "test"; } (listOf str)).description == "list of string";
|
||||
# json & toml
|
||||
assert json.description == "JSON value";
|
||||
assert toml.description == "TOML value";
|
||||
# done
|
||||
"ok";
|
||||
};
|
||||
|
||||
@@ -1437,6 +1437,45 @@ rec {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
Creates a value type suitable for serialization formats.
|
||||
|
||||
Parameters:
|
||||
- typeName: String describing the format (e.g. "JSON", "YAML", "XML")
|
||||
- nullable: Whether the structured value type allows `null` values.
|
||||
|
||||
Returns a type suitable for structured data formats that supports:
|
||||
- Basic types: boolean, integer, float, string, path
|
||||
- Complex types: attribute sets and lists
|
||||
*/
|
||||
serializableValueWith =
|
||||
{
|
||||
typeName,
|
||||
nullable ? true,
|
||||
}:
|
||||
let
|
||||
baseType = oneOf [
|
||||
bool
|
||||
int
|
||||
float
|
||||
str
|
||||
path
|
||||
(attrsOf valueType)
|
||||
(listOf valueType)
|
||||
];
|
||||
valueType = (if nullable then nullOr baseType else baseType) // {
|
||||
description = "${typeName} value";
|
||||
};
|
||||
in
|
||||
valueType;
|
||||
|
||||
json = serializableValueWith { typeName = "JSON"; };
|
||||
|
||||
toml = serializableValueWith {
|
||||
typeName = "TOML";
|
||||
nullable = false;
|
||||
};
|
||||
|
||||
# Either value of type `t1` or `t2`.
|
||||
either =
|
||||
t1: t2:
|
||||
|
||||
@@ -497,6 +497,20 @@ Composed types are types that take a type as parameter. `listOf
|
||||
value of type *`to`*. Can be used to preserve backwards compatibility
|
||||
of an option if its type was changed.
|
||||
|
||||
`types.json`
|
||||
|
||||
: A type representing JSON-compatible values. This includes `null`, booleans,
|
||||
integers, floats, strings, paths, attribute sets, and lists.
|
||||
Attribute sets and lists can be arbitrarily nested and contain any JSON-compatible
|
||||
values.
|
||||
|
||||
`types.toml`
|
||||
|
||||
: A type representing TOML-compatible values. This includes booleans,
|
||||
integers, floats, strings, paths, attribute sets, and lists.
|
||||
Attribute sets and lists can be arbitrarily nested and contain any TOML-compatible
|
||||
values.
|
||||
|
||||
## Submodule {#section-option-types-submodule}
|
||||
|
||||
`submodule` is a very powerful type that defines a set of sub-options
|
||||
|
||||
@@ -40,6 +40,7 @@ let
|
||||
;
|
||||
|
||||
inherit (lib.types)
|
||||
serializableValueWith
|
||||
attrsOf
|
||||
atom
|
||||
bool
|
||||
@@ -58,38 +59,6 @@ let
|
||||
submodule
|
||||
;
|
||||
|
||||
/*
|
||||
Creates a structured value type suitable for serialization formats.
|
||||
|
||||
Parameters:
|
||||
- typeName: String describing the format (e.g. "JSON", "YAML", "XML")
|
||||
- nullable: Whether the structured value type allows `null` values.
|
||||
|
||||
Returns a type suitable for structured data formats that supports:
|
||||
- Basic types: boolean, integer, float, string, path
|
||||
- Complex types: attribute sets and lists
|
||||
*/
|
||||
mkStructuredType =
|
||||
{
|
||||
typeName,
|
||||
nullable ? true,
|
||||
}:
|
||||
let
|
||||
baseType = oneOf [
|
||||
bool
|
||||
int
|
||||
float
|
||||
str
|
||||
path
|
||||
(attrsOf valueType)
|
||||
(listOf valueType)
|
||||
];
|
||||
valueType = (if nullable then nullOr baseType else baseType) // {
|
||||
description = "${typeName} value";
|
||||
};
|
||||
in
|
||||
valueType;
|
||||
|
||||
# Attributes added accidentally in https://github.com/NixOS/nixpkgs/pull/335232 (2024-08-18)
|
||||
# Deprecated in https://github.com/NixOS/nixpkgs/pull/415666 (2025-06)
|
||||
allowAliases = pkgs.config.allowAliases or false;
|
||||
@@ -162,7 +131,7 @@ optionalAttrs allowAliases aliases
|
||||
{ }:
|
||||
{
|
||||
|
||||
type = mkStructuredType { typeName = "JSON"; };
|
||||
type = types.json;
|
||||
|
||||
generate =
|
||||
name: value:
|
||||
@@ -203,7 +172,7 @@ optionalAttrs allowAliases aliases
|
||||
''
|
||||
) { };
|
||||
|
||||
type = mkStructuredType { typeName = "YAML 1.1"; };
|
||||
type = serializableValueWith { typeName = "YAML 1.1"; };
|
||||
|
||||
};
|
||||
|
||||
@@ -226,7 +195,7 @@ optionalAttrs allowAliases aliases
|
||||
''
|
||||
) { };
|
||||
|
||||
type = mkStructuredType { typeName = "YAML 1.2"; };
|
||||
type = serializableValueWith { typeName = "YAML 1.2"; };
|
||||
|
||||
};
|
||||
|
||||
@@ -487,10 +456,7 @@ optionalAttrs allowAliases aliases
|
||||
{ }:
|
||||
json { }
|
||||
// {
|
||||
type = mkStructuredType {
|
||||
typeName = "TOML";
|
||||
nullable = false;
|
||||
};
|
||||
type = types.toml;
|
||||
|
||||
generate =
|
||||
name: value:
|
||||
@@ -523,7 +489,7 @@ optionalAttrs allowAliases aliases
|
||||
{ }:
|
||||
json { }
|
||||
// {
|
||||
type = mkStructuredType { typeName = "CDN"; };
|
||||
type = serializableValueWith { typeName = "CDN"; };
|
||||
|
||||
generate =
|
||||
name: value:
|
||||
@@ -938,7 +904,7 @@ optionalAttrs allowAliases aliases
|
||||
pythonVars =
|
||||
{ }:
|
||||
{
|
||||
type = attrsOf (mkStructuredType {
|
||||
type = attrsOf (serializableValueWith {
|
||||
typeName = "Python";
|
||||
});
|
||||
|
||||
@@ -1020,7 +986,7 @@ optionalAttrs allowAliases aliases
|
||||
}:
|
||||
if format == "badgerfish" then
|
||||
{
|
||||
type = mkStructuredType { typeName = "XML"; };
|
||||
type = serializableValueWith { typeName = "XML"; };
|
||||
|
||||
generate =
|
||||
name: value:
|
||||
|
||||
Reference in New Issue
Block a user