diff --git a/pkgs/pkgs-lib/formats.nix b/pkgs/pkgs-lib/formats.nix index a9be2a0e6dcd..46a0dfcfcfe9 100644 --- a/pkgs/pkgs-lib/formats.nix +++ b/pkgs/pkgs-lib/formats.nix @@ -1053,4 +1053,27 @@ optionalAttrs allowAliases aliases generate = name: value: pkgs.writeText name (lib.generators.toPlist { inherit escape; } value); }; + + hcl1 = + args: + let + # Helper function to recursively transform values for HCL1 canonicalization + # Rule: If an attribute value is an attribute set, wrap it in a list + transform = + value: + if isAttrs value && !isDerivation value then + # If it's an attribute set, transform it recursively and wrap in a list + [ (mapAttrs (name: transform) value) ] + else if isList value then + # If it's already a list, transform each element + map transform value + else + value; + jsonFormat = json { }; + in + jsonFormat + // { + generate = name: value: jsonFormat.generate name (mapAttrs (_: transform) value); + }; + } diff --git a/pkgs/pkgs-lib/tests/formats.nix b/pkgs/pkgs-lib/tests/formats.nix index a32db61709b5..c50a92174436 100644 --- a/pkgs/pkgs-lib/tests/formats.nix +++ b/pkgs/pkgs-lib/tests/formats.nix @@ -1080,4 +1080,70 @@ runBuildTests { ''; }; + + hcl1Atoms = shouldPass { + format = formats.hcl1 { }; + input = { + resource = { + aws_instance = { + example = { + ami = "ami-12345"; + instance_type = "t2.micro"; + }; + }; + }; + variable = { + region = { + default = "us-east-1"; + }; + }; + output = { + ip = { + value = "127.0.0.1"; + }; + }; + primitive = "just a string"; + number = 42; + enabled = true; + }; + expected = '' + { + "enabled": true, + "number": 42, + "output": [ + { + "ip": [ + { + "value": "127.0.0.1" + } + ] + } + ], + "primitive": "just a string", + "resource": [ + { + "aws_instance": [ + { + "example": [ + { + "ami": "ami-12345", + "instance_type": "t2.micro" + } + ] + } + ] + } + ], + "variable": [ + { + "region": [ + { + "default": "us-east-1" + } + ] + } + ] + } + ''; + }; }