Unverified Commit a0150d72 authored by Johannes Kirschbauer's avatar Johannes Kirschbauer Committed by GitHub
Browse files

lib/types: add types json from pkgs.formats (#470842)

parents 945fb95c f4d45cdc
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -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
+32 −0
Original line number Diff line number Diff line
@@ -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";
  };
+39 −0
Original line number Diff line number Diff line
@@ -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:
+14 −0
Original line number Diff line number Diff line
@@ -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
+8 −42
Original line number Diff line number Diff line
@@ -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: