{ lib }: with lib; rec { # Whether the string is a reserved keyword in lua isKeyword = s: elem s [ "and" "break" "do" "else" "elseif" "end" "false" "for" "function" "if" "in" "local" "nil" "not" "or" "repeat" "return" "then" "true" "until" "while" ]; # Valid lua identifiers are not reserved keywords, do not start with a digit, # and contain only letters, digits, and underscores. isIdentifier = s: !(isKeyword s) && (match "[A-Za-z_][0-9A-Za-z_]*" s) == [ ]; # Black functional magic that converts a bunch of different Nix types to their # lua equivalents! toLuaObject = args: if builtins.isAttrs args then if hasAttr "__raw" args then args.__raw else if hasAttr "__empty" args then "{ }" else "{" + (concatStringsSep ", " ( mapAttrsToList ( n: v: let keyString = if n == "__emptyString" then "['']" else if hasPrefix "__rawKey__" n then "[${removePrefix "__rawKey__" n}]" else if isIdentifier n then n else "[${toLuaObject n}]"; valueString = toLuaObject v; in if hasPrefix "__unkeyed" n then valueString else "${keyString} = ${valueString}" ) (filterAttrs (n: v: v != null && (toLuaObject v != "{}")) args) )) + "}" else if builtins.isList args then "{" + concatMapStringsSep ", " toLuaObject args + "}" else if builtins.isString args then # This should be enough! builtins.toJSON args else if builtins.isPath args then builtins.toJSON (toString args) else if builtins.isBool args then "${boolToString args}" else if builtins.isFloat args then "${toString args}" else if builtins.isInt args then "${toString args}" else if (args == null) then "nil" else ""; }