diff --git a/modules/lib/generators.nix b/modules/lib/generators.nix index 9cb0e1cf..63829fa3 100644 --- a/modules/lib/generators.nix +++ b/modules/lib/generators.nix @@ -1,11 +1,22 @@ { lib }: { + toKDL = { }: let - inherit (lib) concatStringsSep splitString mapAttrsToList any; + inherit (lib) concatStringsSep; inherit (builtins) typeOf replaceStrings elem; + # KDL Spec Summary + # Document -> Node[] + # Node -> {[Type] NodeName [Args] [Properties] [Children]} + # Type -> Ident + # NodeName -> Ident + # Args -> Value[] # Note: ordered + # Properties -> map[Ident]Value # Note: Unordered + # Children -> Node[] # Note: ordered + # Value -> String | Number | Bool | Null + # ListOf String -> String indentStrings = let # Although the input of this function is a list of strings, @@ -35,69 +46,49 @@ else toString element); - # Attrset Conversion - # String -> AttrsOf Anything -> String - convertAttrsToKDL = name: attrs: + # Node Attrset Conversion + # AttrsOf Anything -> String + attrsToKDLNode = attrs: let - optArgsString = lib.optionalString (attrs ? "_args") - (lib.pipe attrs._args [ + optType = lib.optionalString (attrs ? "type") attrs.type; + + name = attrs.name; + + optArgsString = lib.optionalString (attrs ? "args") + (lib.pipe attrs.args [ + (a: if typeOf a == "list" then a else [ a ]) (map literalValueToString) (lib.concatStringsSep " ") - (s: s + " ") ]); - optPropsString = lib.optionalString (attrs ? "_props") - (lib.pipe attrs._props [ + optPropsString = lib.optionalString (attrs ? "props") + (lib.pipe attrs.props [ (lib.mapAttrsToList (name: value: "${name}=${literalValueToString value}")) (lib.concatStringsSep " ") - (s: s + " ") ]); - children = - lib.filterAttrs (name: _: !(elem name [ "_args" "_props" ])) attrs; - in '' - ${name} ${optArgsString}${optPropsString}{ - ${indentStrings (mapAttrsToList convertAttributeToKDL children)} - }''; + optChildren = lib.optionalString (attrs ? "children") + (lib.pipe attrs.children [ + (a: if typeOf a == "list" then a else [ a ]) + (map attrsToKDLNode) + (s: + lib.optionalString (builtins.length s > 0) '' + { + ${indentStrings s} + }'') + ]); - # List Conversion - # String -> ListOf (OneOf [Int Float String Bool Null]) -> String - convertListOfFlatAttrsToKDL = name: list: - let flatElements = map literalValueToString list; - in "${name} ${concatStringsSep " " flatElements}"; + in lib.concatStringsSep " " (lib.filter (s: s != "") [ + optType + name + optArgsString + optPropsString + optChildren + ]); - # String -> ListOf Anything -> String - convertListOfNonFlatAttrsToKDL = name: list: '' - ${name} { - ${indentStrings (map (x: convertAttributeToKDL "-" x) list)} - }''; - - # String -> ListOf Anything -> String - convertListToKDL = name: list: - let elementsAreFlat = !any (el: elem (typeOf el) [ "list" "set" ]) list; - in if elementsAreFlat then - convertListOfFlatAttrsToKDL name list - else - convertListOfNonFlatAttrsToKDL name list; - - # Combined Conversion - # String -> Anything -> String - convertAttributeToKDL = name: value: - let vType = typeOf value; - in if elem vType [ "int" "float" "bool" "null" "string" ] then - "${name} ${literalValueToString value}" - else if vType == "set" then - convertAttrsToKDL name value - else if vType == "list" then - convertListToKDL name value - else - throw '' - Cannot convert type `(${typeOf value})` to KDL: - ${name} = ${toString value} - ''; - in attrs: '' - ${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL attrs)} + in nodes: '' + ${concatStringsSep "\n" (map attrsToKDLNode nodes)} ''; toSCFG = { }: diff --git a/tests/lib/generators/tokdl-result.txt b/tests/lib/generators/tokdl-result.txt index 6ad2af36..124d0312 100644 --- a/tests/lib/generators/tokdl-result.txt +++ b/tests/lib/generators/tokdl-result.txt @@ -1,14 +1,19 @@ a 1 b "string" -bigFlatItems 23847590283751 1.239000 "multiline \" \" \"\nstring\n" null c "multiline string\nwith special characters:\n\t \n \\" \"\n" +unsafeString " \" \n " +flatItems 1 2 "asdf" true null +bigFlatItems 23847590283751 1.239000 "multiline \" \" \"\nstring\n" null +repeated 1 2 +repeated true false +repeated +repeated null extraAttrs 2 true arg1=1 arg2=false { nested { a 1 b null } } -flatItems 1 2 "asdf" true null listInAttrsInList { list1 { - { @@ -27,15 +32,6 @@ listInAttrsInList { } } list2 { - - { - a 8 - } + a 8 } } -nested { - - 1 2 - - true false - - - - null -} -unsafeString " \" \n " diff --git a/tests/lib/generators/tokdl.nix b/tests/lib/generators/tokdl.nix index 6e4a4047..55957c46 100644 --- a/tests/lib/generators/tokdl.nix +++ b/tests/lib/generators/tokdl.nix @@ -1,49 +1,126 @@ -{ config, lib, ... }: - -{ - home.file."tokdl-result.txt".text = lib.hm.generators.toKDL { } { - a = 1; - b = "string"; - c = '' - multiline string - with special characters: - \t \n \" " - ''; - unsafeString = " \" \n "; - flatItems = [ 1 2 "asdf" true null ]; - bigFlatItems = [ - 23847590283751 - 1.239 - '' - multiline " " " - string - '' - null - ]; - nested = [ [ 1 2 ] [ true false ] [ ] [ null ] ]; - extraAttrs = { - _args = [ 2 true ]; - _props = { +{ lib, ... }: { + home.file."tokdl-result.txt".text = lib.hm.generators.toKDL { } [ + { + name = "a"; + args = 1; + } + { + name = "b"; + args = "string"; + } + { + name = "c"; + args = '' + multiline string + with special characters: + \t \n \" " + ''; + } + { + name = "unsafeString"; + args = " \" \n "; + } + { + name = "flatItems"; + args = [ 1 2 "asdf" true null ]; + } + { + name = "bigFlatItems"; + args = [ + 23847590283751 + 1.239 + '' + multiline " " " + string + '' + null + ]; + } + { + name = "repeated"; + args = [ 1 2 ]; + } + { + name = "repeated"; + args = [ true false ]; + } + { name = "repeated"; } + { + name = "repeated"; + args = [ null ]; + } + { + name = "extraAttrs"; + args = [ 2 true ]; + props = { arg1 = 1; arg2 = false; }; - nested = { - a = 1; - b = null; + children = { + name = "nested"; + children = [ + { + name = "a"; + args = [ 1 ]; + } + { + name = "b"; + args = [ null ]; + } + ]; }; - }; - listInAttrsInList = { - list1 = [ - { a = 1; } - { b = true; } + } + { + name = "listInAttrsInList"; + children = [ { - c = null; - d = [{ e = "asdfadfasdfasdf"; }]; + name = "list1"; + children = [ + { + name = "-"; + children = { + name = "a"; + args = [ 1 ]; + }; + } + { + name = "-"; + children = { + name = "b"; + args = [ true ]; + }; + } + { + name = "-"; + children = [ + { + name = "c"; + args = [ null ]; + } + { + name = "d"; + children = { + name = "-"; + children = { + name = "e"; + args = [ "asdfadfasdfasdf" ]; + }; + }; + } + ]; + } + ]; + } + { + name = "list2"; + children = [{ + name = "a"; + args = [ 8 ]; + }]; } ]; - list2 = [{ a = 8; }]; - }; - }; + } + ]; nmt.script = '' assertFileContent \