Packages
git_hub_actions
0.3.5
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 multiline?(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, {:quoted, item}} | data], lines, depth) do
case multiline?(item) do
true ->
add = indent_multiline(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_key(key, item, depth), do: "#{indent_key(key, depth)} #{item}"
defp indent_heredoc(string, depth) do
string
|> String.trim_trailing()
|> String.split("\n")
|> indent(depth)
|> Enum.reverse()
end
defp indent_heredoc(key, string, depth) do
lines = indent_heredoc(string, depth + 1)
line = "#{indent_key(key, depth)} |"
lines ++ [line]
end
defp indent_multiline(string, depth) do
[line | lines] =
string
|> String.trim_trailing()
|> String.split("\n")
lines = lines |> indent(depth) |> Enum.reverse()
{line, lines}
end
defp indent_multiline(key, string, depth) do
{line, lines} = indent_multiline(string, depth + 1)
line = "#{indent_key(key, depth)} #{line}"
lines ++ [line]
end
defp multiline?(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