Commit 7ae278da authored by Silvan Mosberger's avatar Silvan Mosberger
Browse files

meta-types.nix: Refactor

parent 4e0f75f6
Loading
Loading
Loading
Loading
+5 −31
Original line number Diff line number Diff line
@@ -317,7 +317,7 @@ let
      ${concatStrings (map (output: "  - ${output}\n") missingOutputs)}
    '';

  metaTypes =
  metaType =
    let
      types = import ./meta-types.nix { inherit lib; };
      inherit (types)
@@ -329,13 +329,14 @@ let
        any
        listOf
        bool
        record
        ;
      platforms = listOf (union [
        str
        (attrsOf any)
      ]); # see lib.meta.platformMatch
    in
    {
    record {
      # These keys are documented
      description = str;
      mainProgram = str;
@@ -404,34 +405,7 @@ let
      identifiers = attrs;
    };

  # Map attrs directly to the verify function for performance
  metaTypes' = mapAttrs (_: t: t.verify) metaTypes;

  checkMetaAttr =
    k: v:
    if metaTypes ? ${k} then
      if metaTypes'.${k} v then
        [ ]
      else
        [
          "key 'meta.${k}' has invalid value; expected ${metaTypes.${k}.name}, got\n    ${
            toPretty { indent = "    "; } v
          }"
        ]
    else
      [
        "key 'meta.${k}' is unrecognized; expected one of: \n  [${
          concatMapStringsSep ", " (x: "'${x}'") (attrNames metaTypes)
        }]"
      ];

  checkMeta = meta: concatMap (attr: checkMetaAttr attr meta.${attr}) (attrNames meta);

  metaInvalid =
    if config.checkMeta then
      meta: !all (attr: metaTypes ? ${attr} && metaTypes'.${attr} meta.${attr}) (attrNames meta)
    else
      meta: false;
  metaInvalid = if config.checkMeta then meta: !metaType.verify meta else meta: false;

  checkOutputsToInstall =
    if config.checkMeta then
@@ -459,7 +433,7 @@ let
      {
        reason = "unknown-meta";
        errormsg = "has an invalid meta attrset:${
          concatMapStrings (x: "\n  - " + x) (checkMeta attrs.meta)
          concatMapStrings (x: "\n  - " + x) (metaType.errors "${getName attrs}.meta" attrs.meta)
        }\n";
        remediation = "";
      }
+54 −1
Original line number Diff line number Diff line
@@ -12,16 +12,40 @@ let
    isList
    all
    any
    attrNames
    attrValues
    concatMap
    isFunction
    isBool
    concatStringsSep
    concatMapStringsSep
    isFloat
    elem
    mapAttrs
    ;
  isTypeDef = t: isAttrs t && t ? name && isString t.name && t ? verify && isFunction t.verify;

in
lib.fix (self: {

  /*
    `errors type "<context>" value` gives a list of string error messages,
    each prefixed with "<context>: ", for why `value` is not of type `type`

    Only use this if `type.verify value` is false

    Types can override this by specifying their own `type.errors = ctx: value:` attribute

    This is intentionally not tied into `type.verify`,
    in order to keep the successful path as fast as possible with minimal allocations
  */
  errors =
    t:
    t.errors or (ctx: v: [
      "${ctx}: Invalid value; expected ${t.name}, got\n    ${
        lib.generators.toPretty { indent = "    "; } v
      }"
    ]);

  string = {
    name = "string";
    verify = isString;
@@ -95,4 +119,33 @@ lib.fix (self: {
      name = "union<${concatStringsSep "," (map (t: t.name) types)}>";
      verify = v: any (func: func v) funcs;
    };

  record =
    fields:
    assert isAttrs fields && all isTypeDef (attrValues fields);
    let
      # Map attrs directly to the verify function for performance
      fieldVerifiers = mapAttrs (_: t: t.verify) fields;
    in
    {
      name = "record";
      verify = v: isAttrs v && all (k: fieldVerifiers ? ${k} && fieldVerifiers.${k} v.${k}) (attrNames v);
      errors =
        ctx: v:
        if !isAttrs v then
          self.errors self.attrs ctx v
        else
          concatMap (
            k:
            if fieldVerifiers ? ${k} then
              lib.optionals (fieldVerifiers.${k} v.${k}) (self.errors fields.${k} (ctx + ".${k}") v.${k})
            else
              [
                "${ctx}: key '${k}' is unrecognized; expected one of: \n  [${
                  concatMapStringsSep ", " (x: "'${x}'") (attrNames fields)
                }]"
              ]
          ) (attrNames v);
    };

})