summaryrefslogtreecommitdiff
path: root/src/clarktown
diff options
context:
space:
mode:
Diffstat (limited to 'src/clarktown')
-rw-r--r--src/clarktown/core.clj130
-rw-r--r--src/clarktown/parser.clj95
-rw-r--r--src/clarktown/parsers.clj32
-rw-r--r--src/clarktown/parsers/bold.clj2
-rw-r--r--src/clarktown/parsers/empty_block.clj2
-rw-r--r--src/clarktown/parsers/heading_block.clj2
-rw-r--r--src/clarktown/parsers/horizontal_line_block.clj2
-rw-r--r--src/clarktown/parsers/inline_code.clj2
-rw-r--r--src/clarktown/parsers/italic.clj2
-rw-r--r--src/clarktown/parsers/link_and_image.clj2
-rw-r--r--src/clarktown/parsers/quote_block.clj23
-rw-r--r--src/clarktown/parsers/strikethrough.clj2
12 files changed, 166 insertions, 130 deletions
diff --git a/src/clarktown/core.clj b/src/clarktown/core.clj
index 7cf1e54..43db7c6 100644
--- a/src/clarktown/core.clj
+++ b/src/clarktown/core.clj
@@ -1,124 +1,7 @@
(ns clarktown.core
(:require
- [clojure.string :as string]
- [clarktown.parsers.bold :as bold]
- [clarktown.parsers.italic :as italic]
- [clarktown.parsers.inline-code :as inline-code]
- [clarktown.parsers.strikethrough :as strikethrough]
- [clarktown.parsers.link-and-image :as link-and-image]
- [clarktown.parsers.empty-block :as empty-block]
- [clarktown.parsers.horizontal-line-block :as horizontal-line-block]
- [clarktown.parsers.heading-block :as heading-block]))
-
-
-(def default-parsers
- [{:matcher empty-block/is?
- :renderers [empty-block/render]}
- {:matcher horizontal-line-block/is?
- :renderers [horizontal-line-block/render]}
- {:matcher heading-block/is?
- :renderers [bold/render
- italic/render
- inline-code/render
- strikethrough/render
- link-and-image/render
- heading-block/render]}
- {:renderers [bold/render
- italic/render
- inline-code/render
- strikethrough/render
- link-and-image/render]}])
-
-
-(defn- stitch-code-blocks
- "Since code blocks can span multiple blocks (a block is separated by
- two line breaks from another block) , we need to stitch them together
- into one block in order for a block parser to be able to do anything
- with it."
- [blocks]
- (loop [stitched-blocks []
- code-block-started? false
- blocks blocks]
- (if (empty? blocks)
- stitched-blocks
- (let [block (first blocks)]
- (if (and (string/starts-with? (string/trim block) "```")
- (not (string/ends-with? (string/trim block) "```")))
- (recur (conj stitched-blocks block)
- true
- (drop 1 blocks))
- (if code-block-started?
- (let [last-block (last stitched-blocks)
- last-block-index (- (count stitched-blocks) 1)]
- (if (string/ends-with? (string/trim block) "```")
- (recur (assoc stitched-blocks last-block-index (str last-block "\n\n" block))
- false
- (drop 1 blocks))
- (recur (assoc stitched-blocks last-block-index (str last-block "\n\n" block))
- true
- (drop 1 blocks))))
- (recur (conj stitched-blocks block)
- false
- (drop 1 blocks))))))))
-
-
-(defn- find-parser-by-block
- "Find a parser from `parsers` that matches the given `block`."
- [parsers block]
- (->> parsers
- (filter
- (fn [{:keys [matcher]}]
- (matcher block)))
- first))
-
-
-(defn- parse-block-with-known-parser
- "Parses a given `block` with a known `parser`."
- [parser block]
- (loop [block block
- renderers (:renderers parser)]
- (if (empty? renderers)
- block
- (let [renderer (first renderers)]
- (recur (renderer block)
- (drop 1 renderers))))))
-
-
-(defn- parse-block-with-unknown-parsers
- "Parses the given `block` with all the parsers that do not have
- a matcher function, useful for any fallback parsing one might want
- to do."
- [parsers block]
- (loop [block block
- parsers (filter #(= nil (:matcher %)) parsers)]
- (if (empty? parsers)
- block
- (loop [block block
- renderers (:renderers (first parsers))]
- (if (empty? renderers)
- block
- (let [renderer (first renderers)]
- (recur (renderer block)
- (drop 1 renderers))))))))
-
-
-(defn- parse-blocks
- "Parses each individual Markdown block, given as `blocks`, with
- the list of `parsers`."
- [blocks parsers]
- (for [block blocks]
- (if-let [parser (find-parser-by-block parsers block)]
- (parse-block-with-known-parser parser block)
- (parse-block-with-unknown-parsers parsers block))))
-
-
-(defn- parse
- "Parses given `markdown` with `parsers`."
- [markdown parsers]
- (let [blocks (-> (string/split markdown #"\n\n")
- stitch-code-blocks)
- parsed-blocks (parse-blocks blocks parsers)]
- (string/join "" parsed-blocks)))
+ [clarktown.parser :as parser]
+ [clarktown.parsers :as parsers]))
(defn render
@@ -139,6 +22,9 @@
:renderers [(fn [block] ...) (fn [block] ...)]}
```"
([markdown]
- (render markdown default-parsers))
- ([markdown parsers]
- (parse markdown parsers)))
+ (render markdown parsers/parsers))
+ ([markdown given-parsers]
+ (parser/parse markdown given-parsers)))
+
+
+(render (slurp "/Users/asko/Documents/work/clarktown/quote-block.md"))
diff --git a/src/clarktown/parser.clj b/src/clarktown/parser.clj
new file mode 100644
index 0000000..53a96c7
--- /dev/null
+++ b/src/clarktown/parser.clj
@@ -0,0 +1,95 @@
+(ns clarktown.parser
+ (:require
+ [clojure.string :as string]))
+
+
+(defn- stitch-code-blocks
+ "Since code blocks can span multiple blocks (a block is separated by
+ two line breaks from another block) , we need to stitch them together
+ into one block in order for a block parser to be able to do anything
+ with it."
+ [blocks]
+ (loop [stitched-blocks []
+ code-block-started? false
+ blocks blocks]
+ (if (empty? blocks)
+ stitched-blocks
+ (let [block (first blocks)]
+ (if (and (string/starts-with? (string/trim block) "```")
+ (not (string/ends-with? (string/trim block) "```")))
+ (recur (conj stitched-blocks block)
+ true
+ (drop 1 blocks))
+ (if code-block-started?
+ (let [last-block (last stitched-blocks)
+ last-block-index (- (count stitched-blocks) 1)]
+ (if (string/ends-with? (string/trim block) "```")
+ (recur (assoc stitched-blocks last-block-index (str last-block "\n\n" block))
+ false
+ (drop 1 blocks))
+ (recur (assoc stitched-blocks last-block-index (str last-block "\n\n" block))
+ true
+ (drop 1 blocks))))
+ (recur (conj stitched-blocks block)
+ false
+ (drop 1 blocks))))))))
+
+
+(defn- find-parser-by-block
+ "Find a parser from `parsers` that matches the given `block`."
+ [parsers block]
+ (->> parsers
+ (filter
+ (fn [{:keys [matcher]}]
+ (when matcher
+ (matcher block))))
+ first))
+
+
+(defn- parse-block-with-known-parser
+ "Parses a given `block` with a known `parser`."
+ [parser parsers block]
+ (loop [block block
+ renderers (:renderers parser)]
+ (if (empty? renderers)
+ block
+ (let [renderer (first renderers)]
+ (recur (renderer block parsers)
+ (drop 1 renderers))))))
+
+
+(defn- parse-block-with-unknown-parsers
+ "Parses the given `block` with all the parsers that do not have
+ a matcher function, useful for any fallback parsing one might want
+ to do."
+ [parsers block]
+ (loop [block block
+ parsers (filter #(= nil (:matcher %)) parsers)]
+ (if (empty? parsers)
+ block
+ (loop [block block
+ renderers (:renderers (first parsers))]
+ (if (empty? renderers)
+ block
+ (let [renderer (first renderers)]
+ (recur (renderer block parsers)
+ (drop 1 renderers))))))))
+
+
+(defn- parse-blocks
+ "Parses each individual Markdown block, given as `blocks`, with
+ the list of `parsers`."
+ [blocks parsers]
+ (for [block blocks]
+ (if-let [parser (find-parser-by-block parsers block)]
+ (parse-block-with-known-parser parser parsers block)
+ (parse-block-with-unknown-parsers parsers block))))
+
+
+(defn parse
+ "Parses given `markdown` with `parsers`."
+ [markdown parsers]
+ (let [blocks (-> (string/split markdown #"\n\n")
+ stitch-code-blocks)
+ parsed-blocks (parse-blocks blocks parsers)]
+ (string/join "" parsed-blocks)))
diff --git a/src/clarktown/parsers.clj b/src/clarktown/parsers.clj
new file mode 100644
index 0000000..fc8eb59
--- /dev/null
+++ b/src/clarktown/parsers.clj
@@ -0,0 +1,32 @@
+(ns clarktown.parsers
+ (:require
+ [clarktown.parsers.bold :as bold]
+ [clarktown.parsers.italic :as italic]
+ [clarktown.parsers.inline-code :as inline-code]
+ [clarktown.parsers.strikethrough :as strikethrough]
+ [clarktown.parsers.link-and-image :as link-and-image]
+ [clarktown.parsers.empty-block :as empty-block]
+ [clarktown.parsers.horizontal-line-block :as horizontal-line-block]
+ [clarktown.parsers.quote-block :as quote-block]
+ [clarktown.parsers.heading-block :as heading-block]))
+
+
+(def parsers
+ [{:matcher empty-block/is?
+ :renderers [empty-block/render]}
+ {:matcher horizontal-line-block/is?
+ :renderers [horizontal-line-block/render]}
+ {:matcher heading-block/is?
+ :renderers [bold/render
+ italic/render
+ inline-code/render
+ strikethrough/render
+ link-and-image/render
+ heading-block/render]}
+ {:matcher quote-block/is?
+ :renderers [quote-block/render]}
+ {:renderers [bold/render
+ italic/render
+ inline-code/render
+ strikethrough/render
+ link-and-image/render]}])
diff --git a/src/clarktown/parsers/bold.clj b/src/clarktown/parsers/bold.clj
index 5840a6e..296f002 100644
--- a/src/clarktown/parsers/bold.clj
+++ b/src/clarktown/parsers/bold.clj
@@ -5,7 +5,7 @@
(defn render
"Renders all occuring bold text as bold."
- [block]
+ [block _]
(loop [block block
matches (-> (re-seq #"\*\*.*?\*\*" block)
distinct)]
diff --git a/src/clarktown/parsers/empty_block.clj b/src/clarktown/parsers/empty_block.clj
index 57d4655..f16bf6a 100644
--- a/src/clarktown/parsers/empty_block.clj
+++ b/src/clarktown/parsers/empty_block.clj
@@ -13,5 +13,5 @@
(defn render
"Renders an empty block."
- [block]
+ [block _]
"")
diff --git a/src/clarktown/parsers/heading_block.clj b/src/clarktown/parsers/heading_block.clj
index 1bc1faf..84a5fdb 100644
--- a/src/clarktown/parsers/heading_block.clj
+++ b/src/clarktown/parsers/heading_block.clj
@@ -13,7 +13,7 @@
(defn render
"Renders the heading block."
- [block]
+ [block _]
(let [single-line-block (-> (string/replace block #"\n" "")
string/trim)
size (-> (string/split single-line-block #" ")
diff --git a/src/clarktown/parsers/horizontal_line_block.clj b/src/clarktown/parsers/horizontal_line_block.clj
index 213b295..06997a6 100644
--- a/src/clarktown/parsers/horizontal_line_block.clj
+++ b/src/clarktown/parsers/horizontal_line_block.clj
@@ -12,5 +12,5 @@
(defn render
"Renders the horizontal line block."
- [_]
+ [_ _]
"<hr>")
diff --git a/src/clarktown/parsers/inline_code.clj b/src/clarktown/parsers/inline_code.clj
index b4323d7..c75adf4 100644
--- a/src/clarktown/parsers/inline_code.clj
+++ b/src/clarktown/parsers/inline_code.clj
@@ -5,7 +5,7 @@
(defn render
"Renders all occuring inline code."
- [block]
+ [block _]
(loop [block block
matches (-> (re-seq #"\`.*?\`" block)
distinct)]
diff --git a/src/clarktown/parsers/italic.clj b/src/clarktown/parsers/italic.clj
index 5b90d12..d8c7c03 100644
--- a/src/clarktown/parsers/italic.clj
+++ b/src/clarktown/parsers/italic.clj
@@ -5,7 +5,7 @@
(defn render
"Renders all occuring italic text as italic."
- [block]
+ [block _]
(loop [block block
matches (-> (re-seq #"_.*?_" block)
distinct)]
diff --git a/src/clarktown/parsers/link_and_image.clj b/src/clarktown/parsers/link_and_image.clj
index 5ef8857..7964448 100644
--- a/src/clarktown/parsers/link_and_image.clj
+++ b/src/clarktown/parsers/link_and_image.clj
@@ -5,7 +5,7 @@
(defn render
"Renders all occuring links and images."
- [block]
+ [block _]
(loop [block block
matches (-> (re-seq #"\!?\[(.*?)\]\((.*?)\)" block)
distinct)]
diff --git a/src/clarktown/parsers/quote_block.clj b/src/clarktown/parsers/quote_block.clj
new file mode 100644
index 0000000..8b9c997
--- /dev/null
+++ b/src/clarktown/parsers/quote_block.clj
@@ -0,0 +1,23 @@
+(ns clarktown.parsers.quote-block
+ (:require
+ [clojure.string :as string]
+ [clarktown.parser :as parser]))
+
+
+(defn is?
+ "Determines whether the given block is a quote block."
+ [block]
+ (-> (string/replace block #"\n" "")
+ string/trim
+ (string/starts-with? ">")))
+
+
+(defn render
+ "Renders a quote block."
+ [block parsers]
+ (let [matches (re-seq #">.*" block)
+ blocks (for [match matches]
+ (-> (subs match 1)
+ string/trim
+ (parser/parse parsers)))]
+ (str "<blockquote>" (string/join "\n" blocks) "</blockquote>")))
diff --git a/src/clarktown/parsers/strikethrough.clj b/src/clarktown/parsers/strikethrough.clj
index add4f6b..31e4cc3 100644
--- a/src/clarktown/parsers/strikethrough.clj
+++ b/src/clarktown/parsers/strikethrough.clj
@@ -5,7 +5,7 @@
(defn render
"Renders all occuring strikethrough text."
- [block]
+ [block _]
(loop [block block
matches (-> (re-seq #"~~.*?~~" block)
distinct)]