Page MenuHomePhorge

No OneTemporary

Size
15 KB
Referenced Files
None
Subscribers
None
diff --git a/.formatter.exs b/.formatter.exs
new file mode 100644
index 0000000..d2cda26
--- /dev/null
+++ b/.formatter.exs
@@ -0,0 +1,4 @@
+# Used by "mix format"
+[
+ inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
+]
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9910425
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# The directory Mix will write compiled artifacts to.
+/_build/
+
+# If you run "mix test --cover", coverage assets end up here.
+/cover/
+
+# The directory Mix downloads your dependencies sources to.
+/deps/
+
+# Where 3rd-party dependencies like ExDoc output generated docs.
+/doc/
+
+# Ignore .fetch files in case you like to edit your project deps locally.
+/.fetch
+
+# If the VM crashes, it generates a dump, let's ignore it too.
+erl_crash.dump
+
+# Also ignore archive artifacts (built via "mix archive.build").
+*.ez
+
+# Ignore package tarball (built via "mix hex.build").
+bbcode-*.tar
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0a04128
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f69638a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+# BBCode
+
+**BBCode parsing for Elixir.**
+
+## Installation
+
+If [available in Hex](https://hex.pm/docs/publish), the package can be installed
+by adding `bbcode` to your list of dependencies in `mix.exs`:
+
+```elixir
+def deps do
+ [
+ {:bbcode, "~> 0.1.0"}
+ ]
+end
+```
+
+Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
+and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
+be found at [https://hexdocs.pm/bbcode](https://hexdocs.pm/bbcode).
+
diff --git a/config/config.exs b/config/config.exs
new file mode 100644
index 0000000..02301c8
--- /dev/null
+++ b/config/config.exs
@@ -0,0 +1,30 @@
+# This file is responsible for configuring your application
+# and its dependencies with the aid of the Mix.Config module.
+use Mix.Config
+
+# This configuration is loaded before any dependency and is restricted
+# to this project. If another project depends on this project, this
+# file won't be loaded nor affect the parent project. For this reason,
+# if you want to provide default values for your application for
+# 3rd-party users, it should be done in your "mix.exs" file.
+
+# You can configure your application as:
+#
+# config :bbcode, key: :value
+#
+# and access this configuration in your application as:
+#
+# Application.get_env(:bbcode, :key)
+#
+# You can also configure a 3rd-party app:
+#
+# config :logger, level: :info
+#
+
+# It is also possible to import configuration files, relative to this
+# directory. For example, you can emulate configuration per environment
+# by uncommenting the line below and defining dev.exs, test.exs and such.
+# Configuration from the imported file will override the ones defined
+# here (which is why it is important to import them last).
+#
+# import_config "#{Mix.env()}.exs"
diff --git a/lib/bbcode.ex b/lib/bbcode.ex
new file mode 100644
index 0000000..1726b40
--- /dev/null
+++ b/lib/bbcode.ex
@@ -0,0 +1,14 @@
+defmodule BBCode do
+ alias BBCode.Parser
+ alias BBCode.Generator
+
+ def to_html(data) do
+ with {:ok, tree} <- Parser.parse(data),
+ {:ok, html} <- Generator.to_html(tree) do
+ {:ok, html}
+ else
+ {:error, e} ->
+ {:error, e}
+ end
+ end
+end
diff --git a/lib/bbcode/generator.ex b/lib/bbcode/generator.ex
new file mode 100644
index 0000000..a8af6ce
--- /dev/null
+++ b/lib/bbcode/generator.ex
@@ -0,0 +1,40 @@
+defmodule BBCode.Generator do
+ @moduledoc """
+ Generate HTML from BBCode fragments in AST form.
+ """
+
+ defp start_tag(tagname), do: Enum.join(["<", tagname, ">"])
+ defp end_tag(tagname), do: Enum.join(["</", tagname, ">"])
+
+ defp simple_tag(tagname, subtree) do
+ {:ok, text} = reduce_subtree(subtree)
+ {:ok, [start_tag(tagname), text, end_tag(tagname)] |> Enum.join()}
+ end
+
+ defp reduce_subtree({:b, subtree}), do: simple_tag("strong", subtree)
+ defp reduce_subtree({:i, subtree}), do: simple_tag("em", subtree)
+ defp reduce_subtree({:u, subtree}), do: simple_tag("u", subtree)
+ defp reduce_subtree({:s, subtree}), do: simple_tag("s", subtree)
+
+ defp reduce_subtree(text_node) when is_binary(text_node),
+ do: {:ok, text_node}
+
+ defp reduce_subtree(tree), do: {:error, "unknown input #{inspect(tree)}"}
+
+ def to_html(tree) do
+ with {:ok, new_tree} <-
+ Enum.reduce_while(tree, {:ok, []}, fn x, {:ok, acc} ->
+ with {:ok, new_tree} <- reduce_subtree(x) do
+ {:cont, {:ok, acc ++ [new_tree]}}
+ else
+ {:error, e} ->
+ {:halt, {:error, e}}
+ end
+ end) do
+ {:ok, Enum.join(new_tree)}
+ else
+ {:error, e} ->
+ {:error, e}
+ end
+ end
+end
diff --git a/lib/bbcode/parser.ex b/lib/bbcode/parser.ex
new file mode 100644
index 0000000..ad1218b
--- /dev/null
+++ b/lib/bbcode/parser.ex
@@ -0,0 +1,57 @@
+defmodule BBCode.Parser do
+ import NimbleParsec
+
+ @moduledoc """
+ Parse BBCode into an abstract tree.
+ """
+
+ tag = utf8_string([?a..?z, ?A..?Z, ?0..?9], min: 1)
+ text = utf8_string([not: ?[], min: 1)
+
+ start_tag = ignore(string("[")) |> concat(tag) |> ignore(string("]"))
+ end_tag = ignore(string("[/")) |> concat(tag) |> ignore(string("]"))
+
+ defcombinatorp(
+ :basic_stanza,
+ start_tag
+ |> repeat(lookahead_not(string("[/")) |> choice([parsec(:basic_stanza), text]))
+ |> wrap()
+ |> concat(end_tag)
+ |> post_traverse(:emit_tree_node)
+ )
+
+ defcombinatorp(
+ :text_stanza,
+ text
+ |> wrap()
+ |> post_traverse(:emit_tree_node)
+ )
+
+ defcombinatorp(
+ :root_stanza,
+ choice([parsec(:basic_stanza), parsec(:text_stanza)])
+ )
+
+ defparsecp(
+ :parse_tree,
+ repeat(lookahead_not(string("[/")) |> parsec(:root_stanza)) |> eos()
+ )
+
+ defp emit_tree_node(_rest, [tag, [tag, inside]], context, _line, _offset),
+ do: {[{String.to_atom(tag), inside}], context}
+
+ defp emit_tree_node(_rest, [tag, [tag | nodes]], context, _line, _offset),
+ do: {[{String.to_atom(tag), nodes}], context}
+
+ defp emit_tree_node(_rest, [[text]], context, _line, _offset),
+ do: {[text], context}
+
+ def parse(text) do
+ with {:ok, nodes, _, _, _, _} <- parse_tree(text) do
+ {:ok, nodes}
+ else
+ {:error, e} ->
+ {:error, e}
+ end
+ end
+end
diff --git a/mix.exs b/mix.exs
new file mode 100644
index 0000000..0bfc85e
--- /dev/null
+++ b/mix.exs
@@ -0,0 +1,35 @@
+defmodule BBCode.MixProject do
+ use Mix.Project
+
+ def project do
+ [
+ app: :bbcode,
+ name: "BBCode",
+ description: "BBCode parsing for Elixir",
+ version: "0.1.0",
+ elixir: "~> 1.7",
+ start_permanent: Mix.env() == :prod,
+ deps: deps(),
+ package: package()
+ ]
+ end
+
+ def application do
+ [
+ extra_applications: [:logger]
+ ]
+ end
+
+ defp deps do
+ [
+ {:nimble_parsec, "~> 0.2"}
+ ]
+ end
+
+ defp package do
+ [
+ licenses: ["LGPLv3"],
+ links: %{"GitLab" => "https://git.pleroma.social/pleroma/bbcode"}
+ ]
+ end
+end
diff --git a/mix.lock b/mix.lock
new file mode 100644
index 0000000..1550e43
--- /dev/null
+++ b/mix.lock
@@ -0,0 +1,3 @@
+%{
+ "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
+}
diff --git a/test/bbcode_test.exs b/test/bbcode_test.exs
new file mode 100644
index 0000000..2c92bf6
--- /dev/null
+++ b/test/bbcode_test.exs
@@ -0,0 +1,8 @@
+defmodule BbcodeTest do
+ use ExUnit.Case
+ doctest Bbcode
+
+ test "greets the world" do
+ assert Bbcode.hello() == :world
+ end
+end
diff --git a/test/test_helper.exs b/test/test_helper.exs
new file mode 100644
index 0000000..869559e
--- /dev/null
+++ b/test/test_helper.exs
@@ -0,0 +1 @@
+ExUnit.start()

File Metadata

Mime Type
text/x-diff
Expires
Wed, Nov 27, 4:26 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40690
Default Alt Text
(15 KB)

Event Timeline