Packages
git_hub_actions
0.2.25
0.4.2
0.4.1
0.4.0
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.27
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A little tool to write GitHub actions in Elixir
Current section
Files
Jump to
Current section
Files
lib/git_hub_actions/yaml.ex
defmodule GitHubActions.Yaml do
@moduledoc false
@spec encode(any()) :: String.t()
def encode(data) do
data
|> do_encode([], 0)
|> Enum.reverse()
|> Enum.join("\n")
|> newline()
end
defp do_encode(data, lines, _depth) when is_binary(data) do
string = if num_or_version?(data), do: "'#{data}'", else: data
[string | lines]
end
defp do_encode(data, lines, _depth) when is_number(data) do
[to_string(data) | lines]
end
defp do_encode(data, lines, depth) when is_map(data) do
data
|> Enum.into([])
|> do_encode(lines, depth)
end
defp do_encode([{key, item} | data], lines, depth) when is_binary(item) do
item = if num_or_version?(item), do: "'#{item}'", else: item
case lines?(item) do
true ->
add = indent_heredoc(key, item, depth)
do_encode(data, add ++ lines, depth)
false ->
add = indent_key(key, item, depth)
do_encode(data, [add | lines], depth)
end
end
defp do_encode([{key, item} | data], lines, depth) when is_number(item) do
add = indent_key(key, item, depth)
do_encode(data, [add | lines], depth)
end
defp do_encode([{key, item} | data], lines, depth) do
add = indent_key(key, depth)
sub = do_encode(item, [], depth + 1)
do_encode(data, Enum.concat([sub, [add], lines]), depth)
end
defp do_encode([item | data], lines, depth) do
{items, [last]} = item |> do_encode([], 0) |> Enum.split(-1)
items = indent(items, depth + 1) ++ [indent_item(last, depth)]
do_encode(data, items ++ lines, depth)
end
defp do_encode([], lines, _depth), do: lines
defp indent(depth), do: String.duplicate(" ", depth * 2)
defp indent(lines, depth) when is_list(lines) do
Enum.map(lines, fn line -> "#{indent(depth)}#{line}" end)
end
defp indent_item(item, depth), do: "#{indent(depth)}- #{item}"
defp indent_key(key, depth), do: "#{indent(depth)}#{key}:"
defp indent_heredoc(string, depth) do
string
|> String.trim_trailing()
|> String.split("\n")
|> indent(depth)
|> Enum.reverse()
end
defp indent_key(key, item, depth), do: "#{indent_key(key, depth)} #{item}"
defp indent_heredoc(key, string, depth) do
lines = indent_heredoc(string, depth + 1)
line = "#{indent_key(key, depth)} |"
lines ++ [line]
end
defp lines?(string), do: String.contains?(string, "\n")
defp newline(string), do: "#{string}\n"
defp num_or_version?(string) do
string
|> String.split(".")
|> Enum.all?(fn part -> part =~ ~r/^\d+$/ end)
end
end