diff --git a/lib/lexer.ex b/lib/lexer.ex
index 90b9337..d648f9f 100644
--- a/lib/lexer.ex
+++ b/lib/lexer.ex
@@ -2,14 +2,13 @@ defmodule MfmParser.Lexer do
alias MfmParser.Reader
alias MfmParser.Token
- alias MfmParser.Token.MFMOpen
- alias MfmParser.Token.MFMClose
+ alias MfmParser.Token.MFM
alias MfmParser.Token.Newline
alias MfmParser.Token.Text
def peek(input) do
case next(input) do
- {:ok, token, _} -> {:ok, token}
+ {token, _} -> token
:eof -> :eof
end
end
@@ -22,9 +21,9 @@ defmodule MfmParser.Lexer do
:eof
end
- defp recursive_extract_next_token({:ok, char, rest}, token) do
+ defp recursive_extract_next_token({char, rest}, token) do
if is_last_char_of_token?(char, rest, token) do
- {:ok, token |> Token.append(char), rest}
+ {token |> Token.append(char), rest}
else
recursive_extract_next_token(Reader.next(rest), token |> Token.append(char))
end
@@ -33,18 +32,18 @@ defmodule MfmParser.Lexer do
defp get_empty_token(input) do
case Reader.peek(input) do
:eof -> :eof
- {:ok, "$"} -> %MFMOpen{}
- {:ok, "]"} -> %MFMClose{}
- {:ok, "\n"} -> %Newline{}
+ "$" -> %MFM.Open{}
+ "]" -> %MFM.Close{}
+ "\n" -> %Newline{}
_ -> %Text{}
end
end
- defp is_last_char_of_token?(char, _, %MFMOpen{}) do
+ defp is_last_char_of_token?(char, _, %MFM.Open{}) do
char == " "
end
- defp is_last_char_of_token?(_, _, %MFMClose{}) do
+ defp is_last_char_of_token?(_, _, %MFM.Close{}) do
true
end
@@ -55,8 +54,8 @@ defmodule MfmParser.Lexer do
defp is_last_char_of_token?(_, rest, %Text{}) do
case Reader.next(rest) do
:eof -> true
- {:ok, "]", _} -> true
- {:ok, "$", new_rest} -> Reader.peek(new_rest) == {:ok, "["}
+ {"]", _} -> true
+ {"$", new_rest} -> Reader.peek(new_rest) == "["
_ -> false
end
end
diff --git a/lib/node/mfm/blur.ex b/lib/node/mfm/blur.ex
new file mode 100644
index 0000000..ed41ec7
--- /dev/null
+++ b/lib/node/mfm/blur.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Blur do
+ defstruct props: %{}, children: []
+end
diff --git a/lib/node/mfm/bounce.ex b/lib/node/mfm/bounce.ex
new file mode 100644
index 0000000..44ddc0f
--- /dev/null
+++ b/lib/node/mfm/bounce.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Bounce do
+ defstruct props: %{ speed: "0.75s" }, children: []
+end
diff --git a/lib/node/mfm/flip.ex b/lib/node/mfm/flip.ex
new file mode 100644
index 0000000..59fbc85
--- /dev/null
+++ b/lib/node/mfm/flip.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Flip do
+ defstruct props: %{ v: false, h: false }, children: []
+end
diff --git a/lib/node/mfm/font.ex b/lib/node/mfm/font.ex
new file mode 100644
index 0000000..e18f80a
--- /dev/null
+++ b/lib/node/mfm/font.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Font do
+ defstruct props: %{ font: nil }, children: []
+end
diff --git a/lib/node/mfm/jelly.ex b/lib/node/mfm/jelly.ex
new file mode 100644
index 0000000..e3e5561
--- /dev/null
+++ b/lib/node/mfm/jelly.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Jelly do
+ defstruct props: %{ speed: "1s" }, children: []
+end
diff --git a/lib/node/mfm/jump.ex b/lib/node/mfm/jump.ex
new file mode 100644
index 0000000..e65bb5e
--- /dev/null
+++ b/lib/node/mfm/jump.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Jump do
+ defstruct props: %{ speed: "0.75s" }, children: []
+end
diff --git a/lib/node/mfm/rainbow.ex b/lib/node/mfm/rainbow.ex
new file mode 100644
index 0000000..51042a6
--- /dev/null
+++ b/lib/node/mfm/rainbow.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Rainbow do
+ defstruct props: %{ speed: "1s" }, children: []
+end
diff --git a/lib/node/mfm/rotate.ex b/lib/node/mfm/rotate.ex
new file mode 100644
index 0000000..8b745ae
--- /dev/null
+++ b/lib/node/mfm/rotate.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Rotate do
+ defstruct props: %{}, children: []
+end
diff --git a/lib/node/mfm/shake.ex b/lib/node/mfm/shake.ex
new file mode 100644
index 0000000..44aa5c7
--- /dev/null
+++ b/lib/node/mfm/shake.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Shake do
+ defstruct props: %{ speed: "0.5s" }, children: []
+end
diff --git a/lib/node/mfm/sparkle.ex b/lib/node/mfm/sparkle.ex
new file mode 100644
index 0000000..9eff541
--- /dev/null
+++ b/lib/node/mfm/sparkle.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Sparkle do
+ defstruct props: %{}, children: []
+end
diff --git a/lib/node/mfm/spin.ex b/lib/node/mfm/spin.ex
new file mode 100644
index 0000000..efb40fd
--- /dev/null
+++ b/lib/node/mfm/spin.ex
@@ -0,0 +1,13 @@
+defmodule MfmParser.Node.MFM.Spin do
+ # keyframes_name:
+ # x -> mfm-spinX
+ # y -> mfm-spinY
+ # _ -> mfm-spin
+ #
+ # direction:
+ # left -> reverse
+ # alternate -> alternate
+ # _ -> normal
+ #
+ defstruct props: %{keyframes_name: "mfm-spin", direction: "normal", speed: "1.5s"}, children: []
+end
diff --git a/lib/node/mfm/tada.ex b/lib/node/mfm/tada.ex
new file mode 100644
index 0000000..857e5a7
--- /dev/null
+++ b/lib/node/mfm/tada.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Tada do
+ defstruct props: %{ speed: "1s" }, children: []
+end
diff --git a/lib/node/mfm/twitch.ex b/lib/node/mfm/twitch.ex
new file mode 100644
index 0000000..87b9a4c
--- /dev/null
+++ b/lib/node/mfm/twitch.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Twitch do
+ defstruct props: %{ speed: "0.5s" }, children: []
+end
diff --git a/lib/node/mfm/undefined.ex b/lib/node/mfm/undefined.ex
new file mode 100644
index 0000000..36ba3bf
--- /dev/null
+++ b/lib/node/mfm/undefined.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.Undefined do
+ defstruct props: %{}, children: []
+end
diff --git a/lib/node/mfm/x.ex b/lib/node/mfm/x.ex
new file mode 100644
index 0000000..80040fd
--- /dev/null
+++ b/lib/node/mfm/x.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.MFM.X do
+ defstruct props: %{ size: nil }, children: []
+end
diff --git a/lib/node/newline.ex b/lib/node/newline.ex
new file mode 100644
index 0000000..8fe4b54
--- /dev/null
+++ b/lib/node/newline.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.Newline do
+ defstruct props: %{text: "\n"}
+end
diff --git a/lib/node/text.ex b/lib/node/text.ex
new file mode 100644
index 0000000..d644d28
--- /dev/null
+++ b/lib/node/text.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Node.Text do
+ defstruct props: %{text: ""}
+end
diff --git a/lib/parser.ex b/lib/parser.ex
new file mode 100644
index 0000000..fb324b0
--- /dev/null
+++ b/lib/parser.ex
@@ -0,0 +1,124 @@
+defmodule MfmParser.Parser do
+ alias MfmParser.Token
+ alias MfmParser.Node
+ alias MfmParser.Lexer
+
+ def parse(input, tree \\ [], is_end_token \\ fn _ -> false end) do
+ case Lexer.next(input) do
+ :eof ->
+ tree
+
+ {token, rest} ->
+ if is_end_token.(token) do
+ parse(rest, tree)
+ else
+ case token do
+ %Token.MFM.Open{} ->
+ parse(rest, tree ++ [get_node(token)], fn token ->
+ case token do
+ %Token.MFM.Close{} -> true
+ _ -> false
+ end
+ end)
+
+ %Token.Text{} ->
+ parse(
+ rest,
+ tree ++ [%Node.Text{props: %{text: token.content}}]
+ )
+
+ %Token.Newline{} ->
+ parse(
+ rest,
+ tree ++ [%Node.Newline{props: %{text: token.content}}]
+ )
+ end
+ end
+ end
+ end
+
+ def get_node(token = %{content: content}) do
+ cond do
+ content =~ "$[flip" -> %Node.MFM.Flip{} |> fill_props(token)
+ content =~ "$[font" -> %Node.MFM.Font{} |> fill_props(token)
+ content =~ "$[x" -> %Node.MFM.X{} |> fill_props(token)
+ content =~ "$[blur" -> %Node.MFM.Blur{} |> fill_props(token)
+ content =~ "$[jelly" -> %Node.MFM.Jelly{} |> fill_props(token)
+ content =~ "$[tada" -> %Node.MFM.Tada{} |> fill_props(token)
+ content =~ "$[jump" -> %Node.MFM.Jump{} |> fill_props(token)
+ content =~ "$[bounce" -> %Node.MFM.Bounce{} |> fill_props(token)
+ content =~ "$[spin" -> %Node.MFM.Spin{} |> fill_props(token)
+ content =~ "$[shake" -> %Node.MFM.Shake{} |> fill_props(token)
+ content =~ "$[twitch" -> %Node.MFM.Twitch{} |> fill_props(token)
+ content =~ "$[rainbow" -> %Node.MFM.Rainbow{} |> fill_props(token)
+ content =~ "$[sparkle" -> %Node.MFM.Sparkle{} |> fill_props(token)
+ content =~ "$[rotate" -> %Node.MFM.Rotate{} |> fill_props(token)
+ true -> %Node.MFM.Undefined{} |> fill_props(token)
+ end
+ end
+
+ defp fill_props(node = %{props: props}, %{content: content}) do
+ new_props = props |> Map.merge(Token.MFM.to_props(content))
+
+ node |> Map.merge(%{props: new_props})
+ end
+
+ # def parse(input, tree \\ [], end_token \\ nil) do
+ # {:ok, token, rest} = MfmParser.Lexer.next(input)
+ #
+ # cond do
+ # # EOF
+ # token == "" ->
+ # {:ok, tree}
+ #
+ # # end_token reached
+ # token == end_token ->
+ # {:ok, tree, rest}
+ #
+ # # Newline
+ # Regex.match?(~r/
|\n/, token) ->
+ # new_tree = tree ++ [%{type: "newline"}]
+ # parse(rest, new_tree, end_token)
+ #
+ # # MFM $[ token
+ # Regex.match?(~r/\$\[/, token) ->
+ # {:ok, content, new_rest} = parse(rest, [], "]")
+ #
+ # new_tree =
+ # tree ++
+ # [
+ # %{
+ # type: "mfm",
+ # name: MfmParser.Parser.MFM.get_name_from_token(token),
+ # content: content
+ # }
+ # ]
+ #
+ # parse(new_rest, new_tree, end_token)
+ #
+ # # HTML token
+ # Regex.match?(~r/<.*>/, token) ->
+ # new_end_token = MfmParser.Parser.HTML.get_end_token(token)
+ #
+ # {:ok, content, new_rest} = parse(rest, [], new_end_token)
+ #
+ # new_tree =
+ # tree ++
+ # [
+ # %{
+ # type: "html",
+ # name: MfmParser.Parser.HTML.get_name_from_token(token),
+ # attributes: MfmParser.Parser.HTML.get_attributes_from_token(token),
+ # content: content
+ # }
+ # ]
+ #
+ # parse(new_rest, new_tree, end_token)
+ #
+ # # Regular text
+ # true ->
+ # new_tree = tree ++ [%{type: "text", content: token}]
+ # parse(rest, new_tree, end_token)
+ # end
+ # end
+end
diff --git a/lib/reader.ex b/lib/reader.ex
index 2dd2e32..89569b2 100644
--- a/lib/reader.ex
+++ b/lib/reader.ex
@@ -4,7 +4,7 @@ defmodule MfmParser.Reader do
case next_char do
nil -> :eof
- _ -> {:ok, next_char}
+ _ -> next_char
end
end
@@ -13,7 +13,7 @@ defmodule MfmParser.Reader do
case next_char do
"" -> :eof
- _ -> {:ok, next_char, rest}
+ _ -> {next_char, rest}
end
end
end
diff --git a/lib/token/mfm.ex b/lib/token/mfm.ex
new file mode 100644
index 0000000..02cedfe
--- /dev/null
+++ b/lib/token/mfm.ex
@@ -0,0 +1,57 @@
+defmodule MfmParser.Token.MFM do
+ def to_props(opts_string) when is_binary(opts_string) do
+ if opts_string =~ "." do
+ Regex.replace(~r/^.*\./u, opts_string, "")
+ |> String.trim()
+ |> String.split(",")
+ |> Enum.reduce(%{}, fn opt, acc ->
+ acc
+ |> Map.merge(
+ cond do
+ opt =~ "speed" ->
+ %{speed: String.replace(opt, "speed=", "")}
+
+ opt =~ "v" ->
+ %{v: true}
+
+ opt =~ "h" ->
+ %{h: true}
+
+ opt =~ "x" ->
+ %{keyframes_name: "mfm-spinX"}
+
+ opt =~ "y" ->
+ %{keyframes_name: "mfm-spinY"}
+
+ opt =~ "left" ->
+ %{direction: "reverse"}
+
+ opt =~ "alternate" ->
+ %{direction: "alternate"}
+
+ true ->
+ if Regex.match?(~r/^\$\[font/, opts_string) do
+ %{font: opt}
+ else
+ %{}
+ end
+ end
+ )
+ end)
+ else
+ if opts_string =~ "$[x" do
+ %{
+ size:
+ case opts_string |> String.replace("$[x", "") |> String.trim() do
+ "2" -> "200%"
+ "3" -> "400%"
+ "4" -> "600%"
+ _ -> "100%"
+ end
+ }
+ else
+ %{}
+ end
+ end
+ end
+end
diff --git a/lib/token/mfm/close.ex b/lib/token/mfm/close.ex
new file mode 100644
index 0000000..91e5eca
--- /dev/null
+++ b/lib/token/mfm/close.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Token.MFM.Close do
+ defstruct content: ""
+end
diff --git a/lib/token/mfm/open.ex b/lib/token/mfm/open.ex
new file mode 100644
index 0000000..8c3720b
--- /dev/null
+++ b/lib/token/mfm/open.ex
@@ -0,0 +1,3 @@
+defmodule MfmParser.Token.MFM.Open do
+ defstruct content: ""
+end
diff --git a/lib/token/mfm_close.ex b/lib/token/mfm_close.ex
deleted file mode 100644
index 2245bb3..0000000
--- a/lib/token/mfm_close.ex
+++ /dev/null
@@ -1,3 +0,0 @@
-defmodule MfmParser.Token.MFMClose do
- defstruct content: ""
-end
diff --git a/lib/token/mfm_open.ex b/lib/token/mfm_open.ex
deleted file mode 100644
index 647eede..0000000
--- a/lib/token/mfm_open.ex
+++ /dev/null
@@ -1,3 +0,0 @@
-defmodule MfmParser.Token.MFMOpen do
- defstruct content: ""
-end
diff --git a/test/lexer_test.exs b/test/lexer_test.exs
index 2e99cf9..f8eb0db 100644
--- a/test/lexer_test.exs
+++ b/test/lexer_test.exs
@@ -3,8 +3,7 @@ defmodule MfmParser.LexerTest do
alias MfmParser.Lexer
- alias MfmParser.Token.MFMOpen
- alias MfmParser.Token.MFMClose
+ alias MfmParser.Token.MFM
alias MfmParser.Token.Newline
alias MfmParser.Token.Text
@@ -20,11 +19,11 @@ defmodule MfmParser.LexerTest do
describe "mfm $[ token" do
test "it ends with a space" do
- assert Lexer.peek("$[ola puerca]") == {:ok, %MFMOpen{content: "$[ola "}}
- assert Lexer.next("$[ola puerca]") == {:ok, %MFMOpen{content: "$[ola "}, "puerca]"}
+ assert Lexer.peek("$[ola puerca]") == %MFM.Open{content: "$[ola "}
+ assert Lexer.next("$[ola puerca]") == {%MFM.Open{content: "$[ola "}, "puerca]"}
assert Lexer.next("$[ola.x,speed=5s puerca]") ==
- {:ok, %MFMOpen{content: "$[ola.x,speed=5s "}, "puerca]"}
+ {%MFM.Open{content: "$[ola.x,speed=5s "}, "puerca]"}
end
test "it doesn't crash if the token can't be completed" do
@@ -35,54 +34,55 @@ defmodule MfmParser.LexerTest do
describe "] token" do
test "it handles ] as a token" do
- assert Lexer.peek("]ve anime") == {:ok, %MFMClose{content: "]"}}
- assert Lexer.next("]ve anime") == {:ok, %MFMClose{content: "]"}, "ve anime"}
+ assert Lexer.peek("]ve anime") == %MFM.Close{content: "]"}
+ assert Lexer.next("]ve anime") == {%MFM.Close{content: "]"}, "ve anime"}
end
test "it works at the eof" do
- assert Lexer.peek("]") == {:ok, %MFMClose{content: "]"}}
- assert Lexer.next("]") == {:ok, %MFMClose{content: "]"}, ""}
+ assert Lexer.peek("]") == %MFM.Close{content: "]"}
+ assert Lexer.next("]") == {%MFM.Close{content: "]"}, ""}
end
end
describe "text token" do
test "it ends when a mfm token opens while a $ alone doesn't end the text token" do
assert Lexer.peek("Tu abuela ve anime y no se lava el $[spin culo]") ==
- {:ok, %Text{content: "Tu abuela ve anime y no se lava el "}}
+ %Text{content: "Tu abuela ve anime y no se lava el "}
assert Lexer.next("Tu abuela ve anime y no se lava el $[spin culo]") ==
- {:ok, %Text{content: "Tu abuela ve anime y no se lava el "}, "$[spin culo]"}
+ {%Text{content: "Tu abuela ve anime y no se lava el "}, "$[spin culo]"}
- assert Lexer.peek("A $2 chocolatine") == {:ok, %Text{content: "A $2 chocolatine"}}
- assert Lexer.next("A $2 chocolatine") == {:ok, %Text{content: "A $2 chocolatine"}, ""}
+ assert Lexer.peek("A $2 chocolatine") == %Text{content: "A $2 chocolatine"}
+ assert Lexer.next("A $2 chocolatine") == {%Text{content: "A $2 chocolatine"}, ""}
- assert Lexer.peek("Eyes like $$") == {:ok, %Text{content: "Eyes like $$"}}
- assert Lexer.next("Eyes like $$") == {:ok, %Text{content: "Eyes like $$"}, ""}
+ assert Lexer.peek("Eyes like $$") == %Text{content: "Eyes like $$"}
+ assert Lexer.next("Eyes like $$") == {%Text{content: "Eyes like $$"}, ""}
end
test "it ends when a mfm token closes" do
- assert Lexer.peek("el culo]") == {:ok, %Text{content: "el culo"}}
- assert Lexer.next("el culo]") == {:ok, %Text{content: "el culo"}, "]"}
+ assert Lexer.peek("el culo]") == %Text{content: "el culo"}
+ assert Lexer.next("el culo]") == {%Text{content: "el culo"}, "]"}
end
test "it ends when the eof is reached" do
- assert Lexer.peek("Tu abuela ve anime y no se lava el culo") ==
- {:ok, %Text{content: "Tu abuela ve anime y no se lava el culo"}}
+ assert Lexer.peek("Tu abuela ve anime y no se lava el culo") == %Text{
+ content: "Tu abuela ve anime y no se lava el culo"
+ }
assert Lexer.next("Tu abuela ve anime y no se lava el culo") ==
- {:ok, %Text{content: "Tu abuela ve anime y no se lava el culo"}, ""}
+ {%Text{content: "Tu abuela ve anime y no se lava el culo"}, ""}
end
end
describe "newline token" do
test "it handles \n as a token" do
- assert Lexer.peek("\nchocolat") == {:ok, %Newline{content: "\n"}}
- assert Lexer.next("\nchocolat") == {:ok, %Newline{content: "\n"}, "chocolat"}
+ assert Lexer.peek("\nchocolat") == %Newline{content: "\n"}
+ assert Lexer.next("\nchocolat") == {%Newline{content: "\n"}, "chocolat"}
end
test "it works at the eof" do
- assert Lexer.peek("\n") == {:ok, %Newline{content: "\n"}}
- assert Lexer.next("\n") == {:ok, %Newline{content: "\n"}, ""}
+ assert Lexer.peek("\n") == %Newline{content: "\n"}
+ assert Lexer.next("\n") == {%Newline{content: "\n"}, ""}
end
end
end
diff --git a/test/parser_test.exs b/test/parser_test.exs
new file mode 100644
index 0000000..e21f615
--- /dev/null
+++ b/test/parser_test.exs
@@ -0,0 +1,686 @@
+defmodule MfmParser.ParserTest do
+ use ExUnit.Case
+ alias MfmParser.Parser
+
+ describe "single element input" do
+ test "it can handle an empty string as input" do
+ input = ""
+
+ assert Parser.parse(input) == []
+ end
+
+ test "it can handle text as input" do
+ input = "pain au chocolat"
+
+ output = [%MfmParser.Node.Text{props: %{text: "pain au chocolat"}}]
+
+ assert Parser.parse(input) == output
+ end
+
+ test "it can handle a newline as input" do
+ input = "\n"
+
+ output = [%MfmParser.Node.Newline{props: %{text: "\n"}}]
+
+ assert Parser.parse(input) == output
+ end
+
+ test "it can handle a flip element" do
+ input_default = "$[flip ]"
+ input_v = "$[flip.v ]"
+ input_hv = "$[flip.h,v ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Flip{
+ props: %{
+ v: false,
+ h: false
+ },
+ children: []
+ }
+ ]
+
+ output_v = [
+ %MfmParser.Node.MFM.Flip{
+ props: %{
+ v: true,
+ h: false
+ },
+ children: []
+ }
+ ]
+
+ output_hv = [
+ %MfmParser.Node.MFM.Flip{
+ props: %{
+ v: true,
+ h: true
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_v) == output_v
+ assert Parser.parse(input_hv) == output_hv
+ end
+
+ test "it can handle a font element" do
+ input = "$[font.serif ]"
+
+ output = [
+ %MfmParser.Node.MFM.Font{
+ props: %{
+ font: "serif"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input) == output
+ end
+
+ test "it can handle an x element" do
+ input2 = "$[x2 ]"
+ input3 = "$[x3 ]"
+ input4 = "$[x4 ]"
+
+ output2 = [
+ %MfmParser.Node.MFM.X{
+ props: %{
+ size: "200%"
+ },
+ children: []
+ }
+ ]
+
+ output3 = [
+ %MfmParser.Node.MFM.X{
+ props: %{
+ size: "400%"
+ },
+ children: []
+ }
+ ]
+
+ output4 = [
+ %MfmParser.Node.MFM.X{
+ props: %{
+ size: "600%"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input2) == output2
+ assert Parser.parse(input3) == output3
+ assert Parser.parse(input4) == output4
+ end
+
+ test "it can handle a blur element" do
+ input = "$[blur ]"
+
+ output = [
+ %MfmParser.Node.MFM.Blur{
+ props: %{},
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input) == output
+ end
+
+ test "it can handle a jelly element" do
+ input_default = "$[jelly ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Jelly{
+ props: %{
+ speed: "1s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[jelly.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Jelly{
+ props: %{
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a tada element" do
+ input_default = "$[tada ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Tada{
+ props: %{
+ speed: "1s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[tada.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Tada{
+ props: %{
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a jump element" do
+ input_default = "$[jump ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Jump{
+ props: %{
+ speed: "0.75s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[jump.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Jump{
+ props: %{
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a bounce element" do
+ input_default = "$[bounce ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Bounce{
+ props: %{
+ speed: "0.75s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[bounce.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Bounce{
+ props: %{
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a spin element" do
+ input_default = "$[spin ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spin",
+ direction: "normal",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_left = "$[spin.left ]"
+
+ output_left = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spin",
+ direction: "reverse",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_alternate = "$[spin.alternate ]"
+
+ output_alternate = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spin",
+ direction: "alternate",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_x = "$[spin.x ]"
+
+ output_x = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spinX",
+ direction: "normal",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_x_left = "$[spin.x,left ]"
+
+ output_x_left = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spinX",
+ direction: "reverse",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_x_alternate = "$[spin.x,alternate ]"
+
+ output_x_alternate = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spinX",
+ direction: "alternate",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_y = "$[spin.y ]"
+
+ output_y = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spinY",
+ direction: "normal",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_y_left = "$[spin.y,left ]"
+
+ output_y_left = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spinY",
+ direction: "reverse",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_y_alternate = "$[spin.y,alternate ]"
+
+ output_y_alternate = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spinY",
+ direction: "alternate",
+ speed: "1.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[spin.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Spin{
+ props: %{
+ keyframes_name: "mfm-spin",
+ direction: "normal",
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_left) == output_left
+ assert Parser.parse(input_alternate) == output_alternate
+ assert Parser.parse(input_x) == output_x
+ assert Parser.parse(input_x_left) == output_x_left
+ assert Parser.parse(input_x_alternate) == output_x_alternate
+ assert Parser.parse(input_y) == output_y
+ assert Parser.parse(input_y_left) == output_y_left
+ assert Parser.parse(input_y_alternate) == output_y_alternate
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a shake element" do
+ input_default = "$[shake ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Shake{
+ props: %{
+ speed: "0.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[shake.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Shake{
+ props: %{
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a twitch element" do
+ input_default = "$[twitch ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Twitch{
+ props: %{
+ speed: "0.5s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[twitch.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Twitch{
+ props: %{
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a rainbow element" do
+ input_default = "$[rainbow ]"
+
+ output_default = [
+ %MfmParser.Node.MFM.Rainbow{
+ props: %{
+ speed: "1s"
+ },
+ children: []
+ }
+ ]
+
+ input_speed = "$[rainbow.speed=20s ]"
+
+ output_speed = [
+ %MfmParser.Node.MFM.Rainbow{
+ props: %{
+ speed: "20s"
+ },
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input_default) == output_default
+ assert Parser.parse(input_speed) == output_speed
+ end
+
+ test "it can handle a sparkle element" do
+ input = "$[sparkle ]"
+
+ output = [
+ %MfmParser.Node.MFM.Sparkle{
+ props: %{},
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input) == output
+ end
+
+ test "it can handle a rotate element" do
+ input = "$[rotate ]"
+
+ output = [
+ %MfmParser.Node.MFM.Rotate{
+ props: %{},
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input) == output
+ end
+
+ test "it can handle an undefined element" do
+ input = "$[blabla ]"
+
+ output = [
+ %MfmParser.Node.MFM.Undefined{
+ props: %{},
+ children: []
+ }
+ ]
+
+ assert Parser.parse(input) == output
+ end
+ end
+
+ # test "it returns a parse tree with content" do
+ # input = "$[twitch twitching text]"
+ #
+ # output = [
+ # %MfmParser.MFM.Twitch{
+ # props: %{
+ # speed: "20s"
+ # },
+ # children: [
+ # %MfmParser.Text{
+ # props: %{
+ # text: "twitching text"
+ # }
+ # }
+ # ]
+ # }
+ # ]
+ #
+ # assert Parser.parse(input) == {:ok, output}
+ # end
+ #
+ # test "it returns a parse tree with mutiple entries and contents" do
+ # input = "look at this $[twitch twitching text]"
+ #
+ # output = [
+ # %MfmParser.Text{
+ # props: %{
+ # text: "look at this "
+ # }
+ # },
+ # %MfmParser.MFM.Twitch{
+ # props: %{
+ # speed: "20s"
+ # },
+ # children: [
+ # %MfmParser.Text{
+ # props: %{
+ # text: "twitching text"
+ # }
+ # }
+ # ]
+ # }
+ # ]
+ #
+ # assert Parser.parse(input) == {:ok, output}
+ # end
+
+ ######################
+ #
+ # OLD STUFF BELOW
+ #
+ ######################
+ #
+
+ # test "it returns a parse tree with text" do
+ # input = "blablabla"
+ #
+ # output = [
+ # %{
+ # type: "text",
+ # content: "blablabla"
+ # }
+ # ]
+ #
+ # assert Parser.parse(input) == {:ok, output}
+ # end
+ #
+ # test "it returns a parse tree with mutiple entries and contents and text" do
+ # input = "